Bug 1448757 part 2 - Move longhand animation type table into devtools. r?daisuke draft
authorXidorn Quan <me@upsuper.org>
Fri, 20 Apr 2018 14:06:47 +1000
changeset 785522 021704f4bf40b086d1dfc5988c33644574937a8e
parent 785429 0774327e708bba1144b1aa709e02a02166fe2d43
child 785523 818c9f52bfe85ec61b3c5b34eef264f6c178bc6f
push id107245
push userxquan@mozilla.com
push dateFri, 20 Apr 2018 09:18:04 +0000
reviewersdaisuke
bugs1448757
milestone61.0a1
Bug 1448757 part 2 - Move longhand animation type table into devtools. r?daisuke After switching to Stylo, animation is handled by Servo, and thus it no longer relies on the animation type recorded in nsCSSPropList.h, and devtools become the only consumer of that information. This patch puts a map of longhands to animation types into devtools instead. The map is extracted from nsCSSPropList.h by the script below based on the logic of nsDOMWindowUtils::GetAnimationTypeForLonghand. There are two reasons that I don't port this into Servo: First, Servo doesn't have a concept of property-level animation type. Animation change in Servo is directly encoded into value types. It means porting this to Servo would require creating a new concept purely for devtools. It's not great because that data doesn't reflect how animation is handled in the engine, and people may keep forgetting to give proper animation type to new animatable types they add. Second, the handling of animation type in devtools also looks rather arbitrary to me. For example, eStyleAnimType_Corner_* types are actually two coordinate values, bug GetAnimationTypeForLonghand returns "coord" for them, and devtools just parses the first value and uses it. This means the animation type here is really more closely related to how devtools handles the value, rather than how the style engine does so. Given above, I decided to put the list into devtools rather than encode the information into Servo code. To encourage people to think about animation handling in devtools for new properties, there is also a new test added to ensure every property has a devtools animation type. The content of ANIMATION_TYPE_FOR_LONGHANDS is generated via running the following script in layout/style: ```python #!/usr/bin/env python3 import subprocess from collections import defaultdict ANIMTYPE_MAPPING = { "Custom": "custom", "Coord": "coord", "Sides_Top": "coord", "Sides_Right": "coord", "Sides_Bottom": "coord", "Sides_Left": "coord", "Corner_TopLeft": "coord", "Corner_TopRight": "coord", "Corner_BottomRight": "coord", "Corner_BottomLeft": "coord", "nscoord": "length", "float": "float", "Color": "color", "ComplexColor": "color", "PaintServer": "paintServer", "Shadow": "shadow", "Discrete": "discrete", "None": "none", } input = b""" #define CSS_PROP(name, id, method, flags, pref, \\ variant, kwtable, animtype) name, flags, animtype #include "nsCSSPropList.h" """ props = subprocess.check_output(["clang", "-E", "-P", "-"], input=input) props = props.decode("ascii") result = defaultdict(list) for line in props.splitlines(): line = line.strip() if not line: continue name, flags, animtype = line.split(", ") assert animtype.startswith("eStyleAnimType_") if "CSS_PROPERTY_PARSE_INACCESSIBLE" in flags: continue animtype = ANIMTYPE_MAPPING[animtype[15:]] result[animtype].append(name) print("[") for animtype, names in result.items(): print(' ["{}", new Set(['.format(animtype)) for name in names: print(' "{}",'.format(name)) print(" ])],") print("]") ``` MozReview-Commit-ID: BGiGq0jUgG5
devtools/server/actors/animation-type-longhand.js
devtools/server/actors/animation.js
devtools/server/actors/moz.build
devtools/server/tests/mochitest/chrome.ini
devtools/server/tests/mochitest/test_animation-type-longhand.html
new file mode 100644
--- /dev/null
+++ b/devtools/server/actors/animation-type-longhand.js
@@ -0,0 +1,347 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Types of animation types of longhand properties.
+exports.ANIMATION_TYPE_FOR_LONGHANDS = [
+  ["discrete", new Set([
+    "align-content",
+    "align-items",
+    "align-self",
+    "-moz-appearance",
+    "backface-visibility",
+    "background-attachment",
+    "background-blend-mode",
+    "background-clip",
+    "background-image",
+    "background-origin",
+    "background-repeat",
+    "border-bottom-style",
+    "border-collapse",
+    "border-image-outset",
+    "border-image-repeat",
+    "border-image-slice",
+    "border-image-source",
+    "border-image-width",
+    "border-left-style",
+    "border-right-style",
+    "border-top-style",
+    "-moz-box-align",
+    "box-decoration-break",
+    "-moz-box-direction",
+    "-moz-box-ordinal-group",
+    "-moz-box-orient",
+    "-moz-box-pack",
+    "box-sizing",
+    "caption-side",
+    "clear",
+    "clip-rule",
+    "color-adjust",
+    "color-interpolation",
+    "color-interpolation-filters",
+    "column-fill",
+    "column-rule-style",
+    "column-span",
+    "contain",
+    "content",
+    "counter-increment",
+    "counter-reset",
+    "cursor",
+    "direction",
+    "dominant-baseline",
+    "empty-cells",
+    "fill-rule",
+    "flex-direction",
+    "flex-wrap",
+    "float",
+    "-moz-float-edge",
+    "font-family",
+    "font-feature-settings",
+    "font-kerning",
+    "font-language-override",
+    "font-style",
+    "font-synthesis",
+    "font-variant-alternates",
+    "font-variant-caps",
+    "font-variant-east-asian",
+    "font-variant-ligatures",
+    "font-variant-numeric",
+    "font-variant-position",
+    "-moz-force-broken-image-icon",
+    "grid-auto-columns",
+    "grid-auto-flow",
+    "grid-auto-rows",
+    "grid-column-end",
+    "grid-column-start",
+    "grid-row-end",
+    "grid-row-start",
+    "grid-template-areas",
+    "grid-template-columns",
+    "grid-template-rows",
+    "hyphens",
+    "image-orientation",
+    "image-rendering",
+    "ime-mode",
+    "initial-letter",
+    "isolation",
+    "justify-content",
+    "justify-items",
+    "justify-self",
+    "list-style-image",
+    "list-style-position",
+    "list-style-type",
+    "marker-end",
+    "marker-mid",
+    "marker-start",
+    "mask-clip",
+    "mask-composite",
+    "mask-image",
+    "mask-mode",
+    "mask-origin",
+    "mask-repeat",
+    "mask-type",
+    "mix-blend-mode",
+    "object-fit",
+    "-moz-orient",
+    "-moz-osx-font-smoothing",
+    "outline-style",
+    "overflow-clip-box-block",
+    "overflow-clip-box-inline",
+    "overflow-wrap",
+    "overflow-x",
+    "overflow-y",
+    "overscroll-behavior-x",
+    "overscroll-behavior-y",
+    "page-break-after",
+    "page-break-before",
+    "page-break-inside",
+    "paint-order",
+    "pointer-events",
+    "position",
+    "quotes",
+    "resize",
+    "ruby-align",
+    "ruby-position",
+    "scroll-behavior",
+    "scroll-snap-coordinate",
+    "scroll-snap-destination",
+    "scroll-snap-points-x",
+    "scroll-snap-points-y",
+    "scroll-snap-type-x",
+    "scroll-snap-type-y",
+    "shape-rendering",
+    "-moz-stack-sizing",
+    "stroke-linecap",
+    "stroke-linejoin",
+    "table-layout",
+    "text-align",
+    "text-align-last",
+    "text-anchor",
+    "text-combine-upright",
+    "text-decoration-line",
+    "text-decoration-style",
+    "text-emphasis-position",
+    "text-emphasis-style",
+    "text-justify",
+    "text-orientation",
+    "text-overflow",
+    "text-rendering",
+    "-moz-text-size-adjust",
+    "-webkit-text-stroke-width",
+    "text-transform",
+    "touch-action",
+    "transform-box",
+    "transform-style",
+    "unicode-bidi",
+    "-moz-user-focus",
+    "-moz-user-input",
+    "-moz-user-modify",
+    "-moz-user-select",
+    "vector-effect",
+    "visibility",
+    "white-space",
+    "will-change",
+    "-moz-window-dragging",
+    "word-break",
+    "writing-mode",
+  ])],
+  ["none", new Set([
+    "animation-delay",
+    "animation-direction",
+    "animation-duration",
+    "animation-fill-mode",
+    "animation-iteration-count",
+    "animation-name",
+    "animation-play-state",
+    "animation-timing-function",
+    "-moz-binding",
+    "block-size",
+    "border-block-end-color",
+    "border-block-end-style",
+    "border-block-end-width",
+    "border-block-start-color",
+    "border-block-start-style",
+    "border-block-start-width",
+    "border-inline-end-color",
+    "border-inline-end-style",
+    "border-inline-end-width",
+    "border-inline-start-color",
+    "border-inline-start-style",
+    "border-inline-start-width",
+    "-moz-context-properties",
+    "-moz-control-character-visibility",
+    "display",
+    "font-optical-sizing",
+    "inline-size",
+    "margin-block-end",
+    "margin-block-start",
+    "margin-inline-end",
+    "margin-inline-start",
+    "-moz-math-display",
+    "max-block-size",
+    "max-inline-size",
+    "min-block-size",
+    "-moz-min-font-size-ratio",
+    "min-inline-size",
+    "offset-block-end",
+    "offset-block-start",
+    "offset-inline-end",
+    "offset-inline-start",
+    "padding-block-end",
+    "padding-block-start",
+    "padding-inline-end",
+    "padding-inline-start",
+    "rotate",
+    "scale",
+    "-moz-script-level",
+    "-moz-top-layer",
+    "transition-delay",
+    "transition-duration",
+    "transition-property",
+    "transition-timing-function",
+    "translate",
+    "-moz-window-shadow",
+  ])],
+  ["color", new Set([
+    "background-color",
+    "border-bottom-color",
+    "border-left-color",
+    "border-right-color",
+    "border-top-color",
+    "caret-color",
+    "color",
+    "column-rule-color",
+    "flood-color",
+    "-moz-font-smoothing-background-color",
+    "lighting-color",
+    "outline-color",
+    "stop-color",
+    "text-decoration-color",
+    "text-emphasis-color",
+    "-webkit-text-fill-color",
+    "-webkit-text-stroke-color",
+  ])],
+  ["custom", new Set([
+    "background-position-x",
+    "background-position-y",
+    "background-size",
+    "border-bottom-width",
+    "border-left-width",
+    "border-right-width",
+    "border-spacing",
+    "border-top-width",
+    "clip",
+    "clip-path",
+    "column-count",
+    "column-rule-width",
+    "filter",
+    "font-stretch",
+    "font-variation-settings",
+    "font-weight",
+    "-moz-image-region",
+    "mask-position-x",
+    "mask-position-y",
+    "mask-size",
+    "object-position",
+    "order",
+    "perspective-origin",
+    "shape-outside",
+    "stroke-dasharray",
+    "transform",
+    "transform-origin",
+    "-moz-window-transform",
+    "-moz-window-transform-origin",
+  ])],
+  ["coord", new Set([
+    "border-bottom-left-radius",
+    "border-bottom-right-radius",
+    "border-top-left-radius",
+    "border-top-right-radius",
+    "bottom",
+    "column-gap",
+    "column-width",
+    "flex-basis",
+    "grid-column-gap",
+    "grid-row-gap",
+    "height",
+    "left",
+    "letter-spacing",
+    "line-height",
+    "margin-bottom",
+    "margin-left",
+    "margin-right",
+    "margin-top",
+    "max-height",
+    "max-width",
+    "min-height",
+    "min-width",
+    "-moz-outline-radius-bottomleft",
+    "-moz-outline-radius-bottomright",
+    "-moz-outline-radius-topleft",
+    "-moz-outline-radius-topright",
+    "padding-bottom",
+    "padding-left",
+    "padding-right",
+    "padding-top",
+    "perspective",
+    "right",
+    "stroke-dashoffset",
+    "stroke-width",
+    "-moz-tab-size",
+    "text-indent",
+    "top",
+    "vertical-align",
+    "width",
+    "word-spacing",
+    "z-index",
+  ])],
+  ["float", new Set([
+    "-moz-box-flex",
+    "fill-opacity",
+    "flex-grow",
+    "flex-shrink",
+    "flood-opacity",
+    "font-size-adjust",
+    "opacity",
+    "shape-image-threshold",
+    "stop-opacity",
+    "stroke-miterlimit",
+    "stroke-opacity",
+    "-moz-window-opacity",
+  ])],
+  ["shadow", new Set([
+    "box-shadow",
+    "text-shadow",
+  ])],
+  ["paintServer", new Set([
+    "fill",
+    "stroke",
+  ])],
+  ["length", new Set([
+    "font-size",
+    "outline-offset",
+    "outline-width",
+  ])],
+];
--- a/devtools/server/actors/animation.js
+++ b/devtools/server/actors/animation.js
@@ -24,26 +24,37 @@
  * - WebAnimation WebIDL files:
  *   /dom/webidl/Animation*.webidl
  */
 
 const {Cu, Ci} = require("chrome");
 const protocol = require("devtools/shared/protocol");
 const {Actor} = protocol;
 const {animationPlayerSpec, animationsSpec} = require("devtools/shared/specs/animation");
+const {ANIMATION_TYPE_FOR_LONGHANDS} = require("./animation-type-longhand");
 
 // Types of animations.
 const ANIMATION_TYPES = {
   CSS_ANIMATION: "cssanimation",
   CSS_TRANSITION: "csstransition",
   SCRIPT_ANIMATION: "scriptanimation",
   UNKNOWN: "unknown"
 };
 exports.ANIMATION_TYPES = ANIMATION_TYPES;
 
+function getAnimationTypeForLonghand(property) {
+  for (let [type, props] of ANIMATION_TYPE_FOR_LONGHANDS) {
+    if (props.has(property)) {
+      return type;
+    }
+  }
+  throw new Error("Unknown longhand property name");
+}
+exports.getAnimationTypeForLonghand = getAnimationTypeForLonghand;
+
 /**
  * The AnimationPlayerActor provides information about a given animation: its
  * startTime, currentTime, current state, etc.
  *
  * Since the state of a player changes as the animation progresses it is often
  * useful to call getCurrentState at regular intervals to get the current state.
  *
  * This actor also allows playing, pausing and seeking the animation.
@@ -510,17 +521,17 @@ var AnimationPlayerActor = protocol.Acto
             pseudo = target.type;
             target = target.parentElement;
           }
           const value =
             DOMWindowUtils.getUnanimatedComputedStyle(target,
                                                       pseudo,
                                                       property.name,
                                                       DOMWindowUtils.FLUSH_NONE);
-          const animationType = DOMWindowUtils.getAnimationTypeForLonghand(property.name);
+          const animationType = getAnimationTypeForLonghand(property.name);
           underlyingValue = animationType === "float" ? parseFloat(value, 10) : value;
         }
         values.value = underlyingValue;
       });
     }
 
     // Calculate the distance.
     for (let property of properties) {
@@ -564,22 +575,19 @@ var AnimationPlayerActor = protocol.Acto
   },
 
   /**
    * Get the animation types for a given list of CSS property names.
    * @param {Array} propertyNames - CSS property names (e.g. background-color)
    * @return {Object} Returns animation types (e.g. {"background-color": "rgb(0, 0, 0)"}.
    */
   getAnimationTypes: function(propertyNames) {
-    const DOMWindowUtils = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
-                               .getInterface(Ci.nsIDOMWindowUtils);
     const animationTypes = {};
     for (let propertyName of propertyNames) {
-      animationTypes[propertyName] =
-        DOMWindowUtils.getAnimationTypeForLonghand(propertyName);
+      animationTypes[propertyName] = getAnimationTypeForLonghand(propertyName);
     }
     return animationTypes;
   },
 
   /**
    * Returns the distance of between value1, value2.
    * @param {Object} target - dom element
    * @param {String} propertyName - e.g. transform
--- a/devtools/server/actors/moz.build
+++ b/devtools/server/actors/moz.build
@@ -16,16 +16,17 @@ DIRS += [
 ]
 
 DevToolsModules(
     'accessibility-parent.js',
     'accessibility.js',
     'actor-registry.js',
     'addon.js',
     'addons.js',
+    'animation-type-longhand.js',
     'animation.js',
     'array-buffer.js',
     'breakpoint.js',
     'call-watcher.js',
     'canvas.js',
     'child-process.js',
     'chrome.js',
     'common.js',
--- a/devtools/server/tests/mochitest/chrome.ini
+++ b/devtools/server/tests/mochitest/chrome.ini
@@ -25,16 +25,17 @@ support-files =
   memory-helpers.js
   nonchrome_unsafeDereference.html
   small-image.gif
   setup-in-child.js
   setup-in-parent.js
   webconsole-helpers.js
   webextension-helpers.js
 [test_animation_actor-lifetime.html]
+[test_animation-type-longhand.html]
 [test_connection-manager.html]
 [test_connectToFrame.html]
 [test_css-logic.html]
 [test_css-logic-media-queries.html]
 [test_css-logic-specificity.html]
 [test_css-properties.html]
 [test_Debugger.Source.prototype.introductionScript.html]
 [test_Debugger.Source.prototype.introductionType.html]
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/mochitest/test_animation-type-longhand.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>Test animation-type-longhand</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<body>
+<script>
+  "use strict";
+
+  // This test checks the content of animation type for longhands table that
+  // * every longhand property is included
+  // * nothing else is included
+  // * no property is mapped to more than one animation type
+  window.onload = function() {
+    const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
+    const { ANIMATION_TYPE_FOR_LONGHANDS } =
+      require("devtools/server/actors/animation-type-longhand");
+    const InspectorUtils = SpecialPowers.InspectorUtils;
+
+    const all_longhands = InspectorUtils.getCSSPropertyNames({
+      includeShorthands: false,
+      includeExperimentals: true,
+    });
+
+    let unseen_longhands = new Set(all_longhands);
+    let seen_longhands = new Set();
+    for (let [, names] of ANIMATION_TYPE_FOR_LONGHANDS) {
+      for (let name of names) {
+        ok(!seen_longhands.has(name),
+           `${name} should have only one animation type`);
+        ok(unseen_longhands.has(name),
+           `${name} is an unseen longhand property`);
+        unseen_longhands.delete(name);
+        seen_longhands.add(name);
+      }
+    }
+    is(unseen_longhands.size, 0,
+       "All longhands should be mapped to some animation type");
+
+    SimpleTest.finish();
+  };
+</script>
+</body>