Bug 1567330 - Add offset shorthand. r=emilio,birtles
authorBoris Chiou <boris.chiou@gmail.com>
Mon, 23 Sep 2019 19:56:33 +0000
changeset 494614 dcf8bb9eb0db981075bc8864e0a0115b21980d89
parent 494613 79ac597adb58c9b4946b82a78eebe7b5aa71e19b
child 494615 b86222d6233c566268a56cebc38e260ba8229105
push id36611
push usercbrindusan@mozilla.com
push dateTue, 24 Sep 2019 09:43:48 +0000
treeherdermozilla-central@79b08a0a1c3f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio, birtles
bugs1567330
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1567330 - Add offset shorthand. r=emilio,birtles Also, update the serialization by the shorter perference because this is a new feature and using older syntax doesn't make sense. Besides, use `cssOffset` for web animation IDL attribute name. Differential Revision: https://phabricator.services.mozilla.com/D45607
devtools/shared/css/generated/properties-db.js
dom/animation/KeyframeEffect.cpp
dom/animation/KeyframeUtils.cpp
layout/style/test/property_database.js
servo/components/style/properties/counted_unknown_properties.py
servo/components/style/properties/shorthands/box.mako.rs
servo/components/style/values/specified/motion.rs
testing/web-platform/meta/css/motion/__dir__.ini
testing/web-platform/meta/css/motion/animation/offset-interpolation.html.ini
testing/web-platform/meta/css/motion/parsing/offset-parsing-valid.html.ini
testing/web-platform/tests/css/motion/animation/offset-interpolation.html
testing/web-platform/tests/css/motion/parsing/offset-parsing-valid.html
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -8296,16 +8296,42 @@ exports.CSS_PROPERTIES = {
       "initial",
       "left",
       "revert",
       "right",
       "top",
       "unset"
     ]
   },
+  "offset": {
+    "isInherited": false,
+    "subproperties": [
+      "offset-path",
+      "offset-distance",
+      "offset-rotate",
+      "offset-anchor"
+    ],
+    "supports": [],
+    "values": [
+      "auto",
+      "bottom",
+      "center",
+      "inherit",
+      "initial",
+      "left",
+      "none",
+      "path",
+      "ray",
+      "reverse",
+      "revert",
+      "right",
+      "top",
+      "unset"
+    ]
+  },
   "offset-anchor": {
     "isInherited": false,
     "subproperties": [
       "offset-anchor"
     ],
     "supports": [],
     "values": [
       "auto",
@@ -10972,16 +10998,20 @@ exports.PREFERENCES = [
     "overflow-clip-box",
     "layout.css.overflow-clip-box.enabled"
   ],
   [
     "overscroll-behavior",
     "layout.css.overscroll-behavior.enabled"
   ],
   [
+    "offset",
+    "layout.css.motion-path.enabled"
+  ],
+  [
     "scroll-margin",
     "layout.css.scroll-snap-v1.enabled"
   ],
   [
     "scroll-margin-block",
     "layout.css.scroll-snap-v1.enabled"
   ],
   [
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -1182,17 +1182,35 @@ void KeyframeEffect::GetKeyframes(JSCont
             mBaseValues.GetWeak(propertyValue.mProperty);
 
         if (value) {
           Servo_AnimationValue_Serialize(value, propertyValue.mProperty,
                                          &stringValue);
         }
       }
 
-      const char* name = nsCSSProps::PropertyIDLName(propertyValue.mProperty);
+      // Basically, we need to do the mapping:
+      // * eCSSProperty_offset => "cssOffset"
+      // * eCSSProperty_float => "cssFloat"
+      // This means if property refers to the CSS "offset"/"float" property,
+      // return the string "cssOffset"/"cssFloat". (So avoid overlapping
+      // "offset" property in BaseKeyframe.)
+      // https://drafts.csswg.org/web-animations/#property-name-conversion
+      const char* name = nullptr;
+      switch (propertyValue.mProperty) {
+        case nsCSSPropertyID::eCSSProperty_offset:
+          name = "cssOffset";
+          break;
+        case nsCSSPropertyID::eCSSProperty_float:
+          // FIXME: Bug 1582314: Should handle cssFloat manually if we remove it
+          // from nsCSSProps::PropertyIDLName().
+        default:
+          name = nsCSSProps::PropertyIDLName(propertyValue.mProperty);
+      }
+
       JS::Rooted<JS::Value> value(aCx);
       if (!ToJSValue(aCx, stringValue, &value) ||
           !JS_DefineProperty(aCx, keyframeObject, name, value,
                              JSPROP_ENUMERATE)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return;
       }
     }
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -501,18 +501,34 @@ static bool GetPropertyValuesPairs(JSCon
   if (!JS_Enumerate(aCx, aObject, &ids)) {
     return false;
   }
   for (size_t i = 0, n = ids.length(); i < n; i++) {
     nsAutoJSString propName;
     if (!propName.init(aCx, ids[i])) {
       return false;
     }
-    nsCSSPropertyID property = nsCSSProps::LookupPropertyByIDLName(
-        propName, CSSEnabledState::ForAllContent);
+
+    // Basically, we have to handle "cssOffset" and "cssFloat" specially here:
+    // "cssOffset" => eCSSProperty_offset
+    // "cssFloat"  => eCSSProperty_float
+    // This means if the attribute is the string "cssOffset"/"cssFloat", we use
+    // CSS "offset"/"float" property.
+    // https://drafts.csswg.org/web-animations/#property-name-conversion
+    nsCSSPropertyID property = nsCSSPropertyID::eCSSProperty_UNKNOWN;
+    if (propName.EqualsLiteral("cssOffset")) {
+      property = nsCSSPropertyID::eCSSProperty_offset;
+    } else if (propName.EqualsLiteral("cssFloat")) {
+      property = nsCSSPropertyID::eCSSProperty_float;
+    } else if (!propName.EqualsLiteral("offset") &&
+               !propName.EqualsLiteral("float")) {
+      property = nsCSSProps::LookupPropertyByIDLName(
+          propName, CSSEnabledState::ForAllContent);
+    }
+
     if (KeyframeUtils::IsAnimatableProperty(property)) {
       AdditionalProperty* p = properties.AppendElement();
       p->mProperty = property;
       p->mJsidIndex = i;
     }
   }
 
   // Sort the entries by IDL name and then get each value and
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -12787,16 +12787,60 @@ if (IsCSSPropertyPrefEnabled("layout.css
     type: CSS_TYPE_LONGHAND,
     initial_values: ["auto"],
     other_values: ["none", "thin"],
     invalid_values: ["1px"],
   };
 }
 
 if (IsCSSPropertyPrefEnabled("layout.css.motion-path.enabled")) {
+  gCSSProperties["offset"] = {
+    domProp: "offset",
+    inherited: false,
+    type: CSS_TYPE_TRUE_SHORTHAND,
+    subproperties: [
+      "offset-path",
+      "offset-distance",
+      "offset-rotate",
+      "offset-anchor",
+    ],
+    initial_values: ["none"],
+    other_values: [
+      "none 30deg reverse",
+      "none 50px reverse 30deg",
+      "none calc(10px + 20%) auto",
+      "none reverse",
+      "none / left center",
+      "path('M 0 0 H 1') -200% auto",
+      "path('M 0 0 H 1') -200%",
+      "path('M 0 0 H 1') 50px",
+      "path('M 0 0 H 1') auto",
+      "path('M 0 0 H 1') reverse 30deg 50px",
+      "path('M 0 0 H 1')",
+      "path('m 20 0 h 100') -7rad 8px / auto",
+      "path('m 0 30 v 100') -7rad 8px / left top",
+      "path('m 0 0 h 100') -7rad 8px",
+      "path('M 0 0 H 100') 100px 0deg",
+    ],
+    invalid_values: [
+      "100px 0deg path('m 0 0 h 100')",
+      "30deg",
+      "auto 30deg 100px",
+      "auto / none",
+      "none /",
+      "none / 100px 20px 30deg",
+      "path('M 20 30 A 60 70 80') bottom",
+      "path('M 20 30 A 60 70 80') bottom top",
+      "path('M 20 30 A 60 70 80') 100px 200px",
+      "path('M 20 30 A 60 70 80') reverse auto",
+      "path('M 20 30 A 60 70 80') reverse 10px 30deg",
+      "path('M 20 30 A 60 70 80') /",
+    ],
+  };
+
   gCSSProperties["offset-path"] = {
     domProp: "offsetPath",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: ["none"],
     other_values: [
       "path('M 10 10 20 20 H 90 V 90 Z')",
       "path('M10 10 20,20H90V90Z')",
--- a/servo/components/style/properties/counted_unknown_properties.py
+++ b/servo/components/style/properties/counted_unknown_properties.py
@@ -4,17 +4,18 @@
 
 # The following properties are under development, so they are not in this list.
 # FIXME: We should handle the developing properties properly by Bug 1577358:
 #    "backdrop-filter",
 #    "text-decoration-skip-ink",
 #    "column-span",
 #    "offset-distance",
 #    "offset-path",
-#    "offset-rotate"
+#    "offset-rotate",
+#    "offset"
 COUNTED_UNKNOWN_PROPERTIES = [
     "-webkit-font-smoothing",
     "zoom",
     "-webkit-tap-highlight-color",
     "speak",
     "text-size-adjust",
     "-webkit-font-feature-settings",
     "-webkit-user-drag",
@@ -77,17 +78,16 @@ COUNTED_UNKNOWN_PROPERTIES = [
     "-webkit-perspective-origin-y",
     "-webkit-margin-before-collapse",
     "-webkit-border-before-style",
     "scroll-snap-stop",
     "-webkit-margin-bottom-collapse",
     "-webkit-ruby-position",
     "-webkit-column-break-after",
     "-webkit-margin-collapse",
-    "offset",
     "-webkit-border-before",
     "-webkit-border-end",
     "-webkit-border-after",
     "-webkit-border-start",
     "-webkit-min-logical-width",
     "-webkit-logical-height",
     "-webkit-transform-origin-z",
     "-webkit-font-size-delta",
--- a/servo/components/style/properties/shorthands/box.mako.rs
+++ b/servo/components/style/properties/shorthands/box.mako.rs
@@ -360,8 +360,84 @@ macro_rules! try_parse_one {
     }
 
     impl<'a> ToCss for LonghandsToSerialize<'a> {
         fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
             self.break_after.to_css_legacy(dest)
         }
     }
 </%helpers:shorthand>
+
+<%helpers:shorthand name="offset"
+                    engines="gecko"
+                    sub_properties="offset-path offset-distance offset-rotate offset-anchor"
+                    gecko_pref="layout.css.motion-path.enabled",
+                    spec="https://drafts.fxtf.org/motion-1/#offset-shorthand">
+    use crate::parser::Parse;
+    use crate::values::specified::motion::{OffsetPath, OffsetRotate};
+    use crate::values::specified::position::PositionOrAuto;
+    use crate::values::specified::LengthPercentage;
+    use crate::Zero;
+
+    pub fn parse_value<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Longhands, ParseError<'i>> {
+        // FIXME: Bug 1559232: Support offset-position.
+        // Per the spec, this must have offet-position and/or offset-path. However, we don't
+        // support offset-position, so offset-path is necessary now.
+        let offset_path = OffsetPath::parse(context, input)?;
+
+        let mut offset_distance = None;
+        let mut offset_rotate = None;
+        loop {
+            if offset_distance.is_none() {
+                if let Ok(value) = input.try(|i| LengthPercentage::parse(context, i)) {
+                    offset_distance = Some(value);
+                }
+            }
+
+            if offset_rotate.is_none() {
+                if let Ok(value) = input.try(|i| OffsetRotate::parse(context, i)) {
+                    offset_rotate = Some(value);
+                    continue;
+                }
+            }
+            break;
+        }
+
+        let offset_anchor = input.try(|i| {
+            i.expect_delim('/')?;
+            PositionOrAuto::parse(context, i)
+        }).ok();
+
+        Ok(expanded! {
+            offset_path: offset_path,
+            offset_distance: offset_distance.unwrap_or(LengthPercentage::zero()),
+            offset_rotate: offset_rotate.unwrap_or(OffsetRotate::auto()),
+            offset_anchor: offset_anchor.unwrap_or(PositionOrAuto::auto()),
+        })
+    }
+
+    impl<'a> ToCss for LonghandsToSerialize<'a>  {
+        fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
+            // FIXME: Bug 1559232: Support offset-position. We don't support offset-position,
+            // so always serialize offset-path now.
+            self.offset_path.to_css(dest)?;
+
+            if !self.offset_distance.is_zero() {
+                dest.write_str(" ")?;
+                self.offset_distance.to_css(dest)?;
+            }
+
+            if !self.offset_rotate.is_auto() {
+                dest.write_str(" ")?;
+                self.offset_rotate.to_css(dest)?;
+            }
+
+            if *self.offset_anchor != PositionOrAuto::auto() {
+                dest.write_str(" / ")?;
+                self.offset_anchor.to_css(dest)?;
+            }
+            Ok(())
+        }
+    }
+</%helpers:shorthand>
--- a/servo/components/style/values/specified/motion.rs
+++ b/servo/components/style/values/specified/motion.rs
@@ -125,16 +125,33 @@ pub struct OffsetRotate {
     /// If direction is None, this is a fixed angle which indicates a
     /// constant clockwise rotation transformation applied to it by this
     /// specified rotation angle. Otherwise, the angle will be added to
     /// the angle of the direction in layout.
     #[css(contextual_skip_if = "direction_specified_and_angle_is_zero")]
     angle: Angle,
 }
 
+impl OffsetRotate {
+    /// Returns the initial value, auto.
+    #[inline]
+    pub fn auto() -> Self {
+        OffsetRotate {
+            direction: OffsetRotateDirection::Auto,
+            angle: Angle::zero(),
+        }
+    }
+
+    /// Returns true if self is auto 0deg.
+    #[inline]
+    pub fn is_auto(&self) -> bool {
+        self.direction == OffsetRotateDirection::Auto && self.angle.is_zero()
+    }
+}
+
 impl Parse for OffsetRotate {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
         let location = input.current_source_location();
         let mut direction = input.try(OffsetRotateDirection::parse);
         let angle = input.try(|i| Angle::parse(context, i));
--- a/testing/web-platform/meta/css/motion/__dir__.ini
+++ b/testing/web-platform/meta/css/motion/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [layout.css.motion-path.enabled:true, layout.css.individual-transform.enabled:true]
+prefs: [layout.css.motion-path.enabled:true, layout.css.individual-transform.enabled:true, dom.animations-api.core.enabled:true]
deleted file mode 100644
--- a/testing/web-platform/meta/css/motion/animation/offset-interpolation.html.ini
+++ /dev/null
@@ -1,187 +0,0 @@
-[offset-interpolation.html]
-  [Animation between "path("M0 0V 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress 0.3]
-    expected: FAIL
-
-  [Animation between "path("M0 0V 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress 0.6]
-    expected: FAIL
-
-  [Animation between "path("M0 200H 700") 500px 800deg" and "path("M0 300H 700 Z") 600px 900deg" at progress 1.5]
-    expected: FAIL
-
-  [Animation between "path("M0 0V 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress 1]
-    expected: FAIL
-
-  [Animation between "path("M0 0V 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress 0]
-    expected: FAIL
-
-  [Animation between "path("M0 200H 700") 500px 800deg" and "path("M0 300H 700 Z") 600px 900deg" at progress 0.3]
-    expected: FAIL
-
-  [Animation between "path("M0 200H 700") 500px 800deg" and "path("M0 300H 700 Z") 600px 900deg" at progress 0.6]
-    expected: FAIL
-
-  [Animation between "path("M0 0H 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress 1.5]
-    expected: FAIL
-
-  [Animation between "path("M0 0V 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress -0.3]
-    expected: FAIL
-
-  [Animation between "path("M0 0H 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress 3.40282e+38]
-    expected: FAIL
-
-  [Animation between "path("M0 0H 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress 1]
-    expected: FAIL
-
-  [Animation between "path("M0 0H 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress 0]
-    expected: FAIL
-
-  [Animation between "path("M0 200H 700") 500px 800deg" and "path("M0 300H 700 Z") 600px 900deg" at progress -0.3]
-    expected: FAIL
-
-  [Animation between "path("M0 0V 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress 1.5]
-    expected: FAIL
-
-  [Animation between "path("M0 0H 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress 0.3]
-    expected: FAIL
-
-  [Animation between "path("M0 0H 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress 0.6]
-    expected: FAIL
-
-  ["path("M0 0H 200") 500px auto" and "path("M0 0H 300") 600px 0deg" are valid offset values]
-    expected: FAIL
-
-  ["path("M0 0V 200") 500px auto" and "path("M0 0H 300") 600px 0deg" are valid offset values]
-    expected: FAIL
-
-  ["path("M0 200H 700") 500px 800deg" and "path("M0 300H 700 Z") 600px 900deg" are valid offset values]
-    expected: FAIL
-
-  [Animation between "path("M0 200H 700") 500px 800deg" and "path("M0 300H 700 Z") 600px 900deg" at progress 1]
-    expected: FAIL
-
-  [Animation between "path("M0 200H 700") 500px 800deg" and "path("M0 300H 700 Z") 600px 900deg" at progress 0]
-    expected: FAIL
-
-  [Animation between "path("M0 0H 200") 500px auto" and "path("M0 0H 300") 600px 0deg" at progress -0.3]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (1) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (1) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (3.40282e+38) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (-0.3) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (-0.3) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (0) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 0V 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (0.3) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (0.3) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (0) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (0.6) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (1.5) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (0) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (-0.3) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 0V 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (1) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (1) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions with transition: all: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (3.40282e+38) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (0.6) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (-0.3) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (0) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (0.6) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 0V 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (0) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (-0.3) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (0.3) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (1.5) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (3.40282e+38) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (0.6) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (1.5) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (0) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (0.3) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 0V 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (-0.3) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 0V 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (1.5) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (1) should be [\]]
-    expected: FAIL
-
-  [CSS Animations: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (0.3) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (0.6) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 0V 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (0.6) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (1.5) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (0.3) should be [\]]
-    expected: FAIL
-
-  [Web Animations: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (3.40282e+38) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 200H 700") 500px 800deg\] to [path("M0 300H 700 Z") 600px 900deg\] at (1.5) should be [\]]
-    expected: FAIL
-
-  [CSS Transitions: property <offset> from [path("M0 0H 200") 500px auto\] to [path("M0 0H 300") 600px 0deg\] at (1) should be [\]]
-    expected: FAIL
-
--- a/testing/web-platform/meta/css/motion/parsing/offset-parsing-valid.html.ini
+++ b/testing/web-platform/meta/css/motion/parsing/offset-parsing-valid.html.ini
@@ -1,190 +1,34 @@
 [offset-parsing-valid.html]
-  [Serialization should round-trip after setting e.style['offset'\] = "100px none auto 90deg"]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "100px"]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "none 30deg reverse"]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "path('M 0 0 H 1') reverse 30deg 50px"]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "path('m 0 0 h 100') -7rad 8px / auto"]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "path('m 0 0 h 100') -7rad 8px / left top"]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "path('m 0 0 h 100') -7rad 8px"]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "ray(farthest-corner 90deg) 1%"]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "ray(sides 0deg) 50% 90deg auto"]
-    expected: FAIL
-
   [e.style['offset'\] = "100px none auto 90deg" should set the property value]
     expected: FAIL
 
   [e.style['offset'\] = "100px" should set the property value]
     expected: FAIL
 
   [e.style['offset'\] = "auto none reverse" should set the property value]
     expected: FAIL
 
-  [Serialization should round-trip after setting e.style['offset'\] = "auto none reverse"]
-    expected: FAIL
-
   [e.style['offset'\] = "auto" should set the property value]
     expected: FAIL
 
-  [Serialization should round-trip after setting e.style['offset'\] = "auto"]
-    expected: FAIL
-
   [e.style['offset'\] = "center bottom path('M 1 2 V 3 Z')" should set the property value]
     expected: FAIL
 
-  [Serialization should round-trip after setting e.style['offset'\] = "center bottom path('M 1 2 V 3 Z')"]
-    expected: FAIL
-
   [e.style['offset'\] = "center center path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z') 100% 90deg / left bottom" should set the property value]
     expected: FAIL
 
-  [Serialization should round-trip after setting e.style['offset'\] = "center center path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z') 100% 90deg / left bottom"]
-    expected: FAIL
-
   [e.style['offset'\] = "left bottom ray(0rad closest-side) 10px auto 30deg / right bottom" should set the property value]
     expected: FAIL
 
-  [Serialization should round-trip after setting e.style['offset'\] = "left bottom ray(0rad closest-side) 10px auto 30deg / right bottom"]
-    expected: FAIL
-
   [e.style['offset'\] = "left top" should set the property value]
     expected: FAIL
 
-  [Serialization should round-trip after setting e.style['offset'\] = "left top"]
-    expected: FAIL
-
-  [e.style['offset'\] = "none 30deg reverse" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "none 50px reverse 30deg" should set the property value]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "none 50px reverse 30deg"]
-    expected: FAIL
-
-  [e.style['offset'\] = "none calc(10px + 20%) auto" should set the property value]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "none calc(10px + 20%) auto"]
-    expected: FAIL
-
-  [e.style['offset'\] = "none reverse" should set the property value]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "none reverse"]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('M 0 0 H 1') -200% auto" should set the property value]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "path('M 0 0 H 1') -200% auto"]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('M 0 0 H 1') -200%" should set the property value]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "path('M 0 0 H 1') -200%"]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('M 0 0 H 1') 50px" should set the property value]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "path('M 0 0 H 1') 50px"]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('M 0 0 H 1') auto" should set the property value]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "path('M 0 0 H 1') auto"]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('M 0 0 H 1') reverse 30deg 50px" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('M 0 0 H 1')" should set the property value]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "path('M 0 0 H 1')"]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('m 0 0 h 100') -7rad 8px / auto" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('m 0 0 h 100') -7rad 8px / left top" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('m 0 0 h 100') -7rad 8px" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('m 0 0 h 100') 100px 0deg" should set the property value]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "path('m 0 0 h 100') 100px 0deg"]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('m 1 2 v 3 Z')" should set the property value]
-    expected: FAIL
-
-  [Serialization should round-trip after setting e.style['offset'\] = "path('m 1 2 v 3 Z')"]
-    expected: FAIL
-
-  [e.style['offset'\] = "ray(farthest-corner 90deg) 1%" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "ray(sides 0deg) 50% 90deg auto" should set the property value]
-    expected: FAIL
-
   [e.style['offset'\] = "right bottom / left top" should set the property value]
     expected: FAIL
 
-  [Serialization should round-trip after setting e.style['offset'\] = "right bottom / left top"]
-    expected: FAIL
-
-  [e.style['offset'\] = "path(\\"M 0 0 H 1\\")" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "path(\\"M 0 0 H 1\\") -200%" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "path(\\"M 0 0 H 1\\") -200% auto" should set the property value]
-    expected: FAIL
-
   [e.style['offset'\] = "center center path(\\"M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z\\") 100% 90deg / left bottom" should set the property value]
     expected: FAIL
 
   [e.style['offset'\] = "center bottom path(\\"M 1 2 V 3 Z\\")" should set the property value]
     expected: FAIL
 
-  [e.style['offset'\] = "path(\\"M 0 0 H 1\\") auto" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "path(\\"m 0 0 h 100\\") 100px 0deg" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('m 20 0 h 100') -7rad 8px / auto" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "path('m 0 30 v 100') -7rad 8px / left top" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "path(  'm 1 2   v 3.00 z')" should set the property value]
-    expected: FAIL
-
-  [e.style['offset'\] = "path(\\"M 0 0 H 100\\") 100px 0deg" should set the property value]
-    expected: FAIL
-
--- a/testing/web-platform/tests/css/motion/animation/offset-interpolation.html
+++ b/testing/web-platform/tests/css/motion/animation/offset-interpolation.html
@@ -52,19 +52,19 @@
       ]);
 
       test_interpolation({
         property: 'offset',
         from: 'path("M0 0H 200") 500px auto',
         to: 'path("M0 0H 300") 600px 0deg',
         method: 'CSS Animations',
       }, [
-        {at: -0.3, expect: 'path("M0 0H 170") 470px auto'},
-        {at: 0, expect: 'path("M0 0H 200") 500px auto'},
-        {at: 0.3, expect: 'path("M0 0H 230") 530px auto'},
+        {at: -0.3, expect: 'path("M0 0H 170") 470px'},
+        {at: 0, expect: 'path("M0 0H 200") 500px'},
+        {at: 0.3, expect: 'path("M0 0H 230") 530px'},
         {at: 0.6, expect: 'path("M0 0H 260") 560px 0deg'},
         {at: 1, expect: 'path("M0 0H 300") 600px 0deg'},
         {at: 1.5, expect: 'path("M0 0H 350") 650px 0deg'},
       ]);
 
       test_interpolation({
         property: 'offset',
         from: 'path("M0 200H 700") 500px 800deg',
@@ -80,18 +80,18 @@
       ]);
 
       test_interpolation({
         property: 'offset',
         from: 'path("M0 0V 200") 500px auto',
         to: 'path("M0 0H 300") 600px 0deg',
         method: 'Web Animations',
       }, [
-        {at: -0.3, expect: 'path("M0 0V 200") 470px auto'},
-        {at: 0, expect: 'path("M0 0V 200") 500px auto'},
-        {at: 0.3, expect: 'path("M0 0V 200") 530px auto'},
+        {at: -0.3, expect: 'path("M0 0V 200") 470px'},
+        {at: 0, expect: 'path("M0 0V 200") 500px'},
+        {at: 0.3, expect: 'path("M0 0V 200") 530px'},
         {at: 0.6, expect: 'path("M0 0H 300") 560px 0deg'},
         {at: 1, expect: 'path("M0 0H 300") 600px 0deg'},
         {at: 1.5, expect: 'path("M0 0H 300") 650px 0deg'},
       ]);
     </script>
   </body>
 </html>
--- a/testing/web-platform/tests/css/motion/parsing/offset-parsing-valid.html
+++ b/testing/web-platform/tests/css/motion/parsing/offset-parsing-valid.html
@@ -17,25 +17,28 @@ test_valid_value("offset", "100px", "100
 test_valid_value("offset", "auto none reverse");
 test_valid_value("offset", "auto");
 test_valid_value("offset", "center bottom path(\"M 1 2 V 3 Z\")");
 test_valid_value("offset", "center center path(\"M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z\") 100% 90deg / left bottom");
 test_valid_value("offset", "left bottom ray(0rad closest-side) 10px auto 30deg / right bottom");
 test_valid_value("offset", "left top");
 test_valid_value("offset", "none 30deg reverse", "none reverse 30deg");
 test_valid_value("offset", "none 50px reverse 30deg");
-test_valid_value("offset", "none calc(10px + 20%) auto");
+test_valid_value("offset", "none calc(10px + 20%) auto", "none calc(20% + 10px)");
 test_valid_value("offset", "none reverse");
-test_valid_value("offset", "path(\"M 0 0 H 1\") -200% auto");
+test_valid_value("offset", "path(\"M 0 0 H 1\") -200% auto", "path(\"M 0 0 H 1\") -200%");
 test_valid_value("offset", "path(\"M 0 0 H 1\") -200%");
 test_valid_value("offset", "path('M 0 0 H 1') 50px", "path(\"M 0 0 H 1\") 50px");
-test_valid_value("offset", "path(\"M 0 0 H 1\") auto");
+test_valid_value("offset", "path(\"M 0 0 H 1\") auto", "path(\"M 0 0 H 1\")");
+test_valid_value("offset", "path(\"M 0 0 H 1\") auto 0deg", "path(\"M 0 0 H 1\")");
+test_valid_value("offset", "path(\"M 0 0 H 1\") auto 0rad", "path(\"M 0 0 H 1\")");
+test_valid_value("offset", "path(\"M 0 0 H 1\") auto 0.5turn", "path(\"M 0 0 H 1\") auto 0.5turn");
 test_valid_value("offset", "path('M 0 0 H 1') reverse 30deg 50px", "path(\"M 0 0 H 1\") 50px reverse 30deg");
 test_valid_value("offset", "path(\"M 0 0 H 1\")");
-test_valid_value("offset", "path('m 20 0 h 100') -7rad 8px / auto", "path(\"m 20 0 h 100\") 8px -7rad / auto");
+test_valid_value("offset", "path('m 20 0 h 100') -7rad 8px / auto", "path(\"m 20 0 h 100\") 8px -7rad");
 test_valid_value("offset", "path('m 0 30 v 100') -7rad 8px / left top", "path(\"m 0 30 v 100\") 8px -7rad / left top");
 test_valid_value("offset", "path('m 0 0 h 100') -7rad 8px", "path(\"m 0 0 h 100\") 8px -7rad");
 test_valid_value("offset", "path(\"M 0 0 H 100\") 100px 0deg");
 test_valid_value("offset", "path(  'm 1 2   v 3.00 z')", "path(\"m 1 2 v 3 Z\")");
 test_valid_value("offset", "ray(farthest-corner 90deg) 1%", "ray(90deg farthest-corner) 1%");
 test_valid_value("offset", "ray(sides 0deg) 50% 90deg auto", "ray(0deg sides) 50% auto 90deg");
 test_valid_value("offset", "right bottom / left top");
 </script>