Bug 1280128: [webext] Use transparent backgrounds and correct border radii for popup browsers. r=bwinton ui-r=maritz a=lizzard
authorKris Maglione <maglione.k@gmail.com>
Thu, 11 Aug 2016 18:30:10 -0700
changeset 349723 61161615e9873acee6f7b798e9199a5aa75c0bbc
parent 349722 08fce3513fac56f170c166d946ea44ab2bac8969
child 349724 024841102facc9e7d949723128603e60939abf50
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbwinton, maritz, lizzard
bugs1280128
milestone50.0a2
Bug 1280128: [webext] Use transparent backgrounds and correct border radii for popup browsers. r=bwinton ui-r=maritz a=lizzard MozReview-Commit-ID: 9jmuxdSLmBM
browser/components/extensions/ext-utils.js
browser/components/extensions/extension-mac-panel.css
browser/components/extensions/extension-win-panel.css
browser/components/extensions/extension.css
browser/components/extensions/jar.mn
browser/components/extensions/test/browser/browser.ini
browser/components/extensions/test/browser/browser_ext_browserAction_popup.js
browser/components/extensions/test/browser/browser_ext_popup_corners.js
browser/components/extensions/test/browser/head.js
browser/themes/linux/browser.css
browser/themes/osx/browser.css
browser/themes/shared/customizableui/panelUI.inc.css
browser/themes/windows/browser.css
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -1,17 +1,23 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
                                   "resource:///modules/CustomizableUI.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+                                  "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
+XPCOMUtils.defineLazyServiceGetter(this, "styleSheetService",
+                                   "@mozilla.org/content/style-sheet-service;1",
+                                   "nsIStyleSheetService");
+
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 Cu.import("resource://gre/modules/AppConstants.jsm");
 
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 // Minimum time between two resizes.
 const RESIZE_TIMEOUT = 100;
 
@@ -37,35 +43,49 @@ function promisePopupShown(popup) {
       popup.addEventListener("popupshown", function onPopupShown(event) {
         popup.removeEventListener("popupshown", onPopupShown);
         resolve();
       });
     }
   });
 }
 
-XPCOMUtils.defineLazyGetter(global, "stylesheets", () => {
-  let styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"]
-      .getService(Components.interfaces.nsIStyleSheetService);
-  let styleSheetURI = Services.io.newURI("chrome://browser/content/extension.css",
-                                         null, null);
+XPCOMUtils.defineLazyGetter(this, "stylesheets", () => {
+  let styleSheetURI = NetUtil.newURI("chrome://browser/content/extension.css");
   let styleSheet = styleSheetService.preloadSheet(styleSheetURI,
                                                   styleSheetService.AGENT_SHEET);
   let stylesheets = [styleSheet];
 
   if (AppConstants.platform === "macosx") {
-    styleSheetURI = Services.io.newURI("chrome://browser/content/extension-mac.css",
-                                       null, null);
+    styleSheetURI = NetUtil.newURI("chrome://browser/content/extension-mac.css");
     let macStyleSheet = styleSheetService.preloadSheet(styleSheetURI,
                                                        styleSheetService.AGENT_SHEET);
     stylesheets.push(macStyleSheet);
   }
   return stylesheets;
 });
 
+XPCOMUtils.defineLazyGetter(this, "standaloneStylesheets", () => {
+  let stylesheets = [];
+
+  if (AppConstants.platform === "macosx") {
+    let styleSheetURI = NetUtil.newURI("chrome://browser/content/extension-mac-panel.css");
+    let macStyleSheet = styleSheetService.preloadSheet(styleSheetURI,
+                                                       styleSheetService.AGENT_SHEET);
+    stylesheets.push(macStyleSheet);
+  }
+  if (AppConstants.platform === "win") {
+    let styleSheetURI = NetUtil.newURI("chrome://browser/content/extension-win-panel.css");
+    let winStyleSheet = styleSheetService.preloadSheet(styleSheetURI,
+                                                       styleSheetService.AGENT_SHEET);
+    stylesheets.push(winStyleSheet);
+  }
+  return stylesheets;
+});
+
 class BasePopup {
   constructor(extension, viewNode, popupURL, browserStyle) {
     let popupURI = Services.io.newURI(popupURL, null, extension.baseURI);
 
     Services.scriptSecurityManager.checkLoadURIWithPrincipal(
       extension.principal, popupURI,
       Services.scriptSecurityManager.DISALLOW_SCRIPT);
 
@@ -118,21 +138,30 @@ class BasePopup {
 
   handleEvent(event) {
     switch (event.type) {
       case this.DESTROY_EVENT:
         this.destroy();
         break;
 
       case "DOMWindowCreated":
-        if (this.browserStyle && event.target === this.browser.contentDocument) {
+        if (event.target === this.browser.contentDocument) {
           let winUtils = this.browser.contentWindow
-              .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-          for (let stylesheet of global.stylesheets) {
-            winUtils.addSheet(stylesheet, winUtils.AGENT_SHEET);
+                             .QueryInterface(Ci.nsIInterfaceRequestor)
+                             .getInterface(Ci.nsIDOMWindowUtils);
+
+          if (this.browserStyle) {
+            for (let stylesheet of stylesheets) {
+              winUtils.addSheet(stylesheet, winUtils.AGENT_SHEET);
+            }
+          }
+          if (!this.fixedWidth) {
+            for (let stylesheet of standaloneStylesheets) {
+              winUtils.addSheet(stylesheet, winUtils.AGENT_SHEET);
+            }
           }
         }
         break;
 
       case "DOMWindowClose":
         if (event.target === this.browser.contentWindow) {
           event.preventDefault();
           this.closePopup();
@@ -169,16 +198,18 @@ class BasePopup {
     }
   }
 
   createBrowser(viewNode, popupURI) {
     let document = viewNode.ownerDocument;
     this.browser = document.createElementNS(XUL_NS, "browser");
     this.browser.setAttribute("type", "content");
     this.browser.setAttribute("disableglobalhistory", "true");
+    this.browser.setAttribute("transparent", "true");
+    this.browser.setAttribute("class", "webextension-popup-browser");
     this.browser.setAttribute("webextension-view-type", "popup");
 
     // We only need flex sizing for the sake of the slide-in sub-views of the
     // main menu panel, so that the browser occupies the full width of the view,
     // and also takes up any extra height that's available to it.
     this.browser.setAttribute("flex", "1");
 
     // Note: When using noautohide panels, the popup manager will add width and
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/extension-mac-panel.css
@@ -0,0 +1,3 @@
+body {
+  border-radius: 3.5px;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/extension-win-panel.css
@@ -0,0 +1,7 @@
+@media (-moz-os-version: windows-xp),
+       (-moz-os-version: windows-vista),
+       (-moz-os-version: windows-win7) {
+  body {
+    border-radius: 4px;
+  }
+}
--- a/browser/components/extensions/extension.css
+++ b/browser/components/extensions/extension.css
@@ -6,17 +6,17 @@ select,
 option,
 input {
   -moz-appearance: none;
 }
 
 /* Variables */
 html,
 body {
-  background-color: #fcfcfc;
+  background: transparent;
   box-sizing: border-box;
   color: #222426;
   cursor: default;
   display: flex;
   flex-direction: column;
   font: caption;
   margin: 0;
   padding: 0;
--- a/browser/components/extensions/jar.mn
+++ b/browser/components/extensions/jar.mn
@@ -1,15 +1,21 @@
 # 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/.
 
 browser.jar:
     content/browser/extension.css
+#ifdef XP_MACOSX
     content/browser/extension-mac.css
+    content/browser/extension-mac-panel.css
+#endif
+#ifdef XP_WIN
+    content/browser/extension-win-panel.css
+#endif
     content/browser/extension.svg
     content/browser/ext-bookmarks.js
     content/browser/ext-browserAction.js
     content/browser/ext-commands.js
     content/browser/ext-contextMenus.js
     content/browser/ext-desktop-runtime.js
     content/browser/ext-history.js
     content/browser/ext-pageAction.js
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -38,16 +38,17 @@ support-files =
 [browser_ext_incognito_popup.js]
 [browser_ext_lastError.js]
 [browser_ext_optionsPage_privileges.js]
 [browser_ext_pageAction_context.js]
 [browser_ext_pageAction_popup.js]
 [browser_ext_pageAction_popup_resize.js]
 [browser_ext_pageAction_simple.js]
 [browser_ext_popup_api_injection.js]
+[browser_ext_popup_corners.js]
 [browser_ext_runtime_openOptionsPage.js]
 [browser_ext_runtime_setUninstallURL.js]
 [browser_ext_simple.js]
 [browser_ext_tab_runtimeConnect.js]
 [browser_ext_tabs_audio.js]
 [browser_ext_tabs_captureVisibleTab.js]
 [browser_ext_tabs_create.js]
 [browser_ext_tabs_create_invalid_url.js]
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_popup.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_popup.js
@@ -15,18 +15,18 @@ function* testInArea(area) {
         "browser_style": true,
       },
     },
 
     files: {
       "popup-a.html": scriptPage("popup-a.js"),
       "popup-a.js": function() {
         window.onload = () => {
-          let background = window.getComputedStyle(document.body).backgroundColor;
-          browser.test.assertEq("rgb(252, 252, 252)", background);
+          let color = window.getComputedStyle(document.body).color;
+          browser.test.assertEq("rgb(34, 36, 38)", color);
           browser.runtime.sendMessage("from-popup-a");
         };
         browser.runtime.onMessage.addListener(msg => {
           if (msg == "close-popup") {
             window.close();
           }
         });
       },
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_popup_corners.js
@@ -0,0 +1,101 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+function* awaitPanel(extension, win = window) {
+  let {target} = yield BrowserTestUtils.waitForEvent(win.document, "load", true, (event) => {
+    return event.target.location && event.target.location.href.endsWith("popup.html");
+  });
+
+  return target.defaultView
+               .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDocShell)
+               .chromeEventHandler;
+}
+
+add_task(function* testPopupBorderRadius() {
+  let extension = ExtensionTestUtils.loadExtension({
+    background() {
+      browser.tabs.query({active: true, currentWindow: true}, tabs => {
+        browser.pageAction.show(tabs[0].id);
+      });
+    },
+
+    manifest: {
+      "browser_action": {
+        "default_popup": "popup.html",
+        "browser_style": false,
+      },
+
+      "page_action": {
+        "default_popup": "popup.html",
+        "browser_style": false,
+      },
+    },
+
+    files: {
+      "popup.html": `<!DOCTYPE html>
+        <html>
+          <head><meta charset="utf-8"></head>
+          <body style="width: 100px; height: 100px;"></body>
+        </html>`,
+    },
+  });
+
+  yield extension.startup();
+
+  function* testPanel(browser, standAlone = true) {
+    let panel = getPanelForNode(browser);
+    let arrowContent = document.getAnonymousElementByAttribute(panel, "class", "panel-arrowcontent");
+
+    let panelStyle = getComputedStyle(arrowContent);
+
+    let viewNode = browser.parentNode === panel ? browser : browser.parentNode;
+    let viewStyle = getComputedStyle(viewNode);
+
+    let win = browser.contentWindow;
+    let bodyStyle = win.getComputedStyle(win.document.body);
+
+    for (let prop of ["borderTopLeftRadius", "borderTopRightRadius",
+                      "borderBottomRightRadius", "borderBottomLeftRadius"]) {
+      if (standAlone) {
+        is(viewStyle[prop], panelStyle[prop], `Panel and view ${prop} should be the same`);
+        is(bodyStyle[prop], panelStyle[prop], `Panel and body ${prop} should be the same`);
+      } else {
+        is(viewStyle[prop], "0px", `View node ${prop} should be 0px`);
+        is(bodyStyle[prop], "0px", `Body node ${prop} should be 0px`);
+      }
+    }
+  }
+
+  {
+    info("Test stand-alone browserAction popup");
+
+    clickBrowserAction(extension);
+    let browser = yield awaitPanel(extension);
+    yield testPanel(browser);
+    yield closeBrowserAction(extension);
+  }
+
+  {
+    info("Test menu panel browserAction popup");
+
+    let widget = getBrowserActionWidget(extension);
+    CustomizableUI.addWidgetToArea(widget.id, CustomizableUI.AREA_PANEL);
+
+    clickBrowserAction(extension);
+    let browser = yield awaitPanel(extension);
+    yield testPanel(browser, false);
+    yield closeBrowserAction(extension);
+  }
+
+  {
+    info("Test pageAction popup");
+
+    clickPageAction(extension);
+    let browser = yield awaitPanel(extension);
+    yield testPanel(browser);
+    yield closePageAction(extension);
+  }
+
+  yield extension.unload();
+});
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -5,17 +5,17 @@
 /* exported CustomizableUI makeWidgetId focusWindow forceGC
  *          getBrowserActionWidget
  *          clickBrowserAction clickPageAction
  *          getBrowserActionPopup getPageActionPopup
  *          closeBrowserAction closePageAction
  *          promisePopupShown promisePopupHidden
  *          openContextMenu closeContextMenu
  *          openExtensionContextMenu closeExtensionContextMenu
- *          imageBuffer getListStyleImage
+ *          imageBuffer getListStyleImage getPanelForNode
  */
 
 var {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm");
 var {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm");
 
 // Bug 1239884: Our tests occasionally hit a long GC pause at unpredictable
 // times in debug builds, which results in intermittent timeouts. Until we have
 // a better solution, we force a GC after certain strategic tests, which tend to
@@ -78,16 +78,23 @@ function promisePopupHidden(popup) {
     let onPopupHidden = event => {
       popup.removeEventListener("popuphidden", onPopupHidden);
       resolve();
     };
     popup.addEventListener("popuphidden", onPopupHidden);
   });
 }
 
+function getPanelForNode(node) {
+  while (node.localName != "panel") {
+    node = node.parentNode;
+  }
+  return node;
+}
+
 function getBrowserActionWidget(extension) {
   return CustomizableUI.getWidget(makeWidgetId(extension.id) + "-browser-action");
 }
 
 function getBrowserActionPopup(extension, win = window) {
   let group = getBrowserActionWidget(extension);
 
   if (group.areaType == CustomizableUI.TYPE_TOOLBAR) {
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1945,11 +1945,15 @@ notification.pluginVulnerable > .notific
   margin-inline-end: 0 !important;
 }
 
 .browser-extension-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
   overflow: hidden;
 }
 
+.webextension-popup-browser {
+  border-radius: inherit;
+}
+
 .menuitem-iconic[usercontextid] > .menu-iconic-left > .menu-iconic-icon {
   visibility: visible;
 }
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -3457,8 +3457,16 @@ menulist.translate-infobar-element > .me
   padding-left: 0;
   padding-right: 0;
 }
 
 .browser-extension-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
   overflow: hidden;
 }
+
+.cui-widget-panelview[id^=PanelUI-webext-] {
+  border-radius: 3.5px;
+}
+
+.webextension-popup-browser {
+  border-radius: inherit;
+}
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -268,20 +268,16 @@ panelmultiview[nosubviews=true] > .panel
 .cui-widget-panel[viewId^=PanelUI-webext-] .panel-mainview {
   max-width: 800px;
 }
 
 .cui-widget-panel[viewId^=PanelUI-webext-] > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
-.cui-widget-panelview[id^=PanelUI-webext-] {
-  border-radius: 3.5px;
-}
-
 panelview[id^=PanelUI-webext-] {
   overflow: hidden;
 }
 
 panelview:not([mainview]) .toolbarbutton-text,
 .cui-widget-panel toolbarbutton > .toolbarbutton-text {
   text-align: start;
   display: -moz-box;
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -2696,8 +2696,20 @@ notification.pluginVulnerable > .notific
 @media not all and (-moz-os-version: windows-xp) {
 %include browser-aero.css
 }
 
 .browser-extension-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
   overflow: hidden;
 }
+
+@media (-moz-os-version: windows-xp),
+       (-moz-os-version: windows-vista),
+       (-moz-os-version: windows-win7) {
+  .cui-widget-panelview[id^=PanelUI-webext-] {
+    border-radius: 4px;
+  }
+}
+
+.webextension-popup-browser {
+  border-radius: inherit;
+}