Bug 511771 - Provide a way for Web content to preview and install lightweight themes. r=mconnor, sr=vlad
authorDão Gottwald <dao@mozilla.com>
Tue, 22 Sep 2009 10:40:12 +0200
changeset 32945 a534af2896e24293dfa843a68730f5da83ac3247
parent 32944 58922624da1cedfb8bf78ac453277b8808353dcf
child 32946 80dc1c31b175fdbfeea482af4aaede6aa5e2b57f
push id9244
push userdgottwald@mozilla.com
push dateTue, 22 Sep 2009 08:44:41 +0000
treeherdermozilla-central@a534af2896e2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconnor, vlad
bugs511771
milestone1.9.3a1pre
Bug 511771 - Provide a way for Web content to preview and install lightweight themes. r=mconnor, sr=vlad
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/components/preferences/permissions.js
toolkit/content/LightweightThemeConsumer.jsm
toolkit/mozapps/extensions/test/unit/test_LightweightThemeManager.js
xpinstall/src/nsInstallTrigger.cpp
xpinstall/src/nsInstallTrigger.h
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -170,18 +170,18 @@ pref("extensions.getMoreThemesURL", "htt
 pref("extensions.getMorePluginsURL", "https://%LOCALE%.add-ons.mozilla.com/%LOCALE%/%APP%/%VERSION%/plugins/");
 pref("extensions.dss.enabled", false);          // Dynamic Skin Switching                                               
 pref("extensions.dss.switchPending", false);    // Non-dynamic switch pending after next
                                                 // restart.
 
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name", "chrome://browser/locale/browser.properties");
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description", "chrome://browser/locale/browser.properties");
 
-pref("xpinstall.whitelist.add", "update.mozilla.org");
-pref("xpinstall.whitelist.add.103", "addons.mozilla.org");
+pref("xpinstall.whitelist.add", "addons.mozilla.org");
+pref("xpinstall.whitelist.add.36", "getpersonas.com");
 
 pref("keyword.enabled", true);
 pref("keyword.URL", "chrome://browser-region/locale/region.properties");
 
 pref("general.useragent.locale", "@AB_CD@");
 pref("general.skins.selectedSkin", "classic/1.0");
 pref("general.useragent.extra.firefox", "@APP_UA_NAME@/@APP_VERSION@");
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1351,16 +1351,20 @@ function delayedStartup(isLoadingBlank, 
   updateEditUIVisibility();
   let placesContext = document.getElementById("placesContext");
   placesContext.addEventListener("popupshowing", updateEditUIVisibility, false);
   placesContext.addEventListener("popuphiding", updateEditUIVisibility, false);
 #endif
 
   // initialize the private browsing UI
   gPrivateBrowsingUI.init();
+
+  gBrowser.mPanelContainer.addEventListener("InstallBrowserTheme", LightWeightThemeWebInstaller, false, true);
+  gBrowser.mPanelContainer.addEventListener("PreviewBrowserTheme", LightWeightThemeWebInstaller, false, true);
+  gBrowser.mPanelContainer.addEventListener("ResetBrowserThemePreview", LightWeightThemeWebInstaller, false, true);
 }
 
 function BrowserShutdown()
 {
   gPrefService.removeObserver(ctrlTab.prefName, ctrlTab);
   gPrefService.removeObserver(allTabs.prefName, allTabs);
   tabPreviews.uninit();
   ctrlTab.uninit();
@@ -7051,8 +7055,146 @@ let gURLBarEmptyText = {
       case 2:
         type = "bookmark";
         break;
       }
     }
     return gURLBar.getAttribute(type + "emptytext");
   }
 };
+
+var LightWeightThemeWebInstaller = {
+  handleEvent: function (event) {
+    switch (event.type) {
+      case "InstallBrowserTheme":
+        this._install(event);
+        break;
+      case "PreviewBrowserTheme":
+        this._preview(event);
+        break;
+      case "ResetBrowserThemePreview":
+        this._resetPreview(event);
+        break;
+    }
+  },
+
+  get _manager () {
+    var temp = {};
+    Cu.import("resource://gre/modules/LightweightThemeManager.jsm", temp);
+    delete this._manager;
+    return this._manager = temp.LightweightThemeManager;
+  },
+
+  _install: function (event) {
+    var node = event.target;
+    var data = this._getThemeFromNode(node);
+    if (!data)
+      return;
+
+    if (this._isAllowed(node)) {
+      this._manager.currentTheme = data;
+      return;
+    }
+
+    var allowButtonText =
+      gNavigatorBundle.getString("lwthemeInstallRequest.allowButton");
+    var allowButtonAccesskey =
+      gNavigatorBundle.getString("lwthemeInstallRequest.allowButton.accesskey");
+    var message =
+      gNavigatorBundle.getFormattedString("lwthemeInstallRequest.message",
+                                          [node.ownerDocument.location.host]);
+    var buttons = [{
+      label: allowButtonText,
+      accessKey: allowButtonAccesskey,
+      callback: function () {
+        LightWeightThemeWebInstaller._manager.currentTheme = data;
+      }
+    }];
+    var notificationBox = gBrowser.getNotificationBox();
+    notificationBox.appendNotification(message, "lwtheme-install-request", "",
+                                       notificationBox.PRIORITY_INFO_MEDIUM,
+                                       buttons);
+  },
+
+  _preview: function (event) {
+    if (!this._isAllowed(event.target))
+      return;
+
+    var data = this._getThemeFromNode(event.target);
+    if (!data)
+      return;
+
+    this._manager.previewTheme(data);
+  },
+
+  _resetPreview: function (event) {
+    if (!this._isAllowed(event.target))
+      return;
+
+    this._manager.resetPreview();
+  },
+
+  _isAllowed: function (node) {
+    var pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
+
+    var prefs = [["xpinstall.whitelist.add", pm.ALLOW_ACTION],
+                 ["xpinstall.whitelist.add.36", pm.ALLOW_ACTION],
+                 ["xpinstall.blacklist.add", pm.DENY_ACTION]];
+    prefs.forEach(function ([pref, permission]) {
+      try {
+        var hosts = gPrefService.getCharPref(pref);
+      } catch (e) {}
+
+      if (hosts) {
+        hosts.split(",").forEach(function (host) {
+          pm.add(makeURI("http://" + host), "install", permission);
+        });
+
+        gPrefService.setCharPref(pref, "");
+      }
+    });
+
+    var uri = node.ownerDocument.documentURIObject;
+    return pm.testPermission(uri, "install") == pm.ALLOW_ACTION;
+  },
+
+  _getThemeFromNode: function (node) {
+    const MANDATORY = ["id", "name", "headerURL"];
+    const OPTIONAL = ["footerURL", "textcolor", "accentcolor", "iconURL",
+                      "previewURL", "author", "description", "homepageURL"];
+
+    try {
+      var data = JSON.parse(node.getAttribute("data-browsertheme"));
+    } catch (e) {
+      return null;
+    }
+
+    if (!data || typeof data != "object")
+      return null;
+
+    for (let prop in data) {
+      if (!data[prop] ||
+          typeof data[prop] != "string" ||
+          MANDATORY.indexOf(prop) == -1 && OPTIONAL.indexOf(prop) == -1) {
+        delete data[prop];
+        continue;
+      }
+
+      if (/URL$/.test(prop)) {
+        try {
+          data[prop] = makeURLAbsolute(node.baseURI, data[prop]);
+
+          if (/^https?:/.test(data[prop]))
+            continue;
+        } catch (e) {}
+
+        delete data[prop];
+      }
+    }
+
+    for (let i = 0; i < MANDATORY.length; i++) {
+      if (!(MANDATORY[i] in data)) 
+        return null;
+    }
+
+    return data;
+  }
+}
--- a/browser/components/preferences/permissions.js
+++ b/browser/components/preferences/permissions.js
@@ -366,17 +366,17 @@ var gPermissionManager = {
   _updatePermissions: function ()
   {
     try {
       var ioService = Components.classes["@mozilla.org/network/io-service;1"]
                                 .getService(Components.interfaces.nsIIOService);
       var pbi = Components.classes["@mozilla.org/preferences-service;1"]
                           .getService(Components.interfaces.nsIPrefBranch2);
       var prefList = [["xpinstall.whitelist.add", nsIPermissionManager.ALLOW_ACTION],
-                      ["xpinstall.whitelist.add.103", nsIPermissionManager.ALLOW_ACTION],
+                      ["xpinstall.whitelist.add.36", nsIPermissionManager.ALLOW_ACTION],
                       ["xpinstall.blacklist.add", nsIPermissionManager.DENY_ACTION]];
 
       for (var i = 0; i < prefList.length; ++i) {
         try {
           // this pref is a comma-delimited list of hosts
           var hosts = pbi.getCharPref(prefList[i][0]);
         } catch(ex) {
           continue;
--- a/toolkit/content/LightweightThemeConsumer.jsm
+++ b/toolkit/content/LightweightThemeConsumer.jsm
@@ -62,29 +62,31 @@ LightweightThemeConsumer.prototype = {
               .getService(Components.interfaces.nsIObserverService)
               .removeObserver(this, "lightweight-theme-changed");
 
     this._doc = null;
   },
 
   _update: function (aData) {
     if (!aData)
-      aData = { headerURL: "", footerURL: "", textColor: "", dominantColor: "" };
+      aData = { headerURL: "", footerURL: "", textcolor: "", accentcolor: "" };
 
     var root = this._doc.documentElement;
     var active = !!aData.headerURL;
 
     if (active) {
-      root.style.color = aData.textColor || "black";
+      root.style.color = aData.textcolor || "black";
+      root.style.backgroundColor = aData.accentcolor || "white";
       let [r, g, b] = _parseRGB(this._doc.defaultView.getComputedStyle(root, "").color);
       let brightness = (r + g + b) / 3;
       root.setAttribute("lwthemetextcolor", brightness <= 127 ? "dark" : "bright");
       root.setAttribute("lwtheme", "true");
     } else {
       root.style.color = "";
+      root.style.backgroundColor = "";
       root.removeAttribute("lwthemetextcolor");
       root.removeAttribute("lwtheme");
     }
 
     _setImage(root, active, aData.headerURL);
     if (this._footerId) {
       let footer = this._doc.getElementById(this._footerId);
       _setImage(footer, active, aData.footerURL);
@@ -96,19 +98,19 @@ LightweightThemeConsumer.prototype = {
 
     if (root.hasAttribute("activetitlebarcolor")) {
       if (!root.hasAttribute("originalactivetitlebarcolor")) {
         root.setAttribute("originalactivetitlebarcolor",
                           root.getAttribute("activetitlebarcolor"));
         root.setAttribute("originalinactivetitlebarcolor",
                           root.getAttribute("inactivetitlebarcolor"));
       }
-      root.setAttribute("activetitlebarcolor", aData.dominantColor
+      root.setAttribute("activetitlebarcolor", (active && aData.accentcolor)
                           || root.getAttribute("originalactivetitlebarcolor"));
-      root.setAttribute("inactivetitlebarcolor", aData.dominantColor
+      root.setAttribute("inactivetitlebarcolor", (active && aData.accentcolor)
                           || root.getAttribute("originalinactivetitlebarcolor"));
     }
   }
 }
 
 function _setImage(aElement, aActive, aURL) {
   aElement.style.backgroundImage =
     (aActive && aURL) ? 'url("' + aURL.replace('"', '\\"', "g") + '")' : "";
--- a/toolkit/mozapps/extensions/test/unit/test_LightweightThemeManager.js
+++ b/toolkit/mozapps/extensions/test/unit/test_LightweightThemeManager.js
@@ -1,16 +1,16 @@
 function dummy(id) {
   return {
     id: id,
     name: Math.random(),
     headerURL: Math.random(),
     footerURL: Math.random(),
-    textColor: Math.random(),
-    dominantColor: Math.random()
+    textcolor: Math.random(),
+    accentcolor: Math.random()
   };
 }
 
 function run_test() {
   var temp = {};
   Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", temp);
   do_check_eq(typeof temp.LightweightThemeManager, "object");
 
--- a/xpinstall/src/nsInstallTrigger.cpp
+++ b/xpinstall/src/nsInstallTrigger.cpp
@@ -345,17 +345,17 @@ nsInstallTrigger::AllowInstall(nsIURI* a
 
         // file: and chrome: don't need whitelisted hosts
         if ( !isChrome && !isFile )
         {
             // check prefs for permission updates before testing URI
             updatePermissions( XPINSTALL_WHITELIST_ADD,
                                nsIPermissionManager::ALLOW_ACTION,
                                permissionMgr, prefBranch );
-            updatePermissions( XPINSTALL_WHITELIST_ADD_103,
+            updatePermissions( XPINSTALL_WHITELIST_ADD_36,
                                nsIPermissionManager::ALLOW_ACTION,
                                permissionMgr, prefBranch );
             updatePermissions( XPINSTALL_BLACKLIST_ADD,
                                nsIPermissionManager::DENY_ACTION,
                                permissionMgr, prefBranch );
 
             PRBool requireWhitelist = PR_TRUE;
             prefBranch->GetBoolPref( XPINSTALL_WHITELIST_REQUIRED, &requireWhitelist );
--- a/xpinstall/src/nsInstallTrigger.h
+++ b/xpinstall/src/nsInstallTrigger.h
@@ -27,17 +27,17 @@
 
 #define XPI_PERMISSION      "install"
 
 #define XPI_WHITELIST       PR_TRUE
 #define XPI_GLOBAL          PR_FALSE
 
 #define XPINSTALL_ENABLE_PREF            "xpinstall.enabled"
 #define XPINSTALL_WHITELIST_ADD          "xpinstall.whitelist.add"
-#define XPINSTALL_WHITELIST_ADD_103      "xpinstall.whitelist.add.103"
+#define XPINSTALL_WHITELIST_ADD_36       "xpinstall.whitelist.add.36"
 #define XPINSTALL_WHITELIST_REQUIRED     "xpinstall.whitelist.required"
 #define XPINSTALL_BLACKLIST_ADD          "xpinstall.blacklist.add"
 
 class nsInstallTrigger: public nsIScriptObjectOwner,
                         public nsIDOMInstallTriggerGlobal,
                         public nsIContentHandler
 {
     public: