Bug 940393 - Win8: Text color on inactive tabs makes text very hard to read. r=gijs
☠☠ backed out by c1f9dc63a495 ☠ ☠
authorJared Wein <jwein@mozilla.com>
Thu, 20 Mar 2014 20:23:36 -0400
changeset 174722 bbb44c12555371b8d46793a85ca0acc60d74767a
parent 174721 f2c21183e206404f17b336b4687d19438f73d20d
child 174723 3800705bc8517fec77c9f3a347b51edea042bd60
push id26459
push usercbook@mozilla.com
push dateFri, 21 Mar 2014 14:16:34 +0000
treeherdermozilla-central@6648c56ed512 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs
bugs940393
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 940393 - Win8: Text color on inactive tabs makes text very hard to read. r=gijs
browser/base/content/browser.js
browser/components/migration/src/IEProfileMigrator.js
browser/modules/Windows8WindowFrameColor.jsm
browser/modules/WindowsRegistry.jsm
browser/modules/moz.build
browser/themes/windows/browser-aero.css
browser/themes/windows/browser.css
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1181,16 +1181,43 @@ var gBrowserInit = {
       Cu.reportError("Could not end startup crash tracking: " + ex);
     }
 
     if (typeof WindowsPrefSync !== 'undefined') {
       // Pulls in Metro controlled prefs and pushes out Desktop controlled prefs
       WindowsPrefSync.init();
     }
 
+#ifdef XP_WIN
+    if (window.matchMedia("-moz-os-version: windows-win8") &&
+        window.matchMedia("-moz-windows-default-theme")) {
+      let windows8WindowFrameColor = Cu.import("resource:///modules/Windows8WindowFrameColor.jsm", {}).Windows8WindowFrameColor;
+      let windowFrameColor = windows8WindowFrameColor.get();
+
+      // Formula from W3C Techniques For Accessibility Evaluation And
+      // Repair Tools, Section 2.2 http://www.w3.org/TR/AERT#color
+      let brightnessThreshold = 125;
+      let colorThreshold = 500;
+      let bY = windowFrameColor[0] * .299 +
+               windowFrameColor[1] * .587 +
+               windowFrameColor[2] * .114;
+      let fY = 0; // Default to black for foreground text.
+      let brightnessDifference = Math.abs(bY - fY);
+      // Color difference calculation is simplified because black is 0 for R,G,B.
+      let colorDifference = windowFrameColor[0] + windowFrameColor[1] + windowFrameColor[2];
+
+      // Brightness is defined within {0, 255}. Set an attribute
+      // if the window frame color doesn't reach these thresholds
+      // so the theme can be adjusted for readability.
+      if (brightnessDifference < brightnessThreshold && colorDifference < colorThreshold) {
+        document.documentElement.setAttribute("darkwindowframe", "true");
+      }
+    }
+#endif
+
     SessionStore.promiseInitialized.then(() => {
       // Bail out if the window has been closed in the meantime.
       if (window.closed) {
         return;
       }
 
       // Enable the Restore Last Session command if needed
       RestoreLastSessionObserver.init();
--- a/browser/components/migration/src/IEProfileMigrator.js
+++ b/browser/components/migration/src/IEProfileMigrator.js
@@ -5,27 +5,28 @@
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 const kMainKey = "Software\\Microsoft\\Internet Explorer\\Main";
-const kRegMultiSz = 7;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource:///modules/MigrationUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
                                   "resource://gre/modules/ctypes.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
+                                  "resource:///modules/WindowsRegistry.jsm");
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Helpers.
 
 let CtypesHelpers = {
   _structs: {},
   _functions: {},
   _libs: {},
@@ -121,55 +122,16 @@ function hostIsIPAddress(aHost) {
   try {
     Services.eTLD.getBaseDomainFromHost(aHost);
   } catch (e if e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {
     return true;
   } catch (e) {}
   return false;
 }
 
-/**
- * Safely reads a value from the registry.
- *
- * @param aRoot
- *        The root registry to use.
- * @param aPath
- *        The registry path to the key.
- * @param aKey
- *        The key name.
- * @return The key value or undefined if it doesn't exist.  If the key is
- *         a REG_MULTI_SZ, an array is returned.
- */
-function readRegKey(aRoot, aPath, aKey) {
-  let registry = Cc["@mozilla.org/windows-registry-key;1"].
-                 createInstance(Ci.nsIWindowsRegKey);
-  try {
-    registry.open(aRoot, aPath, Ci.nsIWindowsRegKey.ACCESS_READ);
-    if (registry.hasValue(aKey)) {
-      let type = registry.getValueType(aKey);
-      switch (type) {
-        case kRegMultiSz:
-          // nsIWindowsRegKey doesn't support REG_MULTI_SZ type out of the box.
-          let str = registry.readStringValue(aKey);
-          return [v for each (v in str.split("\0")) if (v)];
-        case Ci.nsIWindowsRegKey.TYPE_STRING:
-          return registry.readStringValue(aKey);
-        case Ci.nsIWindowsRegKey.TYPE_INT:
-          return registry.readIntValue(aKey);
-        default:
-          throw new Error("Unsupported registry value.");
-      }
-    }
-  } catch (ex) {
-  } finally {
-    registry.close();
-  }
-  return undefined;
-};
-
 ////////////////////////////////////////////////////////////////////////////////
 //// Resources
 
 function Bookmarks() {
 }
 
 Bookmarks.prototype = {
   type: MigrationUtils.resourceTypes.BOOKMARKS,
@@ -187,19 +149,19 @@ Bookmarks.prototype = {
   },
 
   __toolbarFolderName: null,
   get _toolbarFolderName() {
     if (!this.__toolbarFolderName) {
       // Retrieve the name of IE's favorites subfolder that holds the bookmarks
       // in the toolbar. This was previously stored in the registry and changed
       // in IE7 to always be called "Links".
-      let folderName = readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
-                                  "Software\\Microsoft\\Internet Explorer\\Toolbar",
-                                  "LinksFolderName");
+      let folderName = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+                                                  "Software\\Microsoft\\Internet Explorer\\Toolbar",
+                                                  "LinksFolderName");
       this.__toolbarFolderName = folderName || "Links";
     }
     return this.__toolbarFolderName;
   },
 
   migrate: function B_migrate(aCallback) {
     PlacesUtils.bookmarks.runInBatchMode({
       runBatched: (function migrateBatched() {
@@ -600,18 +562,18 @@ Settings.prototype = {
    * @param aKey
    *        Name of the key.
    * @param aPref
    *        Firefox preference.
    * @param [optional] aTransformFn
    *        Conversion function from the Registry format to the pref format.
    */
   _set: function S__set(aPath, aKey, aPref, aTransformFn) {
-    let value = readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
-                           aPath, aKey);
+    let value = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+                                           aPath, aKey);
     // Don't import settings that have never been flipped.
     if (value === undefined)
       return;
 
     if (aTransformFn)
       value = aTransformFn(value);
 
     switch (typeof(value)) {
@@ -646,31 +608,31 @@ IEProfileMigrator.prototype.getResources
   , new Cookies()
   , new Settings()
   ];
   return [r for each (r in resources) if (r.exists)];
 };
 
 Object.defineProperty(IEProfileMigrator.prototype, "sourceHomePageURL", {
   get: function IE_get_sourceHomePageURL() {
-    let defaultStartPage = readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
-                                      kMainKey, "Default_Page_URL");
-    let startPage = readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
-                               kMainKey, "Start Page");
+    let defaultStartPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
+                                                      kMainKey, "Default_Page_URL");
+    let startPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+                                               kMainKey, "Start Page");
     // If the user didn't customize the Start Page, he is still on the default
     // page, that may be considered the equivalent of our about:home.  There's
     // no reason to retain it, since it is heavily targeted to IE.
     let homepage = startPage != defaultStartPage ? startPage : "";
 
     // IE7+ supports secondary home pages located in a REG_MULTI_SZ key.  These
     // are in addition to the Start Page, and no empty entries are possible,
     // thus a Start Page is always defined if any of these exists, though it
     // may be the default one.
-    let secondaryPages = readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
-                                    kMainKey, "Secondary Start Pages");
+    let secondaryPages = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+                                                    kMainKey, "Secondary Start Pages");
     if (secondaryPages) {
       if (homepage)
         secondaryPages.unshift(homepage);
       homepage = secondaryPages.join("|");
     }
 
     return homepage;
   }
new file mode 100644
--- /dev/null
+++ b/browser/modules/Windows8WindowFrameColor.jsm
@@ -0,0 +1,33 @@
+/* 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/. */
+
+"use strict";
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+this.EXPORTED_SYMBOLS = ["Windows8WindowFrameColor"];
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource:///modules/WindowsRegistry.jsm");
+
+const Windows8WindowFrameColor = {
+  _windowFrameColor: null,
+
+  get: function() {
+    if (this._windowFrameColor)
+      return this._windowFrameColor;
+
+    let windowFrameColor = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+                                                      "Software\\Microsoft\\Windows\\DWM",
+                                                      "ColorizationColor");
+    // The color returned from the Registry is in decimal form.
+    let windowFrameColorHex = windowFrameColor.toString(16);
+    // Zero-pad the number just to make sure that it is 8 digits.
+    windowFrameColorHex = ("00000000" + windowFrameColorHex).substr(-8);
+    let windowFrameColorArray = windowFrameColorHex.match(/../g);
+    let [pixelA, pixelR, pixelG, pixelB] = windowFrameColorArray.map(function(val) parseInt(val, 16));
+
+    return this._windowFrameColor = [pixelR, pixelG, pixelB];
+  },
+};
new file mode 100644
--- /dev/null
+++ b/browser/modules/WindowsRegistry.jsm
@@ -0,0 +1,50 @@
+/* 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/. */
+
+"use strict";
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+this.EXPORTED_SYMBOLS = ["WindowsRegistry"];
+
+const WindowsRegistry = {
+  /**
+   * Safely reads a value from the registry.
+   *
+   * @param aRoot
+   *        The root registry to use.
+   * @param aPath
+   *        The registry path to the key.
+   * @param aKey
+   *        The key name.
+   * @return The key value or undefined if it doesn't exist.  If the key is
+   *         a REG_MULTI_SZ, an array is returned.
+   */
+  readRegKey: function(aRoot, aPath, aKey) {
+    const kRegMultiSz = 7;
+    let registry = Cc["@mozilla.org/windows-registry-key;1"].
+                   createInstance(Ci.nsIWindowsRegKey);
+    try {
+      registry.open(aRoot, aPath, Ci.nsIWindowsRegKey.ACCESS_READ);
+      if (registry.hasValue(aKey)) {
+        let type = registry.getValueType(aKey);
+        switch (type) {
+          case kRegMultiSz:
+            // nsIWindowsRegKey doesn't support REG_MULTI_SZ type out of the box.
+            let str = registry.readStringValue(aKey);
+            return [v for each (v in str.split("\0")) if (v)];
+          case Ci.nsIWindowsRegKey.TYPE_STRING:
+            return registry.readStringValue(aKey);
+          case Ci.nsIWindowsRegKey.TYPE_INT:
+            return registry.readIntValue(aKey);
+          default:
+            throw new Error("Unsupported registry value.");
+        }
+      }
+    } catch (ex) {
+    } finally {
+      registry.close();
+    }
+    return undefined;
+  },
+};
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -21,18 +21,20 @@ EXTRA_JS_MODULES += [
     'Social.jsm',
     'TabCrashReporter.jsm',
     'WebappManager.jsm',
     'webrtcUI.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXTRA_JS_MODULES += [
+        'Windows8WindowFrameColor.jsm',
         'WindowsJumpLists.jsm',
         'WindowsPreviewPerTab.jsm',
+        'WindowsRegistry.jsm',
     ]
 
 EXTRA_PP_JS_MODULES += [
     'AboutHome.jsm',
     'RecentWindow.jsm',
     'UITour.jsm',
 ]
 
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -131,16 +131,36 @@
   #toolbar-menubar:not(:-moz-lwtheme),
   #TabsToolbar:not(:-moz-lwtheme) {
     background-color: transparent !important;
     color: black;
     border-left-style: none !important;
     border-right-style: none !important;
   }
 
+  #main-window[darkwindowframe="true"] #toolbar-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive),
+  #main-window[darkwindowframe="true"] #TabsToolbar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
+    color: white;
+  }
+
+  #main-window[darkwindowframe="true"] :-moz-any(#toolbar-menubar, #TabsToolbar) :-moz-any(@primaryToolbarButtons@):not(:-moz-lwtheme):not(:-moz-window-inactive),
+  #main-window[darkwindowframe="true"] :-moz-any(#toolbar-menubar, #TabsToolbar) #bookmarks-menu-button:not(:-moz-lwtheme) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:not(:-moz-window-inactive) {
+    list-style-image: url(chrome://browser/skin/Toolbar-inverted.png);
+  }
+
+  #main-window[darkwindowframe="true"] .tabs-newtab-button:not(:-moz-lwtheme):not(:-moz-window-inactive),
+  #main-window[darkwindowframe="true"] :-moz-any(#toolbar-menubar, #TabsToolbar) > #new-tab-button:not(:-moz-lwtheme):not(:-moz-window-inactive),
+  #main-window[darkwindowframe="true"] :-moz-any(#toolbar-menubar, #TabsToolbar) > toolbarpaletteitem > #new-tab-button:not(:-moz-lwtheme):not(:-moz-window-inactive) {
+    list-style-image: url(chrome://browser/skin/tabbrowser/newtab-inverted.png);
+  }
+
+  #main-window[darkwindowframe="true"] .tab-close-button:not(:-moz-any(:hover, [selected="true"], :-moz-lwtheme, :-moz-window-inactive)) {
+    -moz-image-region: rect(0, 64px, 16px, 48px);
+  }
+
   #toolbar-menubar:not(:-moz-lwtheme) {
     text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
   }
 
   /* Vertical toolbar border */
   #main-window[sizemode=normal] #navigator-toolbox::after,
   #main-window[sizemode=normal] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
     border-left: 1px solid @toolbarShadowColor@;
@@ -190,16 +210,17 @@
   }
 
   #appcontent:not(:-moz-lwtheme) {
     background-color: -moz-dialog;
   }
 
   #main-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
     background-color: rgba(255,255,255,.5);
+    color: black;
   }
 
   @media (-moz-os-version: windows-vista),
          (-moz-os-version: windows-win7) {
     #main-window[sizemode=normal] #nav-bar {
       border-top-left-radius: 2.5px;
       border-top-right-radius: 2.5px;
     }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -104,18 +104,18 @@
     -moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox");
     visibility: visible;
   }
 %ifdef WINDOWS_AERO
 }
 %endif
 
 /* Make the menu inherit the toolbar's color. On non-compositor (Aero Basic, XP modern, classic)
- * this is defined above. Otherwise (Aero Glass, Windows 8), this is hardcoded to black in
- * browser-aero.css. */
+ * this is defined above. Otherwise (Aero Glass, Windows 8 inactive windows), this is hardcoded
+ * to black in browser-aero.css. */
 #main-menubar > menu:not(:-moz-lwtheme) {
   color: inherit;
 }
 
 /**
  * In the classic themes, the titlebar has a horizontal gradient, which is
  * problematic for reading the text of background tabs when they're in the
  * titlebar. We side-step this issue by layering our own background underneath