Bug 1396666 - Flip the grid line box's number position if there is not enough space along the container edge. r?pbro
authorMicah Tigley <tigleym@gmail.com>
Thu, 04 Jan 2018 20:53:28 -0700
changeset 721363 bad0ab9236ae3722cd61e012399441e9d5ca831e
parent 721208 b2cb61e83ac50115a28f04aaa8a32d4db90aad23
push id95828
push userbmo:pbrosset@mozilla.com
push dateWed, 17 Jan 2018 08:25:55 +0000
reviewerspbro
bugs1396666
milestone59.0a1
Bug 1396666 - Flip the grid line box's number position if there is not enough space along the container edge. r?pbro MozReview-Commit-ID: 22UyufRUIhH
devtools/server/actors/highlighters/css-grid.js
--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -64,16 +64,20 @@ const GRID_LINES_PROPERTIES = {
   }
 };
 
 const GRID_GAP_PATTERN_WIDTH = 14; // px
 const GRID_GAP_PATTERN_HEIGHT = 14; // px
 const GRID_GAP_PATTERN_LINE_DASH = [5, 3]; // px
 const GRID_GAP_ALPHA = 0.5;
 
+// 25 is a good margin distance between the document grid container edge without cutting
+// off parts of the arrow box container.
+const OFFSET_FROM_EDGE = 25;
+
 /**
  * Cached used by `CssGridHighlighter.getGridGapPattern`.
  */
 const gCachedGridPattern = new Map();
 
 /**
  * The CssGridHighlighter is the class that overlays a visual grid on top of
  * display:[inline-]grid elements.
@@ -1163,58 +1167,130 @@ class CssGridHighlighter extends AutoRef
         x -= xOffset;
         y -= yOffset;
       } else {
         x += xOffset;
         y += yOffset;
       }
     }
 
-    if (!this.hasNodeTransformations) {
-      x = Math.max(x, padding);
-      y = Math.max(y, padding);
-    }
-
-    // Draw a bubble rectanglular arrow with a border width of 2 pixels, a border color
+    // Draw a bubble rectangular arrow with a border width of 2 pixels, a border color
     // matching the grid color and a white background (the line number will be written in
     // black).
     this.ctx.lineWidth = 2 * displayPixelRatio;
     this.ctx.strokeStyle = this.color;
     this.ctx.fillStyle = "white";
 
     // See param definitions of drawBubbleRect.
     let radius = 2 * displayPixelRatio;
     let margin = 2 * displayPixelRatio;
     let arrowSize = 8 * displayPixelRatio;
 
+    let minOffsetFromEdge = OFFSET_FROM_EDGE * displayPixelRatio;
+
     let minBoxSize = arrowSize * 2 + padding;
     boxWidth = Math.max(boxWidth, minBoxSize);
     boxHeight = Math.max(boxHeight, minBoxSize);
 
+    let { width, height } = this._winDimensions;
+
+    let boxAlignment;
+    let textCenterPos;
+
     if (dimensionType === COLUMNS) {
       if (lineNumber > 0) {
+        boxAlignment = "top";
+        textCenterPos = (boxHeight + arrowSize + radius) - boxHeight / 2;
+
+        // If there is not enough space for the box number, flip its alignment and
+        // its text position.
+        if (y <= minOffsetFromEdge) {
+          boxAlignment = "bottom";
+          textCenterPos = -((boxHeight + arrowSize + radius) - boxHeight / 2);
+
+          // Maintain a consistent margin between the pointer and viewport edge when the
+          // grid edge falls out of view. We can use the arrow text's padding value to
+          // maintain this distance.
+          if (y + padding < 0 || y === padding) {
+            y = padding;
+          } else {
+            // If the grid edge is still visible, increment the pointer position by its
+            // arrow size so that the it does not cross over edge.
+            y += arrowSize;
+          }
+        }
+
         drawBubbleRect(this.ctx, x, y, boxWidth, boxHeight, radius, margin, arrowSize,
-          "top");
+          boxAlignment);
+
         // After drawing the number box, we need to center the x/y coordinates of the
         // number text written it.
-        y -= (boxHeight + arrowSize + radius) - boxHeight / 2;
+        y -= textCenterPos;
       } else {
+        boxAlignment = "bottom";
+        textCenterPos = (boxHeight + arrowSize + radius) - boxHeight / 2;
+
+        // Flip the negative number when its position reaches 95% of the document's
+        // height/width.
+        if (y / displayPixelRatio >= height * .95) {
+          boxAlignment = "top";
+          textCenterPos = -((boxHeight + arrowSize + radius) - boxHeight / 2);
+
+          if (y + padding > height) {
+            y -= arrowSize;
+          }
+        }
+
         drawBubbleRect(this.ctx, x, y, boxWidth, boxHeight, radius, margin, arrowSize,
-          "bottom");
-        y += (boxHeight + arrowSize + radius) - boxHeight / 2;
+                       boxAlignment);
+
+        y += textCenterPos;
       }
-    } else if (dimensionType === ROWS) {
+    }
+
+    if (dimensionType === ROWS) {
       if (lineNumber > 0) {
+        boxAlignment = "left";
+        textCenterPos = (boxWidth + arrowSize + radius) - boxWidth / 2;
+
+        if (x <= minOffsetFromEdge) {
+          boxAlignment = "right";
+          textCenterPos = -((boxWidth + arrowSize + radius) - boxWidth / 2);
+
+          // See comment above for maintaining a consistent distance between the arrow box
+          // pointer and the edge of the viewport.
+          if (x + padding < 0 || x === padding) {
+            x = padding;
+          } else {
+            x += arrowSize;
+          }
+        }
+
         drawBubbleRect(this.ctx, x, y, boxWidth, boxHeight, radius, margin, arrowSize,
-          "left");
-        x -= (boxWidth + arrowSize + radius) - boxWidth / 2;
+                       boxAlignment);
+
+        x -= textCenterPos;
       } else {
+        boxAlignment = "right";
+        textCenterPos = (boxWidth + arrowSize + radius) - boxWidth / 2;
+
+        // See above comment for flipping negative numbers .
+        if (x / displayPixelRatio >= width * .95) {
+          boxAlignment = "left";
+          textCenterPos = -((boxWidth + arrowSize + radius) - boxWidth / 2);
+
+          if (x + padding > width) {
+            x -= arrowSize;
+          }
+        }
+
         drawBubbleRect(this.ctx, x, y, boxWidth, boxHeight, radius, margin, arrowSize,
-          "right");
-        x += (boxWidth + arrowSize + radius) - boxWidth / 2;
+                       boxAlignment);
+
+        x += textCenterPos;
       }
     }
 
     // Write the line number inside of the rectangle.
     this.ctx.textAlign = "center";
     this.ctx.textBaseline = "middle";
     this.ctx.fillStyle = "black";
     const numberText = stackedLineIndex ? "" : lineNumber;