Bug 1239298 - Make sure percentage width of iterations and delays in the timeline are relative to the same parent draft
authorPatrick Brosset <pbrosset@mozilla.com>
Wed, 13 Jan 2016 14:32:11 +0100
changeset 321388 66784084934dc9fa0d151de17c53913e54a319a5
parent 321375 593d2794b14e557d5661c49f95d66c7ba7bd6b16
child 512890 6dd72253dece2dc0024cfe9900b90f641f5ab58e
push id9366
push userpbrosset@mozilla.com
push dateWed, 13 Jan 2016 13:32:35 +0000
bugs1239298
milestone46.0a1
Bug 1239298 - Make sure percentage width of iterations and delays in the timeline are relative to the same parent
devtools/client/animationinspector/components/animation-time-block.js
devtools/client/animationinspector/components/animation-timeline.js
devtools/client/animationinspector/utils.js
devtools/client/themes/animationinspector.css
--- a/devtools/client/animationinspector/components/animation-time-block.js
+++ b/devtools/client/animationinspector/components/animation-time-block.js
@@ -50,48 +50,51 @@ AnimationTimeBlock.prototype = {
     // It is positioned according to its delay (divided by the playbackrate),
     // and its width is according to its duration (divided by the playbackrate).
     let {x, iterationW, delayX, delayW, negativeDelayW} =
       TimeScale.getAnimationDimensions(animation);
 
     let iterations = createNode({
       parent: this.containerEl,
       attributes: {
-        "class": state.type + " iterations" +
-                 (state.iterationCount ? "" : " infinite"),
+        "class": "iterations" + (state.iterationCount ? "" : " infinite"),
         // Individual iterations are represented by setting the size of the
         // repeating linear-gradient.
         "style": `left:${x}%;
                   width:${iterationW}%;
                   background-size:${100 / (state.iterationCount || 1)}% 100%;`
       }
     });
 
     // The animation name is displayed over the iterations.
-    // Note that in case of negative delay, we push the name towards the right
-    // so the delay can be shown.
+    // Note that in case of negative delay, it is pushed towards the right so
+    // the delay element does not overlap.
     createNode({
-      parent: iterations,
-      attributes: {
-        "class": "name",
-        "title": this.getTooltipText(state),
-        // Make space for the negative delay with a margin-left.
-        "style": `margin-left:${negativeDelayW}%`
-      },
+      parent: createNode({
+        parent: this.containerEl,
+        attributes: {
+          "class": "name",
+          "title": this.getTooltipText(state),
+          // Place the name at the same position as the iterations, but make
+          // space for the negative delay if any.
+          "style": `left:${x + negativeDelayW}%;
+                    width:${iterationW - negativeDelayW}%;`
+        },
+      }),
       textContent: state.name
     });
 
     // Delay.
     if (state.delay) {
       // Negative delays need to start at 0.
       createNode({
-        parent: iterations,
+        parent: this.containerEl,
         attributes: {
           "class": "delay" + (state.delay < 0 ? " negative" : ""),
-          "style": `left:-${delayX}%;
+          "style": `left:${delayX}%;
                     width:${delayW}%;`
         }
       });
     }
   },
 
   getTooltipText: function(state) {
     let getTime = time => L10N.getFormatStr("player.timeLabel",
--- a/devtools/client/animationinspector/components/animation-timeline.js
+++ b/devtools/client/animationinspector/components/animation-timeline.js
@@ -272,19 +272,19 @@ AnimationsTimeline.prototype = {
       animation.on("changed", this.onAnimationStateChanged);
 
       // Each line contains the target animated node and the animation time
       // block.
       let animationEl = createNode({
         parent: this.animationsEl,
         nodeType: "li",
         attributes: {
-          "class": "animation" + (animation.state.isRunningOnCompositor
-                                  ? " fast-track"
-                                  : "")
+          "class": "animation " +
+                   animation.state.type +
+                   (animation.state.isRunningOnCompositor ? " fast-track" : "")
         }
       });
 
       // Right below the line is a hidden-by-default line for displaying the
       // inline keyframes.
       let detailsEl = createNode({
         parent: this.animationsEl,
         nodeType: "li",
--- a/devtools/client/animationinspector/utils.js
+++ b/devtools/client/animationinspector/utils.js
@@ -333,19 +333,19 @@ var TimeScale = {
 
     // The start position.
     let x = this.startTimeToDistance(start + (delay / rate));
     // The width for a single iteration.
     let w = this.durationToDistance(duration / rate);
     // The width for all iterations.
     let iterationW = w * (count || 1);
     // The start position of the delay.
-    let delayX = this.durationToDistance((delay < 0 ? 0 : delay) / rate);
+    let delayX = delay < 0 ? x : this.startTimeToDistance(start);
     // The width of the delay.
     let delayW = this.durationToDistance(Math.abs(delay) / rate);
-    // The width of the delay if it is positive, 0 otherwise.
+    // The width of the delay if it is negative, 0 otherwise.
     let negativeDelayW = delay < 0 ? delayW : 0;
 
     return {x, w, iterationW, delayX, delayW, negativeDelayW};
   }
 };
 
 exports.TimeScale = TimeScale;
--- a/devtools/client/themes/animationinspector.css
+++ b/devtools/client/themes/animationinspector.css
@@ -22,16 +22,31 @@
   --timeline-animation-height: 20px;
   /* The size of a keyframe marker in the keyframes diagram */
   --keyframes-marker-size: 10px;
   /* The color of the time graduation borders. This should match the the color
      devtools/client/animationinspector/utils.js */
   --time-graduation-border-color: rgba(128, 136, 144, .5);
 }
 
+.animation {
+  --timeline-border-color: var(--theme-body-color);
+  --timeline-background-color: var(--theme-splitter-color);
+}
+
+.animation.cssanimation {
+  --timeline-border-color: var(--theme-highlight-lightorange);
+  --timeline-background-color: var(--theme-contrast-background);
+}
+
+.animation.csstransition {
+  --timeline-border-color: var(--theme-highlight-bluegrey);
+  --timeline-background-color: var(--theme-highlight-blue);
+}
+
 html {
   height: 100%;
 }
 
 body {
   margin: 0;
   padding: 0;
   display : flex;
@@ -280,51 +295,40 @@ body {
 
 .animation-timeline .animation .time-block {
   cursor: pointer;
 }
 
 /* Animation iterations */
 
 .animation-timeline .animation .iterations {
-  position: relative;
+  position: absolute;
   height: 100%;
   box-sizing: border-box;
 
-  --timeline-border-color: var(--theme-body-color);
-  --timeline-background-color: var(--theme-splitter-color);
-
   /* Iterations of the animation are displayed with a repeating linear-gradient
      which size is dynamically changed from JS. The gradient only draws 1px
      borders between each iteration. These borders must have the same color as
      the border of this element */
   background-image:
     linear-gradient(to right,
                     var(--timeline-border-color) 0,
                     var(--timeline-border-color) 1px,
                     transparent 1px,
                     transparent 2px);
   background-repeat: repeat-x;
   background-position: -1px 0;
   border: 1px solid var(--timeline-border-color);
+  /* Border-right is already handled by the gradient */
+  border-width: 1px 0 1px 1px;
 
   /* The background color is set independently */
   background-color: var(--timeline-background-color);
 }
 
-.animation-timeline .animation .cssanimation {
-  --timeline-border-color: var(--theme-highlight-lightorange);
-  --timeline-background-color: var(--theme-contrast-background);
-}
-
-.animation-timeline .animation .csstransition {
-  --timeline-border-color: var(--theme-highlight-bluegrey);
-  --timeline-background-color: var(--theme-highlight-blue);
-}
-
 .animation-timeline .animation .iterations.infinite {
   border-right-width: 0;
 }
 
 .animation-timeline .animation .iterations.infinite::before,
 .animation-timeline .animation .iterations.infinite::after {
   content: "";
   position: absolute;
@@ -338,43 +342,60 @@ body {
 }
 
 .animation-timeline .animation .iterations.infinite::after {
   bottom: 0;
   top: unset;
 }
 
 .animation-timeline .animation .name {
+  position: absolute;
   color: var(--theme-selection-color);
   height: 100%;
-  width: 100%;
+  display: flex;
+  align-items: center;
+  padding: 0 2px;
+  box-sizing: border-box;
+  --fast-track-icon-width: 12px;
+}
+
+.animation-timeline .animation .name div {
+  /* Flex items don't support text-overflow, so a child div is used */
+  white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
-  white-space: nowrap;
-  line-height: 150%;
-  padding: 0 2px;
+}
+
+.animation-timeline .fast-track .name div {
+  width: calc(100% - var(--fast-track-icon-width));
 }
 
-.animation-timeline .fast-track .name {
+.animation-timeline .fast-track .name::after {
   /* Animations running on the compositor have the fast-track background image*/
+  content: "";
+  display: block;
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 100%;
+  width: var(--fast-track-icon-width);
+
   background-image: url("images/animation-fast-track.svg");
   background-repeat: no-repeat;
-  background-position: calc(100% - 5px) center;
+  background-position: center;
 }
 
 .animation-timeline .animation .delay {
   position: absolute;
-  top: 0;
-  /* Make sure the delay covers up the animation border */
-  transform: translate(-1px, -1px);
-  box-sizing: border-box;
-  height: calc(100% + 2px);
+  height: 100%;
 
   border: 1px solid var(--timeline-border-color);
+  box-sizing: border-box;
   border-width: 1px 0 1px 1px;
+
   background-image: repeating-linear-gradient(45deg,
                                               transparent,
                                               transparent 1px,
                                               var(--theme-selection-color) 1px,
                                               var(--theme-selection-color) 4px);
   background-color: var(--timeline-border-color);
 }