Bug 1418602 - Allow Theming Sidebars (WIP) draft
authorConnor Masini <cjmasini@gmail.com>
Fri, 23 Feb 2018 12:17:56 -0500
changeset 778687 8cfd60d6382577d7aabda2b3f9d9cc1dc9ab4ec3
parent 766570 2415fc46287ee1df58097f940e6f01f519ea3c36
push id105566
push userbmo:masinico@msu.edu
push dateFri, 06 Apr 2018 18:40:15 +0000
bugs1418602
milestone60.0a1
Bug 1418602 - Allow Theming Sidebars (WIP) MozReview-Commit-ID: 8OcbExWxTkI
browser/components/places/content/sidebarUtils.js
browser/modules/ThemeVariableMap.jsm
browser/themes/shared/places/places.inc.css
browser/themes/shared/places/tree-icons.inc.css
browser/themes/shared/sidebar.inc.css
browser/themes/windows/browser.css
toolkit/components/extensions/ext-theme.js
toolkit/components/extensions/schemas/theme.json
toolkit/components/extensions/test/browser/browser.ini
toolkit/components/extensions/test/browser/browser_ext_themes_sidebars.js
toolkit/modules/LightweightThemeConsumer.jsm
--- a/browser/components/places/content/sidebarUtils.js
+++ b/browser/components/places/content/sidebarUtils.js
@@ -1,13 +1,16 @@
 /* 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/. */
 
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
+const { LightweightThemeConsumer }  = ChromeUtils.import("resource://gre/modules/LightweightThemeConsumer.jsm", {});
+new LightweightThemeConsumer(document, window.top);
+
 window.top.gUIDensity.update();
 
 var SidebarUtils = {
   handleTreeClick: function SU_handleTreeClick(aTree, aEvent, aGutterSelect) {
     // right-clicks are not handled here
     if (aEvent.button == 2)
       return;
 
--- a/browser/modules/ThemeVariableMap.jsm
+++ b/browser/modules/ThemeVariableMap.jsm
@@ -18,9 +18,14 @@ const ThemeVariableMap = [
   ["--urlbar-separator-color", "toolbar_field_separator"],
   ["--tabs-border-color", "toolbar_top_separator", "navigator-toolbox"],
   ["--lwt-toolbar-vertical-separator", "toolbar_vertical_separator"],
   ["--toolbox-border-bottom-color", "toolbar_bottom_separator"],
   ["--lwt-toolbarbutton-icon-fill", "icon_color"],
   ["--lwt-toolbarbutton-icon-fill-attention", "icon_attention_color"],
   ["--lwt-toolbarbutton-hover-background", "button_background_hover"],
   ["--lwt-toolbarbutton-active-background", "button_background_active"],
+  ["--lwt-sidebar-background", "sidebar"],
+  ["--lwt-sidebar-text", "sidebar_text"],
+  ["--lwt-sidebar-border", "sidebar_border"],
+  ["--lwt-sidebar-highlight", "sidebar_highlight"],
+  ["--lwt-sidebar-highlight-text", "sidebar_highlight_text"],
 ];
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/places/places.inc.css
@@ -0,0 +1,22 @@
+/* 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/. */
+
+.sidebar,
+#sidebar {
+  background-color: var(--lwt-sidebar-background, transparent);
+  color: color: var(--lwt-sidebar-text, black);
+  border-color: var(--lwt-sidebar-border, transparent);
+}
+
+.sidebar-header,
+#sidebar-header {
+  background-color: var(--lwt-sidebar-background, transparent);
+  color: var(--lwt-sidebar-text, black);
+  border-color: var(--lwt-sidebar-border, transparent);
+}
+
+:root[style*="--lwt-sidebar-highlight"] treechildren::-moz-tree-row(hover) {
+  color: var(--lwt-sidebar-highlight-text);
+  background-color: var(--lwt-sidebar-highlight);
+}
\ No newline at end of file
--- a/browser/themes/shared/places/tree-icons.inc.css
+++ b/browser/themes/shared/places/tree-icons.inc.css
@@ -1,15 +1,15 @@
 /* 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/. */
 
 treechildren:-moz-tree-image {
   -moz-context-properties: fill, fill-opacity;
-  fill: -moz-FieldText;
+  fill: currentColor;
   fill-opacity: 0.7;
 }
 
 treechildren::-moz-tree-image(title) {
   list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.svg");
   padding-inline-end: 2px;
   margin: 0 2px;
   width: 16px;
--- a/browser/themes/shared/sidebar.inc.css
+++ b/browser/themes/shared/sidebar.inc.css
@@ -1,14 +1,16 @@
 %if 0
 /* 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/. */
 %endif
 
+%include ../shared/places/places.inc.css
+
 .sidebar-header,
 #sidebar-header {
   font-size: 1.333em;
   font-weight: lighter;
   padding: 8px;
 }
 
 %ifndef MOZ_WIDGET_GTK
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -668,21 +668,21 @@ html|*.urlbar-input:-moz-lwtheme::placeh
 %include ../shared/sidebar.inc.css
 
 #sidebar-box {
   background-color: -moz-Field;
   color: -moz-FieldText;
 }
 
 #sidebar-header {
-  border-bottom: 1px solid ThreeDLightShadow;
+  border-bottom: 1px solid var(--lwt-sidebar-border, ThreeDLightShadow);
 }
 
 .sidebar-splitter {
-  border-color: ThreeDLightShadow;
+  border-color: var(--lwt-sidebar-border, ThreeDLightShadow);;
 }
 
 .browserContainer > findbar {
   background-color: -moz-dialog;
   color: -moz-DialogText;
   text-shadow: none;
 }
 
@@ -717,16 +717,18 @@ html|*.urlbar-input:-moz-lwtheme::placeh
 }
 
 /* All tabs menupopup */
 
 .alltabs-item[selected="true"] {
   font-weight: bold;
 }
 
+%include ../shared/places/places.inc.css
+
 /* Bookmarks toolbar */
 #PlacesToolbarDropIndicator {
   list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);
 }
 
 toolbarbutton.bookmark-item[dragover="true"][open="true"] {
   -moz-appearance: none;
   background: Highlight !important;
--- a/toolkit/components/extensions/ext-theme.js
+++ b/toolkit/components/extensions/ext-theme.js
@@ -157,16 +157,21 @@ class Theme {
         case "toolbar_top_separator":
         case "toolbar_bottom_separator":
         case "toolbar_vertical_separator":
         case "button_background_hover":
         case "button_background_active":
         case "popup":
         case "popup_text":
         case "popup_border":
+        case "sidebar":
+        case "sidebar_text":
+        case "sidebar_border":
+        case "sidebar_highlight":
+        case "sidebar_highlight_text":
           this.lwtStyles[color] = cssColor;
           break;
       }
     }
   }
 
   /**
    * Helper method for loading images found in the extension's manifest.
--- a/toolkit/components/extensions/schemas/theme.json
+++ b/toolkit/components/extensions/schemas/theme.json
@@ -159,16 +159,36 @@
               },
               "popup_text": {
                 "$ref": "ThemeColor",
                 "optional": true
               },
               "popup_border": {
                 "$ref": "ThemeColor",
                 "optional": true
+              },
+              "sidebar": {
+                "$ref": "ThemeColor",
+                "optional": true
+              },
+              "sidebar_text": {
+                "$ref": "ThemeColor",
+                "optional": true
+              },
+              "sidebar_border": {
+                "$ref": "ThemeColor",
+                "optional": true
+              },
+              "sidebar_highlight": {
+                "$ref": "ThemeColor",
+                "optional": true
+              },
+              "sidebar_highlight_text": {
+                "$ref": "ThemeColor",
+                "optional": true
               }
             },
             "additionalProperties": { "$ref": "UnrecognizedProperty" }
           },
           "icons": {
             "type": "object",
             "optional": true,
             "properties": {
--- a/toolkit/components/extensions/test/browser/browser.ini
+++ b/toolkit/components/extensions/test/browser/browser.ini
@@ -16,8 +16,9 @@ support-files =
 [browser_ext_themes_static_onUpdated.js]
 [browser_ext_themes_tab_loading.js]
 [browser_ext_themes_tab_text.js]
 [browser_ext_themes_toolbar_fields.js]
 [browser_ext_themes_toolbars.js]
 [browser_ext_themes_toolbarbutton_icons.js]
 [browser_ext_themes_toolbarbutton_colors.js]
 [browser_ext_themes_arrowpanels.js]
+[browser_ext_themes_sidebars.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_sidebars.js
@@ -0,0 +1,62 @@
+"use strict";
+
+// This test checks applied WebExtension themes that attempt to change
+// popup properties
+
+add_task(async function test_popup_styling(browser, accDoc) {
+  const BACKGROUND_COLOR = "#FF0000";
+  const TEXT_COLOR = "#008000";
+  const BORDER_COLOR = "#0000FF";
+  const HIGHLIGHT_COLOR = "#FF00FF";
+  const HIGHLIGHT_TEXT_COLOR = "#00FF00";
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "theme": {
+        "images": {
+          "headerURL": "image1.png",
+        },
+        "colors": {
+          "accentcolor": ACCENT_COLOR,
+          "textcolor": TEXT_COLOR,
+          "sidebar": BACKGROUND_COLOR,
+          "sidebar_text": TEXT_COLOR,
+          "sidebar_border": BORDER_COLOR,
+          "sidebar_highlight": HIGHLIGHT_COLOR,
+          "sidebar_highlight_text": HIGHLIGHT_TEXT_COLOR,
+        },
+      },
+    },
+    files: {
+      "image1.png": BACKGROUND,
+    },
+  });
+
+
+  await BrowserTestUtils.withNewTab({gBrowser, url: "https://example.com"}, async function(browser) {
+    await extension.startup();
+    let sidebar = document.getElementById("sidebar");
+    BrowserTestUtils.waitForEvent(sidebar, "load", true);
+    SidebarUI.toggle("viewBookmarksSidebar");
+
+    let sidebarContent = document.getElementById("sidebar");
+    let sidebarComputedStyle = window.getComputedStyle(sidebarContent);
+
+    // Ensure sidebar background color was set properly
+    Assert.equal(
+      sidebarComputedStyle.getPropertyValue("background-color"),
+      `rgb(${hexToRGB(BACKGROUND_COLOR).join(", ")})`,
+      "Popup background color should have been themed"
+    );
+
+    // Ensure sidebar text color was set properly
+    Assert.equal(
+      sidebarComputedStyle.getPropertyValue("color"),
+      `rgb(${hexToRGB(TEXT_COLOR).join(", ")})`,
+      "Popup text color should have been themed"
+    );
+
+    SidebarUI.toggle("viewBookmarksSidebar");
+    await extension.unload();
+  });
+});
--- a/toolkit/modules/LightweightThemeConsumer.jsm
+++ b/toolkit/modules/LightweightThemeConsumer.jsm
@@ -15,21 +15,25 @@ const toolkitVariableMap = [
   ["--arrowpanel-color", "popup_text"],
   ["--arrowpanel-border-color", "popup_border"],
 ];
 ChromeUtils.import("resource:///modules/ThemeVariableMap.jsm");
 
 ChromeUtils.defineModuleGetter(this, "LightweightThemeImageOptimizer",
   "resource://gre/modules/addons/LightweightThemeImageOptimizer.jsm");
 
+// this._doc: The document where the theme variables are applied in.
+// this._win: The corresponding browser window used in the theme data.
 this.LightweightThemeConsumer =
- function LightweightThemeConsumer(aDocument) {
+ function LightweightThemeConsumer(aDocument, aWindow = null) {
   this._doc = aDocument;
-  this._win = aDocument.defaultView;
-
+  if (aWindow == null)
+    this._win = aDocument.defaultView;
+  else
+    this._win = aWindow;
   let screen = this._win.screen;
   this._lastScreenWidth = screen.width;
   this._lastScreenHeight = screen.height;
 
   Services.obs.addObserver(this, "lightweight-theme-styling-update");
 
   var temp = {};
   ChromeUtils.import("resource://gre/modules/LightweightThemeManager.jsm", temp);
@@ -119,17 +123,17 @@ LightweightThemeConsumer.prototype = {
     // We need to clear these either way: either because the theme is being removed,
     // or because we are applying a new theme and the data might be bogus CSS,
     // so if we don't reset first, it'll keep the old value.
     root.style.removeProperty("--lwt-text-color");
     root.style.removeProperty("--lwt-accent-color");
     let textcolor = aData.textcolor || "black";
     _setProperty(root, active, "--lwt-text-color", textcolor);
     _setProperty(root, active, "--lwt-accent-color", this._sanitizeCSSColor(aData.accentcolor) || "white");
-
+    // add properties here MASINI
     if (active) {
       let dummy = this._doc.createElement("dummy");
       dummy.style.color = textcolor;
       let [r, g, b] = _parseRGB(this._win.getComputedStyle(dummy).color);
       let luminance = 0.2125 * r + 0.7154 * g + 0.0721 * b;
       root.setAttribute("lwthemetextcolor", luminance <= 110 ? "dark" : "bright");
       root.setAttribute("lwtheme", "true");
     } else {
@@ -197,16 +201,18 @@ function _setProperty(elem, active, vari
   } else {
     elem.style.removeProperty(variableName);
   }
 }
 
 function _setProperties(root, active, vars) {
   for (let map of [toolkitVariableMap, ThemeVariableMap]) {
     for (let [cssVarName, varsKey, optionalElementID] of map) {
+      if (optionalElementID != null)
+        continue;
       let elem = optionalElementID ? root.ownerDocument.getElementById(optionalElementID)
                                    : root;
       _setProperty(elem, active, cssVarName, vars[varsKey]);
     }
   }
 }
 
 function _parseRGB(aColorString) {