Bug 1401477 - limit autoscroll popup coordinates so we always display it full-size, instead of having the popup code constrain its size to fit on-screen, r=dao
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Mon, 13 Nov 2017 16:06:33 +0000
changeset 437499 a77dc52424ef72a2c419b8497d1e24af50d8aa26
parent 437498 3c7a4c69bb8cc50c080c66e49ca36a0f3a2528a9
child 437500 df3695afb47e0598e3fb1425a7e2a0d16adf35ee
push id117
push userfmarier@mozilla.com
push dateTue, 28 Nov 2017 20:17:16 +0000
reviewersdao
bugs1401477
milestone59.0a1
Bug 1401477 - limit autoscroll popup coordinates so we always display it full-size, instead of having the popup code constrain its size to fit on-screen, r=dao MozReview-Commit-ID: 6XQNfkkjadC
toolkit/content/widgets/browser.xml
toolkit/themes/linux/global/global.css
toolkit/themes/osx/global/global.css
toolkit/themes/windows/global/global.css
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -1285,43 +1285,73 @@
         </body>
       </method>
 
       <method name="startScroll">
         <parameter name="scrolldir"/>
         <parameter name="screenX"/>
         <parameter name="screenY"/>
         <body><![CDATA[
+            const POPUP_SIZE = 28;
             if (!this._autoScrollPopup) {
               if (this.hasAttribute("autoscrollpopup")) {
                 // our creator provided a popup to share
                 this._autoScrollPopup = document.getElementById(this.getAttribute("autoscrollpopup"));
               } else {
                 // we weren't provided a popup; we have to use the global scope
                 this._autoScrollPopup = this._createAutoScrollPopup();
                 document.documentElement.appendChild(this._autoScrollPopup);
                 this._autoScrollNeedsCleanup = true;
               }
+              this._autoScrollPopup.removeAttribute("hidden");
+              this._autoScrollPopup.setAttribute("noautofocus", "true");
+              this._autoScrollPopup.style.height = POPUP_SIZE + "px";
+              this._autoScrollPopup.style.width = POPUP_SIZE + "px";
+              this._autoScrollPopup.style.margin = -POPUP_SIZE / 2 + "px";
             }
 
+            let screenManager = Components.classes["@mozilla.org/gfx/screenmanager;1"]
+              .getService(Components.interfaces.nsIScreenManager);
+            let screen = screenManager.screenForRect(screenX, screenY, 1, 1);
+
             // we need these attributes so themers don't need to create per-platform packages
             if (screen.colorDepth > 8) { // need high color for transparency
               // Exclude second-rate platforms
               this._autoScrollPopup.setAttribute("transparent", !/BeOS|OS\/2/.test(navigator.appVersion));
               // Enable translucency on Windows and Mac
               this._autoScrollPopup.setAttribute("translucent", /Win|Mac/.test(navigator.platform));
             }
 
-            this._autoScrollPopup.removeAttribute("hidden");
-            this._autoScrollPopup.setAttribute("noautofocus", "true");
             this._autoScrollPopup.setAttribute("scrolldir", scrolldir);
             this._autoScrollPopup.addEventListener("popuphidden", this, true);
+
+            // Sanitize screenX/screenY for available screen size with half the size
+            // of the popup removed. The popup uses negative margins to center on the
+            // coordinates we pass. Unfortunately `window.screen.availLeft` can be negative
+            // on Windows in multi-monitor setups, so we use nsIScreenManager instead:
+            let left = {}, top = {}, width = {}, height = {};
+            screen.GetAvailRectDisplayPix(left, top, width, height);
+
+            // We need to get screen CSS-pixel (rather than display-pixel) coordinates.
+            // With 175% DPI, the actual ratio of display pixels to CSS pixels is
+            // 1.7647 because of rounding inside gecko. Unfortunately defaultCSSScaleFactor
+            // returns the original 1.75 dpi factor. While window.devicePixelRatio would
+            // get us the correct ratio, if the window is split between 2 screens,
+            // window.devicePixelRatio isn't guaranteed to match the screen we're
+            // autoscrolling on. So instead we do the same math as Gecko.
+            const scaleFactor = 60 / Math.round(60 / screen.defaultCSSScaleFactor);
+            let minX = left.value / scaleFactor + 0.5 * POPUP_SIZE;
+            let maxX = (left.value + width.value) / scaleFactor - 0.5 * POPUP_SIZE;
+            let minY = top.value / scaleFactor + 0.5 * POPUP_SIZE;
+            let maxY = (top.value + height.value) / scaleFactor - 0.5 * POPUP_SIZE;
+            let popupX = Math.max(minX, Math.min(maxX, screenX));
+            let popupY = Math.max(minY, Math.min(maxY, screenY));
             this._autoScrollPopup.showPopup(document.documentElement,
-                                            screenX,
-                                            screenY,
+                                            popupX,
+                                            popupY,
                                             "popup", null, null);
             this._ignoreMouseEvents = true;
             this._scrolling = true;
             this._startX = screenX;
             this._startY = screenY;
 
             window.addEventListener("mousemove", this, true);
             window.addEventListener("mousedown", this, true);
--- a/toolkit/themes/linux/global/global.css
+++ b/toolkit/themes/linux/global/global.css
@@ -269,20 +269,17 @@ popupnotificationcontent {
   margin-top: .5em;
 }
 
 %include ../../shared/notification-popup.inc.css
 
 /* :::::: autoscroll popup ::::: */
 
 .autoscroller {
-  height: 28px;
-  width: 28px;
   border: none;
-  margin: -14px;
   padding: 0;
   background-image: url("chrome://global/skin/icons/autoscroll.svg");
   background-size: contain;
   background-color: transparent;
   background-repeat: no-repeat;
   -moz-appearance: none;
 }
 
--- a/toolkit/themes/osx/global/global.css
+++ b/toolkit/themes/osx/global/global.css
@@ -282,20 +282,17 @@ popupnotificationcontent {
   margin-top: .5em;
 }
 
 %include ../../shared/notification-popup.inc.css
 
 /* :::::: autoscroll popup ::::: */
 
 .autoscroller {
-  height: 28px;
-  width: 28px;
   border: none;
-  margin: -14px;
   padding: 0;
   background-image: url("chrome://global/skin/icons/autoscroll.svg");
   background-size: contain;
   background-color: transparent;
   background-position: right top;
   background-repeat: no-repeat;
   -moz-appearance: none;
   -moz-window-shadow: none;
--- a/toolkit/themes/windows/global/global.css
+++ b/toolkit/themes/windows/global/global.css
@@ -291,20 +291,17 @@ popupnotificationcontent {
   margin-top: .5em;
 }
 
 %include ../../shared/notification-popup.inc.css
 
 /* :::::: autoscroll popup ::::: */
 
 .autoscroller {
-  height: 28px;
-  width: 28px;
   border: none;
-  margin: -14px;
   padding: 0;
   background-image: url("chrome://global/skin/icons/autoscroll.svg");
   background-size: contain;
   background-color: transparent;
   background-repeat: no-repeat;
   -moz-appearance: none;
 }