Bug 1485501 - Change the calculated viewport if anchor element is displayed at second screen. r=birtles
authorMantaroh Yoshinaga <mantaroh@gmail.com>
Tue, 16 Oct 2018 01:16:59 +0000
changeset 489778 70daf386e9d36a170da95d59009ef953ccb6310f
parent 489754 ba7c1249b79b39df4be295ed0c65a32bc7eaa932
child 489779 d5cc1ab5bb162464e4be7593e6a71d330faf3b51
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersbirtles
bugs1485501
milestone64.0a1
Bug 1485501 - Change the calculated viewport if anchor element is displayed at second screen. r=birtles If we displayed the devtools across the second screen, the Screen.availLeft might be not zero. I.e., Screen.availLeft point to second screen's left. The HTMLTooltip does't consider this case, so this patch will change the viewpor's left and right position if the left of anchor element is bigger than screen.right. Differential Revision: https://phabricator.services.mozilla.com/D8183
devtools/client/shared/widgets/tooltip/HTMLTooltip.js
--- a/devtools/client/shared/widgets/tooltip/HTMLTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/HTMLTooltip.js
@@ -484,17 +484,17 @@ HTMLTooltip.prototype = {
 
   _updateContainerBounds(anchor, {position, x = 0, y = 0} = {}) {
     // Get anchor geometry
     let anchorRect = getRelativeRect(anchor, this.doc);
     if (this.useXulWrapper) {
       anchorRect = this._convertToScreenRect(anchorRect);
     }
 
-    const { viewportRect, windowRect } = this._getBoundingRects();
+    const { viewportRect, windowRect } = this._getBoundingRects(anchorRect);
 
     // Calculate the horizonal position and width
     let preferredWidth;
     // Record the height too since it might save us from having to look it up
     // later.
     let measuredHeight;
     if (this.preferredWidth === "auto") {
       // Reset any styles that constrain the dimensions we want to calculate.
@@ -608,25 +608,31 @@ HTMLTooltip.prototype = {
    * - Window rect: This is the bounds of the view in which the tooltip is
    *   presented. It is reported in the same coordinates as the viewport
    *   rect and is used for determining in which direction a doorhanger-type
    *   tooltip should "hang".
    *   When using the XUL panel wrapper this will be the dimensions of the
    *   window in screen coordinates. Otherwise it will be the same as the
    *   viewport rect.
    *
+   * @param {Object} anchorRect
+   *        DOMRect-like object of the target anchor element.
+   *        We need to pass this to detect the case when the anchor is not in
+   *        the current window (because, the center of the window is in
+   *        a different window to the anchor).
+   *
    * @return {Object} An object with the following properties
    *         viewportRect {Object} DOMRect-like object with the Number
    *                      properties: top, right, bottom, left, width, height
    *                      representing the viewport rect.
    *         windowRect   {Object} DOMRect-like object with the Number
    *                      properties: top, right, bottom, left, width, height
-   *                      representing the viewport rect.
+   *                      representing the window rect.
    */
-  _getBoundingRects: function() {
+  _getBoundingRects: function(anchorRect) {
     let viewportRect;
     let windowRect;
 
     if (this.useXulWrapper) {
       // availLeft/Top are the coordinates first pixel available on the screen
       // for applications (excluding space dedicated for OS toolbars, menus
       // etc...)
       // availWidth/Height are the dimensions available to applications
@@ -655,16 +661,35 @@ HTMLTooltip.prototype = {
       windowRect = {
         top: screenY,
         right: screenX + outerWidth,
         bottom: screenY + outerHeight,
         left: screenX,
         width: outerWidth,
         height: outerHeight,
       };
+
+      // If the anchor is outside the viewport, it possibly means we have a
+      // multi-monitor environment where the anchor is displayed on a different
+      // monitor to the "current" screen (as determined by the center of the
+      // window). This can happen when, for example, the screen is spread across
+      // two monitors.
+      //
+      // In this case we simply expand viewport in the direction of the anchor
+      // so that we can still calculate the popup position correctly.
+      if (anchorRect.left > viewportRect.right) {
+        const diffWidth = windowRect.right - viewportRect.right;
+        viewportRect.right += diffWidth;
+        viewportRect.width += diffWidth;
+      }
+      if (anchorRect.right < viewportRect.left) {
+        const diffWidth = viewportRect.left - windowRect.left;
+        viewportRect.left -= diffWidth;
+        viewportRect.width += diffWidth;
+      }
     } else {
       viewportRect = windowRect =
         this.doc.documentElement.getBoundingClientRect();
     }
 
     return { viewportRect, windowRect };
   },