Merge m-c to inbound on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 16 Apr 2014 22:54:57 -0400
changeset 179346 f011f98832e26151590465d8211cdb759acaa05d
parent 179274 18224f0cc4dd08e3a5a4ff6b417ebe11b3204faf (current diff)
parent 179345 e71ed4135461b57a9c7f35995e4e1f1dc5f0e8bf (diff)
child 179347 f1cbde906d5d59e558df56a292a059fbdf7e3396
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
milestone31.0a1
Merge m-c to inbound on a CLOSED TREE.
browser/base/content/aboutaccounts/fonts/clearsans-regular.woff
browser/base/content/aboutaccounts/fonts/firasans-light.woff
browser/base/content/aboutaccounts/fonts/firasans-regular.woff
browser/components/customizableui/test/browser_996364_defaultCollapsed.js
browser/themes/linux/devtools/ruleview.css
browser/themes/osx/devtools/ruleview.css
browser/themes/shared/ClearSans-Regular.ttf
browser/themes/windows/devtools/ruleview.css
dom/icc/interfaces/nsIDOMIccManager.idl
--- a/b2g/chrome/content/devtools.js
+++ b/b2g/chrome/content/devtools.js
@@ -2,34 +2,34 @@
  * 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 DEVELOPER_HUD_LOG_PREFIX = 'DeveloperHUD';
 
 XPCOMUtils.defineLazyGetter(this, 'devtools', function() {
-  const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+  const {devtools} = Cu.import('resource://gre/modules/devtools/Loader.jsm', {});
   return devtools;
 });
 
 XPCOMUtils.defineLazyGetter(this, 'DebuggerClient', function() {
   return Cu.import('resource://gre/modules/devtools/dbg-client.jsm', {}).DebuggerClient;
 });
 
 XPCOMUtils.defineLazyGetter(this, 'WebConsoleUtils', function() {
-  return devtools.require("devtools/toolkit/webconsole/utils").Utils;
+  return devtools.require('devtools/toolkit/webconsole/utils').Utils;
 });
 
 XPCOMUtils.defineLazyGetter(this, 'EventLoopLagFront', function() {
-  return devtools.require("devtools/server/actors/eventlooplag").EventLoopLagFront;
+  return devtools.require('devtools/server/actors/eventlooplag').EventLoopLagFront;
 });
 
 XPCOMUtils.defineLazyGetter(this, 'MemoryFront', function() {
-  return devtools.require("devtools/server/actors/memory").MemoryFront;
+  return devtools.require('devtools/server/actors/memory').MemoryFront;
 });
 
 
 /**
  * The Developer HUD is an on-device developer tool that displays widgets,
  * showing visual debug information about apps. Each widget corresponds to a
  * metric as tracked by a metric watcher (e.g. consoleWatcher).
  */
@@ -42,17 +42,17 @@ let developerHUD = {
   _watchers: [],
   _logging: true,
 
   /**
    * This method registers a metric watcher that will watch one or more metrics
    * on app frames that are being tracked. A watcher must implement the
    * `trackTarget(target)` and `untrackTarget(target)` methods, register
    * observed metrics with `target.register(metric)`, and keep them up-to-date
-   * with `target.update(metric, value, message)` when necessary.
+   * with `target.update(metric, message)` when necessary.
    */
   registerWatcher: function dwp_registerWatcher(watcher) {
     this._watchers.unshift(watcher);
   },
 
   init: function dwp_init() {
     if (this._client)
       return;
@@ -205,25 +205,34 @@ Target.prototype = {
   register: function target_register(metric) {
     this.metrics.set(metric, 0);
   },
 
   /**
    * Modify one of a target's metrics, and send out an event to notify relevant
    * parties (e.g. the developer HUD, automated tests, etc).
    */
-  update: function target_update(metric, value = 0, message) {
+  update: function target_update(metric, message) {
+    if (!metric.name) {
+      throw new Error('Missing metric.name');
+    }
+
+    if (!metric.value) {
+      metric.value = 0;
+    }
+
     let metrics = this.metrics;
-    metrics.set(metric, value);
+    if (metrics) {
+      metrics.set(metric.name, metric.value);
+    }
 
     let data = {
       metrics: [], // FIXME(Bug 982066) Remove this field.
       manifest: this.frame.appManifestURL,
       metric: metric,
-      value: value,
       message: message
     };
 
     // FIXME(Bug 982066) Remove this loop.
     if (metrics && metrics.size > 0) {
       for (let name of metrics.keys()) {
         data.metrics.push({name: name, value: metrics.get(name)});
       }
@@ -235,25 +244,27 @@ Target.prototype = {
     this._send(data);
   },
 
   /**
    * Nicer way to call update() when the metric value is a number that needs
    * to be incremented.
    */
   bump: function target_bump(metric, message) {
-    this.update(metric, this.metrics.get(metric) + 1, message);
+    metric.value = (this.metrics.get(metric.name) || 0) + 1;
+    this.update(metric, message);
   },
 
   /**
    * Void a metric value and make sure it isn't displayed on the front-end
    * anymore.
    */
   clear: function target_clear(metric) {
-    this.update(metric, 0);
+    metric.value = 0;
+    this.update(metric);
   },
 
   /**
    * Tear everything down, including the front-end by sending a message without
    * widgets.
    */
   destroy: function target_destroy() {
     delete this.metrics;
@@ -302,17 +313,17 @@ let consoleWatcher = {
       SettingsListener.observe('hud.' + metric, watching[metric], watch => {
         // Watch or unwatch the metric.
         if (watching[metric] = watch) {
           return;
         }
 
         // If unwatched, remove any existing widgets for that metric.
         for (let target of this._targets.values()) {
-          target.clear(metric);
+          target.clear({name: metric});
         }
       });
     }
 
     client.addListener('logMessage', this.consoleListener);
     client.addListener('pageError', this.consoleListener);
     client.addListener('consoleAPICall', this.consoleListener);
     client.addListener('reflowActivity', this.consoleListener);
@@ -340,72 +351,76 @@ let consoleWatcher = {
       listeners: ['LogMessage', 'PageError', 'ConsoleAPI', 'ReflowActivity']
     }, (res) => { });
 
     this._targets.delete(target.actor.consoleActor);
   },
 
   consoleListener: function cw_consoleListener(type, packet) {
     let target = this._targets.get(packet.from);
-    let metric;
+    let metric = {};
     let output = '';
 
     switch (packet.type) {
 
       case 'pageError':
         let pageError = packet.pageError;
 
         if (pageError.warning || pageError.strict) {
-          metric = 'warnings';
+          metric.name = 'warnings';
           output += 'warning (';
         } else {
-          metric = 'errors';
+          metric.name = 'errors';
           output += 'error (';
         }
 
         if (this._security.indexOf(pageError.category) > -1) {
-          metric = 'security';
+          metric.name = 'security';
         }
 
         let {errorMessage, sourceName, category, lineNumber, columnNumber} = pageError;
         output += category + '): "' + (errorMessage.initial || errorMessage) +
           '" in ' + sourceName + ':' + lineNumber + ':' + columnNumber;
         break;
 
       case 'consoleAPICall':
         switch (packet.message.level) {
 
           case 'error':
-            metric = 'errors';
+            metric.name = 'errors';
             output += 'error (console)';
             break;
 
           case 'warn':
-            metric = 'warnings';
+            metric.name = 'warnings';
             output += 'warning (console)';
             break;
 
           default:
             return;
         }
         break;
 
       case 'reflowActivity':
-        metric = 'reflows';
+        metric.name = 'reflows';
 
-        let {start, end, sourceURL} = packet;
+        let {start, end, sourceURL, interruptible} = packet;
+        metric.interruptible = interruptible;
         let duration = Math.round((end - start) * 100) / 100;
         output += 'reflow: ' + duration + 'ms';
         if (sourceURL) {
           output += ' ' + this.formatSourceURL(packet);
         }
         break;
+
+      default:
+        return;
     }
 
-    if (!this._watching[metric]) {
+    if (!this._watching[metric.name]) {
       return;
     }
 
     target.bump(metric, output);
   },
 
   formatSourceURL: function cw_formatSourceURL(packet) {
     // Abbreviate source URL
@@ -441,29 +456,29 @@ let eventLoopLagWatcher = {
 
     // Toggle the state of existing fronts.
     let fronts = this._fronts;
     for (let target of fronts.keys()) {
       if (value) {
         fronts.get(target).start();
       } else {
         fronts.get(target).stop();
-        target.clear('jank');
+        target.clear({name: 'jank'});
       }
     }
   },
 
   trackTarget: function(target) {
     target.register('jank');
 
     let front = new EventLoopLagFront(this._client, target.actor);
     this._fronts.set(target, front);
 
     front.on('event-loop-lag', time => {
-      target.update('jank', time, 'jank: ' + time + 'ms');
+      target.update({name: 'jank', value: time}, 'jank: ' + time + 'ms');
     });
 
     if (this._active) {
       front.start();
     }
   },
 
   untrackTarget: function(target) {
@@ -509,17 +524,17 @@ let memoryWatcher = {
     SettingsListener.observe('hud.appmemory', false, enabled => {
       if (this._active = enabled) {
         for (let target of this._fronts.keys()) {
           this.measure(target);
         }
       } else {
         for (let target of this._fronts.keys()) {
           clearTimeout(this._timers.get(target));
-          target.clear('memory');
+          target.clear({name: 'memory'});
         }
       }
     });
   },
 
   measure: function mw_measure(target) {
 
     // TODO Also track USS (bug #976024).
@@ -545,17 +560,17 @@ let memoryWatcher = {
       if (watch.style) {
         total += parseInt(data.styleSize);
       }
       if (watch.other) {
         total += parseInt(data.otherSize);
       }
       // TODO Also count images size (bug #976007).
 
-      target.update('memory', total);
+      target.update({name: 'memory', value: total});
       let duration = parseInt(data.jsMilliseconds) + parseInt(data.nonJSMilliseconds);
       let timer = setTimeout(() => this.measure(target), 100 * duration);
       this._timers.set(target, timer);
     }, (err) => {
       console.error(err);
     });
   },
 
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="52c909ccead537f8f9dbf634f3e6639078a8b0bd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -13,17 +13,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
@@ -115,28 +115,28 @@
   <project name="platform/system/netd" path="system/netd" revision="ea8103eae5642621ca8202e00620f4ca954ed413"/>
   <project name="platform/system/security" path="system/security" revision="360f51f7af191316cd739f229db1c5f7233be063"/>
   <project name="platform/system/vold" path="system/vold" revision="153df4d067a4149c7d78f1c92fed2ce2bd6a272e"/>
   <default remote="caf" revision="jb_3.2" sync-j="4"/>
   <!-- Flame specific things -->
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="e8a318f7690092e639ba88891606f4183e846d3f"/>
   <project name="device/qcom/common" path="device/qcom/common" revision="c2c115bec6f5e9bc1daf7bb74bb4d14861c00b9c"/>
   <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="92f9b79e3a5ecf24cb0f66e20d5292b300f8cac9"/>
-  <project name="kernel/msm" path="kernel" revision="ecf7fb3e0178b28a61c4cccc9073ea111e5522ef"/>
+  <project name="kernel/msm" path="kernel" revision="39ca56deb6c4419c0220a762f6e340091032390d"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="f2914eacee9120680a41463708bb6ee8291749fc"/>
   <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="c53977638eb8a7091f752d870e8e0f00f7a23d95"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="f0689ac1914cdbc59e53bdc9edd9013dc157c299"/>
   <project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="dd925f76e4f149c3d5571b80e12f7e24bbe89c59"/>
   <project name="platform/external/dbus" path="external/dbus" revision="ea87119c843116340f5df1d94eaf8275e1055ae8"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="320b05a5761eb2a4816f7529c91ea49422979b55"/>
   <project name="platform/frameworks/av" path="frameworks/av" revision="1df6dac11d7370a2fffca8e31d65b80f537faec5"/>
   <project name="platform/frameworks/base" path="frameworks/base" revision="807d87d5ff66cb5e0664f6924f612fcdb5e2c453"/>
   <project name="platform/frameworks/native" path="frameworks/native" revision="33a2b51f78416536e1bfba0c0b7776db307f3a4f"/>
   <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="484802559ed106bac4811bd01c024ca64f741e60"/>
-  <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="2ff71f0d6af6ae6a15b1c9eaa89f1e4c883115bb"/>
+  <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="d30227d7ae5cbe8bac8775358b472f44504a20d2"/>
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="81afa7f775b7559da52f468150d1fe090c3fbdc5"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="e38444b6ce12c7c25883272a439800376d5308eb"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="13312a5577db9261cb0fcee9ccbc58cdb5e6bc55"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="8a0d0b0d9889ef99c4c6317c810db4c09295f15a"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2208fa3537ace873b8f9ec2355055761c79dfd5f"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
   <project name="platform/system/core" path="system/core" revision="8b7736c56fa9a3fd8b4341eb243e12eec847efed"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "f1f04d6c6f247e9a83960903e2f15774f07ca579", 
+    "revision": "e1fc74c2ae523e7cce5be01e1a29b43defaec124", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/aboutaccounts/fonts.css
+++ b/browser/base/content/aboutaccounts/fonts.css
@@ -1,25 +1,24 @@
 @font-face {
   font-family: 'Fira Sans';
   font-style: normal;
   font-weight: 400;
   src: local('Fira Sans'),
        local('FiraSans'),
-       url('fonts/firasans-regular.woff') format('woff');
+       url('../fonts/FiraSans-Regular.woff') format('woff');
 }
 @font-face {
   font-family: 'Fira Sans';
   font-style: normal;
   font-weight: 300;
   src: local('Fira Sans Light'),
        local('FiraSansLight'),
-       url('fonts/firasans-light.woff') format('woff');
+       url('../fonts/FiraSans-Light.woff') format('woff');
 }
 @font-face {
   font-family: 'Clear Sans';
   font-style: normal;
   font-weight: 400;
   src: local('Clear Sans'),
        local('ClearSans'),
-       url('fonts/clearsans-regular.woff') format('woff');
+       url('../fonts/ClearSans-Regular.woff') format('woff');
 }
-
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -58,16 +58,20 @@ var StarUI = {
   // nsIDOMEventListener
   handleEvent: function SU_handleEvent(aEvent) {
     switch (aEvent.type) {
       case "popuphidden":
         if (aEvent.originalTarget == this.panel) {
           if (!this._element("editBookmarkPanelContent").hidden)
             this.quitEditMode();
 
+          if (this._anchorToolbarButton) {
+            this._anchorToolbarButton.removeAttribute("open");
+            this._anchorToolbarButton = null;
+          }
           this._restoreCommandsState();
           this._itemId = -1;
           if (this._batching) {
             PlacesUtils.transactionManager.endBatch(false);
             this._batching = false;
           }
 
           switch (this._actionOnHide) {
@@ -181,16 +185,31 @@ var StarUI = {
     this._element("editBookmarkPanelRemoveButton").label = label;
 
     // unset the unstarred state, if set
     this._element("editBookmarkPanelStarIcon").removeAttribute("unstarred");
 
     this._itemId = aItemId !== undefined ? aItemId : this._itemId;
     this.beginBatch();
 
+    if (aAnchorElement) {
+      // Set the open=true attribute if the anchor is a
+      // descendent of a toolbarbutton.
+      let parent = aAnchorElement.parentNode;
+      while (parent) {
+        if (parent.localName == "toolbarbutton") {
+          break;
+        }
+        parent = parent.parentNode;
+      }
+      if (parent) {
+        this._anchorToolbarButton = parent;
+        parent.setAttribute("open", "true");
+      }
+    }
     this.panel.openPopup(aAnchorElement, aPosition);
 
     gEditItemOverlay.initPanel(this._itemId,
                                { hiddenRows: ["description", "location",
                                               "loadInSidebar", "keyword"] });
   },
 
   panelShown:
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -232,20 +232,16 @@ let gSyncUI = {
     ));
 
     let notification = new Weave.Notification(
       title, description, null, Weave.Notifications.PRIORITY_WARNING, buttons);
     Weave.Notifications.replaceTitle(notification);
   },
 
   _getAppName: function () {
-    try {
-      let syncStrings = new StringBundle("chrome://browser/locale/sync.properties");
-      return syncStrings.getFormattedString("sync.defaultAccountApplication", [brandName]);
-    } catch (ex) {}
     let brand = new StringBundle("chrome://branding/locale/brand.properties");
     return brand.get("brandShortName");
   },
 
   onEOLNotice: function (data) {
     let code = data.code;
     let kind = (code == "hard-eol") ? "error" : "warning";
     let url = data.url || gSyncUI.DEFAULT_EOL_URL;
rename from browser/base/content/aboutaccounts/fonts/clearsans-regular.woff
rename to browser/base/content/fonts/ClearSans-Regular.woff
rename from browser/base/content/aboutaccounts/fonts/firasans-light.woff
rename to browser/base/content/fonts/FiraSans-Light.woff
rename from browser/base/content/aboutaccounts/fonts/firasans-regular.woff
rename to browser/base/content/fonts/FiraSans-Regular.woff
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -51,19 +51,16 @@ browser.jar:
         content/browser/abouthealthreport/abouthealth.css     (content/abouthealthreport/abouthealth.css)
 #endif
         content/browser/aboutaccounts/aboutaccounts.xhtml                     (content/aboutaccounts/aboutaccounts.xhtml)
         content/browser/aboutaccounts/aboutaccounts.js                        (content/aboutaccounts/aboutaccounts.js)
         content/browser/aboutaccounts/aboutaccounts.css                       (content/aboutaccounts/aboutaccounts.css)
         content/browser/aboutaccounts/main.css                                (content/aboutaccounts/main.css)
         content/browser/aboutaccounts/normalize.css                           (content/aboutaccounts/normalize.css)
         content/browser/aboutaccounts/fonts.css                               (content/aboutaccounts/fonts.css)
-        content/browser/aboutaccounts/fonts/clearsans-regular.woff            (content/aboutaccounts/fonts/clearsans-regular.woff)
-        content/browser/aboutaccounts/fonts/firasans-light.woff               (content/aboutaccounts/fonts/firasans-light.woff)
-        content/browser/aboutaccounts/fonts/firasans-regular.woff             (content/aboutaccounts/fonts/firasans-regular.woff)
         content/browser/aboutaccounts/images/fox.png                          (content/aboutaccounts/images/fox.png)
         content/browser/aboutaccounts/images/graphic_sync_intro.png           (content/aboutaccounts/images/graphic_sync_intro.png)
         content/browser/aboutaccounts/images/graphic_sync_intro@2x.png        (content/aboutaccounts/images/graphic_sync_intro@2x.png)
 
         content/browser/certerror/aboutCertError.xhtml     (content/aboutcerterror/aboutCertError.xhtml)
         content/browser/certerror/aboutCertError.css       (content/aboutcerterror/aboutCertError.css)
 
         content/browser/aboutRobots-icon.png          (content/aboutRobots-icon.png)
@@ -72,16 +69,19 @@ browser.jar:
         content/browser/aboutTabCrashed.js            (content/aboutTabCrashed.js)
         content/browser/aboutTabCrashed.xhtml         (content/aboutTabCrashed.xhtml)
 *       content/browser/browser.css                   (content/browser.css)
 *       content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xul                   (content/browser.xul)
 *       content/browser/browser-tabPreviews.xml       (content/browser-tabPreviews.xml)
 *       content/browser/chatWindow.xul                (content/chatWindow.xul)
         content/browser/content.js                    (content/content.js)
+        content/browser/fonts/ClearSans-Regular.woff  (content/fonts/ClearSans-Regular.woff)
+        content/browser/fonts/FiraSans-Regular.woff   (content/fonts/FiraSans-Regular.woff)
+        content/browser/fonts/FiraSans-Light.woff     (content/fonts/FiraSans-Light.woff)
         content/browser/newtab/newTab.xul             (content/newtab/newTab.xul)
 *       content/browser/newtab/newTab.js              (content/newtab/newTab.js)
         content/browser/newtab/newTab.css             (content/newtab/newTab.css)
         content/browser/newtab/preloaderContent.js    (content/newtab/preloaderContent.js)
 *       content/browser/pageinfo/pageInfo.xul         (content/pageinfo/pageInfo.xul)
         content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
         content/browser/pageinfo/pageInfo.css         (content/pageinfo/pageInfo.css)
         content/browser/pageinfo/pageInfo.xml         (content/pageinfo/pageInfo.xml)
--- a/browser/components/customizableui/src/CustomizableUI.jsm
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -292,21 +292,22 @@ let CustomizableUIInternal = {
 
   registerArea: function(aName, aProperties, aInternalCaller) {
     if (typeof aName != "string" || !/^[a-z0-9-_]{1,}$/i.test(aName)) {
       throw new Error("Invalid area name");
     }
 
     let areaIsKnown = gAreas.has(aName);
     let props = areaIsKnown ? gAreas.get(aName) : new Map();
-    if (areaIsKnown && aProperties["type"] &&
-        props.get("type") != aProperties["type"]) {
-      throw new Error("An area cannot change types");
-    }
+    const kImmutableProperties = new Set(["type", "legacy", "overflowable"]);
     for (let key in aProperties) {
+      if (areaIsKnown && kImmutableProperties.has(key) &&
+          props.get(key) != aProperties[key]) {
+        throw new Error("An area cannot change the property for '" + key + "'");
+      }
       //XXXgijs for special items, we need to make sure they have an appropriate ID
       // so we aren't perpetually in a non-default state:
       if (key == "defaultPlacements" && Array.isArray(aProperties[key])) {
         props.set(key, aProperties[key].map(x => this.isSpecialWidget(x) ? this.ensureSpecialWidgetId(x) : x ));
       } else {
         props.set(key, aProperties[key]);
       }
     }
@@ -3453,18 +3454,18 @@ function WidgetSingleWrapper(aWidget, aN
   this.node = aNode;
   this.provider = CustomizableUI.PROVIDER_API;
 
   const kGlobalProps = ["id", "type"];
   for (let prop of kGlobalProps) {
     this[prop] = aWidget[prop];
   }
 
-  const nodeProps = ["label", "tooltiptext"];
-  for (let prop of nodeProps) {
+  const kNodeProps = ["label", "tooltiptext"];
+  for (let prop of kNodeProps) {
     let propertyName = prop;
     // Look at the node for these, instead of the widget data, to ensure the
     // wrapper always reflects this live instance.
     this.__defineGetter__(propertyName,
                           function() aNode.getAttribute(propertyName));
   }
 
   this.__defineGetter__("disabled", function() aNode.disabled);
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -100,11 +100,11 @@ skip-if = os == "linux"
 [browser_985815_propagate_setToolbarVisibility.js]
 [browser_981305_separator_insertion.js]
 [browser_987177_destroyWidget_xul.js]
 [browser_987177_xul_wrapper_updating.js]
 [browser_987492_window_api.js]
 [browser_992747_toggle_noncustomizable_toolbar.js]
 [browser_993322_widget_notoolbar.js]
 [browser_995164_registerArea_during_customize_mode.js]
-[browser_996364_defaultCollapsed.js]
+[browser_996364_registerArea_different_properties.js]
 [browser_bootstrapped_custom_toolbar.js]
 [browser_panel_toggle.js]
--- a/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
+++ b/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
@@ -53,43 +53,62 @@ add_task(function*() {
   ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
   is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
   ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
 
   let otherWin = yield openAndLoadWindow({}, true);
   let otherTB = otherWin.document.createElementNS(kNSXUL, "toolbar");
   otherTB.id = TOOLBARID;
   otherTB.setAttribute("customizable", "true");
+  let wasInformedCorrectlyOfAreaAppearing = false;
+  let listener = {
+    onAreaNodeRegistered: function(aArea, aNode) {
+      if (aNode == otherTB) {
+        wasInformedCorrectlyOfAreaAppearing = true;
+      }
+    }
+  };
+  CustomizableUI.addListener(listener);
   otherWin.gNavToolbox.appendChild(otherTB);
+  ok(wasInformedCorrectlyOfAreaAppearing, "Should have been told area was registered.");
+  CustomizableUI.removeListener(listener);
+
   ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
 
   simulateItemDrag(syncButton, gNavToolbox.palette);
   ok(!CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved to the palette");
   ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button really is in palette.");
   ok(!otherTB.querySelector("#sync-button"), "Sync button is in palette in other window, too.");
 
   simulateItemDrag(syncButton, toolbar);
   ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
   is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
   ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
   ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
 
   let wasInformedCorrectlyOfAreaDisappearing = false;
-  let listener = {
+  let windowClosed = null;
+  listener = {
     onAreaNodeUnregistered: function(aArea, aNode, aReason) {
       if (aArea == TOOLBARID) {
         is(aNode, otherTB, "Should be informed about other toolbar");
         is(aReason, CustomizableUI.REASON_WINDOW_CLOSED, "Reason should be correct.");
         wasInformedCorrectlyOfAreaDisappearing = (aReason === CustomizableUI.REASON_WINDOW_CLOSED);
       }
-    }
+    },
+    onWindowClosed: function(aWindow) {
+      if (aWindow == otherWin) {
+        windowClosed = aWindow;
+      }
+    },
   };
   CustomizableUI.addListener(listener);
   yield promiseWindowClosed(otherWin);
 
+  is(windowClosed, otherWin, "Window should have sent onWindowClosed notification.");
   ok(wasInformedCorrectlyOfAreaDisappearing, "Should be told about window closing.");
   CustomizableUI.removeListener(listener);
   // Closing the other window should not be counted against this window's customize mode:
   is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should still be a wrapper.");
   isnot(gCustomizeMode.areas.indexOf(toolbar), -1, "Toolbar should still be a customizable area for this customize mode instance.");
 
   yield gCustomizeMode.reset();
 
rename from browser/components/customizableui/test/browser_996364_defaultCollapsed.js
rename to browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
--- a/browser/components/customizableui/test/browser_996364_defaultCollapsed.js
+++ b/browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
@@ -15,42 +15,98 @@ add_task(function() {
   }
 
   CustomizableUI.unregisterArea("area-996364", true);
 });
 
 add_task(function() {
   let exceptionThrown = false;
   try {
-    CustomizableUI.registerArea("area-996364-2", {"type": CustomizableUI.TYPE_TOOLBAR, "defaultCollapsed": "false"});
+    CustomizableUI.registerArea("area-996364-2", {type: CustomizableUI.TYPE_TOOLBAR, defaultCollapsed: "false"});
   } catch (ex) {
     exceptionThrown = true;
   }
   ok(exceptionThrown, "defaultCollapsed is not allowed as an external property");
 
   // No need to unregister the area because registration fails.
 });
 
 add_task(function() {
   let exceptionThrown;
   try {
-    CustomizableUI.registerArea("area-996364-3", {"type": CustomizableUI.TYPE_TOOLBAR});
-    CustomizableUI.registerArea("area-996364-3", {"type": CustomizableUI.TYPE_MENU_PANEL});
+    CustomizableUI.registerArea("area-996364-3", {type: CustomizableUI.TYPE_TOOLBAR});
+    CustomizableUI.registerArea("area-996364-3", {type: CustomizableUI.TYPE_MENU_PANEL});
   } catch (ex) {
     exceptionThrown = ex;
   }
   ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
 
   CustomizableUI.unregisterArea("area-996364-3", true);
 });
 
 add_task(function() {
   let exceptionThrown;
   try {
-    CustomizableUI.registerArea("area-996364-4", {"type": CustomizableUI.TYPE_MENU_PANEL});
-    CustomizableUI.registerArea("area-996364-4", {"type": CustomizableUI.TYPE_TOOLBAR});
+    CustomizableUI.registerArea("area-996364-4", {type: CustomizableUI.TYPE_MENU_PANEL});
+    CustomizableUI.registerArea("area-996364-4", {type: CustomizableUI.TYPE_TOOLBAR});
   } catch (ex) {
     exceptionThrown = ex;
   }
   ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
 
   CustomizableUI.unregisterArea("area-996364-4", true);
 });
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-1", { anchor: "PanelUI-menu-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: [] });
+    CustomizableUI.registerArea("area-996899-1", { anchor: "home-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: [] });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(!exceptionThrown, "Changing anchors shouldn't throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-1", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-2", { anchor: "PanelUI-menu-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: [] });
+    CustomizableUI.registerArea("area-996899-2", { anchor: "PanelUI-menu-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: ["feed-button"] });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(!exceptionThrown, "Changing defaultPlacements shouldn't throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-2", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-3", { legacy: true });
+    CustomizableUI.registerArea("area-996899-3", { legacy: false });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(exceptionThrown, "Changing 'legacy' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-3", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-4", { overflowable: true });
+    CustomizableUI.registerArea("area-996899-4", { overflowable: false });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(exceptionThrown, "Changing 'overflowable' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-4", true);
+});
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -673,18 +673,16 @@ let SessionStoreInternal = {
             this.restoreTabContent(tab);
           }
         }
         break;
       default:
         debug("received unknown message '" + aMessage.name + "'");
         break;
     }
-
-    this._clearRestoringWindows();
   },
 
   /**
    * Record telemetry measurements stored in an object.
    * @param telemetry
    *        {histogramID: value, ...} An object mapping histogramIDs to the
    *        value to be recorded for that ID,
    */
@@ -3395,16 +3393,25 @@ let SessionStoreInternal = {
            !!this._closedWindows[normalWindowIndex].isPopup)
       normalWindowIndex++;
     if (normalWindowIndex >= this._max_windows_undo)
       spliceTo = normalWindowIndex + 1;
 #endif
     this._closedWindows.splice(spliceTo, this._closedWindows.length);
   },
 
+  /**
+   * Clears the set of windows that are "resurrected" before writing to disk to
+   * make closing windows one after the other until shutdown work as expected.
+   *
+   * This function should only be called when we are sure that there has been
+   * a user action that indicates the browser is actively being used and all
+   * windows that have been closed before are not part of a series of closing
+   * windows.
+   */
   _clearRestoringWindows: function ssi_clearRestoringWindows() {
     for (let i = 0; i < this._closedWindows.length; i++) {
       delete this._closedWindows[i]._shouldRestore;
     }
   },
 
   /**
    * Reset state to prepare for a new session state to be restored.
--- a/browser/components/sessionstore/test/browser_819510_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_819510_perwindowpb.js
@@ -110,35 +110,37 @@ function test_3() {
             waitForTabLoad(aWindow, "http://www.example.com/", function() {
 
               let curState = JSON.parse(ss.getBrowserState());
               is(curState.windows.length, 4, "Browser has opened 4 windows");
               is(curState.windows[2].isPrivate, true, "Window 2 is private");
               is(curState.selectedWindow, 4, "Last window opened is the one selected");
 
               waitForWindowClose(normalWindow, function() {
-                // Load another tab before checking the written state so that
+                // Pin and unpin a tab before checking the written state so that
                 // the list of restoring windows gets cleared. Otherwise the
                 // window we just closed would be marked as not closed.
-                waitForTabLoad(aWindow, "http://www.example.com/", function() {
-                  forceWriteState(function(state) {
-                    is(state.windows.length, 2,
-                       "sessionstore state: 2 windows in data being written to disk");
-                    is(state.selectedWindow, 2,
-                       "Selected window is updated to match one of the saved windows");
-                    state.windows.forEach(function(win) {
-                      is(!win.isPrivate, true, "Saved window is not private");
-                    });
-                    is(state._closedWindows.length, 1,
-                       "sessionstore state: 1 closed window in data being written to disk");
-                    state._closedWindows.forEach(function(win) {
-                      is(!win.isPrivate, true, "Closed window is not private");
-                    });
-                    runNextTest();
+                let tab = aWindow.gBrowser.tabs[0];
+                aWindow.gBrowser.pinTab(tab);
+                aWindow.gBrowser.unpinTab(tab);
+
+                forceWriteState(function(state) {
+                  is(state.windows.length, 2,
+                     "sessionstore state: 2 windows in data being written to disk");
+                  is(state.selectedWindow, 2,
+                     "Selected window is updated to match one of the saved windows");
+                  state.windows.forEach(function(win) {
+                    is(!win.isPrivate, true, "Saved window is not private");
                   });
+                  is(state._closedWindows.length, 1,
+                     "sessionstore state: 1 closed window in data being written to disk");
+                  state._closedWindows.forEach(function(win) {
+                    is(!win.isPrivate, true, "Closed window is not private");
+                  });
+                  runNextTest();
                 });
               });
             });
           });
         });
       });
     });
   });
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/chrome.manifest
@@ -0,0 +1,1 @@
+content browser_dbg_addon4 .
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test.xul
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="text/javascript" src="testxul.js"/>
+  <label value="test.xul"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test2.xul
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="text/javascript" src="testxul2.js"/>
+  <label value="test2.xul"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/testxul.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+  window.foo = "bar";
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/testxul2.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+  window.foo = "bar";
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/chrome.manifest
@@ -0,0 +1,1 @@
+content browser_dbg_addon5 .
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test.xul
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="text/javascript" src="testxul.js"/>
+  <label value="test.xul"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test2.xul
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="text/javascript" src="testxul2.js"/>
+  <label value="test2.xul"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/testxul.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+  window.foo = "bar";
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/testxul2.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+  window.foo = "bar";
+});
index a654b7e011b029859b2be10071d13ecb4e9e78eb..31c5331b69dee6d15183647bb598f90195ff1c2a
GIT binary patch
literal 2918
zc$^FHW@Zs#U}E54@a?a132>Y;EtQdhA)J|kfrmkcAt^t<q`0Igu|O}YI5dQlfq7H8
zaWKPto8Zz4ZU#n{Z$PC$-3$y@Cpr2n8}hWi|E#^naw~^w_Yuw`iJ^QYTiY*n8G8vE
z^PW1Qe4A19NWHr3mDHn$xcZ)?J$?GKy6g?(pEJ=POmZyCq+2xv3|!ueFl#jC35cc6
zUDRIuD)!7W#)jTk1xahuOQhak2)-XI=6vU7qDXsSw)}*Xax>+{_;N1)SQS{&GDGy|
zvC1jJGmbicIN90L+OBTVEcul=^^DeX-{Rm+*F7X%WV0pJ@*dv!TEvmp>8IiUaHG=R
zeTJ^dLc-Z+tuiHBxvJOfkX`&%b4p86_=)n3LNlUY-hP=`>ail==+^)9cY7>zjy2G%
z^b*%=Z~2pT)31DU#rqkjoA%6oU+kB5F=eKH;Ju38-qmvjuY^W+yXo%UFuCk(iT;V}
ziFadn3uwr1H~r{cvYCBH)VbBpTQ`W+P3C^^;5t{FQeBbS|8E<+7X996^LKB9??s32
zKbv_&+E&jg6WMM5Ilj;6)xJX?ZNE+S_Ii9_9%BGXR4ImKelP%re-aY|12-_LGV_W{
z5_59&ic-?xF{L&GBc@6xoy}`D5NLUC)9RWxwS)64D~rn1MRHnSFNN)OQ?uv{{jX51
zxy3*JIHUTKwfXb@rj;Kr+V_gpeSV1avJ^qRXN5bonicAA+9*X&T*lGQ;M-Psz4Y_D
zx^-U|^)HzmEo_>sa_Os`QM{0cyr(fYbBWct8G(i$xxSvYP+#XLblltL=t*1dw-zm*
zculR(N^Qti2wExDwc)Cfbd2O=Hjd{L6(+r1$@tpJ_teT05wT%WrERZrV`aB3SvNIi
z-9e{kRT+Kf*L>$)=so-9)nmKaRRp)xY_6T~R`TXvD>nBpU%KXn-Yv?SbK3D<kR~ge
zNv78Y-O>ZDpF{*|7ks#2GUqMFkC~UlB~0aoraY48x%NL*D)8Ww-vUo%-gwPuS|a~-
zw{eBwvDOdkdu4v6H%VI@|0X>3AU|rL7vFpOq8k{B3xJpd80aOb#U;S3k&7?HO-~)<
zYH|>9d-&JpXur4ky<2L!T&1BJHy3qq%$6)s*lTo;sr#O-VAQ<B?uur2InMrl5qp>8
z4nuP9<*5<Oi5|&;Ht+eDPb`SusTaf`HL=ch$=<a`_O5xh?P*@ejq6v=-#9bv-Zf+0
z#jJ`dOTVPByj*#L|G3G{sn7qK-JcrqSSaPpLDPSeS1$Yg^VlnPRL?x#Y9$Es3@6kx
zMr8O#=(ecWHVvhuS!lj71p4OiUx}K#9Df*IuQ89B(`vA!P-Fi0cJmWEukP~}X>eN-
zFF5nTmLJoN?`*rn%h^8bm*nl6mu|BzOWmY!WXY77JqguX-G>Wj-(U6FPP<I>+76eQ
zd>2jsf_<|L**7&|%`Wdc!@V~F9mvRt6g3s4IbhH1o^Klr!f2lH?LR2gWWeL{zQ$F(
zTzaon!~Gz`OI{f>)uKMUUR(5W+Rd~3a&Dcr+FThpZ9)>edUcEUeUrE0b{%;>k2<gX
z@cGWiHvh6u`jLs3uNs~bQEIxFyO3{6*ipw6_9+7SD`#|dUTO@F%~~@h>G>DFGv}7s
zJaW1H#zph-iz#Z0miE2UoXndP{N(I9|F(UG%cd%}yZ+C&y>t4lmc+@!;i7AQe^YGO
z&$C<m>U$ac%<}pjueR>^{(3e)s-GWN+<U(b=nrN_<QOFE=}SOQ14{sqr@y{nu=9S}
zzeOl&S*O^)<=amkjZQQFoq9R$`pmQ4n_5JyEp95u{9cx6|H-i=S;&9MvGiT#20!Mc
z?NaEQlh+rxOhB+FkGpii7A-y{>jf=8rgyEJp&?swb?GrL%`(6LjW=&jai5bhd#*;R
z%-l;ZTdoA!rfzb~>DqJi>&Xk|$F>+f+3@21+V<+5v8>9KKUOR%{huSx^n-Wf?!emf
zA19an{=*u!`RLxn`+JZIzv}2_m+4!|e-#7$(h9^}P>%z>4XdRzSJ(!tt-$cP?rBH9
zCIbQ13$^|qFN><U@j2XidCvPvnU}hz@iHEP<UQ6pG5hx<9++#yop^EPnhib)jtku`
zuxYCwIhKD|#%{(5fvsU(ZYSUBcz)0Jc)4-njmhH53$OhQUDftP|HNvS<f-e9UuXP3
zA+)f$zV(^=_t);_3`p^X=4@_+vyEWx)&aU%YtXox3+QeJa60>@-!NSk$Od74pu3YZ
zit=+)^>P#QGSh%wz?a&R^Ycnl^GXzwit@{gQ;XtLlG5W7Q&RHtOceCE0=yZS<d|_a
zKO`7H0LW!n(g<RqHbz(>MHHHK=q94plE@~m22v<>CUFL$)&R%`DgYggs1JxU4YdeH
zHtj9cG$Ue-!z=@ljoZz_fK(!~LZXX+X{e<OvT5sC8Ia2w!p33dS!Cl@urZ+IU{**D
z#^*eY%!F)SJUatw)?$TZEvyFOO6AA~igPevrg>bxW@Tdl$0jGkWuVEm93UP5@Gl)6
index 2c18f6da191746c1a7c658087fbce264a410e5a6..16991f7a06aeaf2bb32a045d7c925f1d41372d9e
GIT binary patch
literal 2933
zc$~$Sc{o)2AIA@47)!QmD$M;w%D#@|+Vk8&*SHz{&?U<lV~eqjtt8pEvSfsiY(t_&
z_Fa~&C4<P;Ey<d23nBMt`8C6@ZqM(Z-#pLvnRA}!ocDRZ&iniMd=3T;Vc-Gi0T|$B
z7=R+N|Dl4X0{~M90I&fFz{b_plj!Mzb(3}?8vmOafMjPY8PR2^8hQD$0(1=Tz)Qiq
z0ige~roNCITj;{FM4?hC>~LowYeZ84V#<jl7j91yw&Np3>XbpmBeqT`=XXYh!V&G=
z9i7W7bAyo8l=5eegC287SqucMBgVuSG4!JXk{!xg9IyJSlYfT*{QZA6n?0I3GM1TF
zmnRukaj!{~J$pc1AVCeOA&D3yFB)gRfyqfMU0N0uk&O<2mhclVD~G-tqx=k0N3!vW
z)Jd}K?RaE_@&HnA<o?~+mz*Qq>6mNxaaw2naZ#;@ga@vA^&(l|?@qd_Xb&5SGPm4{
zTd+ASTi#nvq0Gc#GNVp!Y52tJg;!Y{E|H{9u`{pr7pK3rTO5;1f}T+sf0fpi)sD2v
zs#)aYH&qeJzgfKZl9@MFWd7>3W!&wis%mdRj5^`;^Q0*|4!6=Y({LxO)Q0fBhQ{0Q
z8q~&w-iLV{Tx$h)=Di<XYF6OuWhVZ7HdCc}QSX4sdIY}DKlFv)oJbO>HB$|Op^3^s
z5Pn_*eE-q(0Kf`H<wziUVx66(J#6j%laxgAuB5y!cM|T)a%!!tu}I8`L&HlfI75#e
z?$gR8JS{Mvu!ihCk9wDrx%r+?L@p<GPL=q&t2UdbGl6F+n76aktofcJpG>EyxaB}>
zn-|HVndyS^g9?{nM?aN*yIA|>HAEio!{X*13mXl1oKe=?p_rbv<@;&v@g_4e(hQ4`
z;v=<9de{0B28({pKPg|WP{U{siPu%U6TzRoWSL0B2g2fyXRXHk;a0Fr4r))M6eFuj
zyPO?L$2oONtE>Wp=ic_x`#AT!%|s^+t%UgiJn@C+h(t`bQ?VK{YUE8bud@=Ohaz!y
zpoFXIY-L_>SudaDe#0bdzR5te7-n>YwYUD)0}(^=zWJvc%Nc?y7c0ZeDi|H4Vh|=<
zp$9PS{eBsh)eXj2w#yVu{d5BwD;pA^v^0^ye7*td9bnGuzas<U*vqMC@TFb{7Yxk6
z6HoL6E5+q|0Vs4dvIHID(f)H&wIvq4Z|teC6pNR!=ulP!ES1+&pcXksA3dhVWp=Ge
zNATz<tb23HViYz4;4V=TPeQQAaR#aj9C`6>=9SWh0AKuht(@AT=Gwx^vX_L2!6$u>
z2D`3|4aiGnLj@1z{$<NBeWQ)z!I8?uSDQ!26HmV2w(V+E_>gdeyuQ{t!$b@7qEwmd
z3k>sT807yz!#xbwEfYOxb9D!e97xl&x&PcKYy+4rR5VKqmCbP%%~%OnY^&_AL-SnF
z&avW3c~-KTBtKF%vWGeR>U-Ydq26IA8DA{WoI^^vXzeE+-Q=D+Ua+h#;SC?CK&7xh
zR@nSVL#C!VXA+Eh9chX#1`X2DQAOkH<@^z*Iz!FKGD~eI%<r*{+(EKzsD*P{B0l`J
z$`{5B<$84;QiRRk%ocepUK#4HbAH;XeD93Gl{gzF5x)@h_>p;2^$3FA^T@tcy%l!G
z42qt8b3CPAu7l@b&|{ZOc9KbprY#eR)AdGjRAg_UsfAM^$>!Bx>|GDZs?Slwb11PF
zQzYT6+?W}$ggrJ!6WzD;!|LS7iGtx;Tdry&o%7=R+nY?`MeFYbFVwSDOY|=wG#q^b
zDrQP6R%TN<Xqlh=GPY0#azN;)6QqXTUb~@tLFkYL)otjvQ-C`9Wo!wz898$AhrIHR
z7IQnrbv(uLNlJHgaR`sfFGE77*2#_<OPZcIZvC8A`zjyV)ik>*ftWNxi~*UG>mq^G
z>w1Ye`$3iKA*)GIH<Cqv_U+GY)fMwTu@yKpMAAufNKF^TBhq_OC4B~J_+m}xsG6a-
z?LCUECCG_8Qwv4mew7wbp);%bSzcSt2k2M#+^sh7f3%q3y}ki8xz|#Q9j~GL3hrwj
zj7lo;c~1mcLczuI863p^GPH#9)r=7NyU3+FHQ9q?IiWrN`im6!A#L_!BhwGjecrkv
zV)A4*PF#(O<f-}^Y(qMd75g})@Q$9fW~O!zql8Fvt7{WNJ-Lmu)Feu~eO~gnmD9(k
z@5T=%>=ViySTimNn~-U{iNYn`dhmp9E6&(GI3RRVXJuB$2l#5+eTQw<ueOn2eD4K4
z=kDI7|0mxppl{&gK1(>RD)TdVyuCO;-#7;kR~Njr3zpz$2O@lLx8Ym~o_K<%fQ^T%
z4-xNSWou(^g|)SHB`63;vtZD4^#6i<>uY2`u>Av1ft<kYBie5h=%*I7<8eC`X@@4Y
z;!W_6W`zEjAngR87L)-^f1L+ErbgR>sns?<t08|>Zg&r)mg`^us5&C_Q(XU`M%!Je
z)#{)Cb+7qnx!pBOEmzJ6&{Qz=Qw4uVZ+9_K>k*g$+R}o4Dy{!2_^n+|Ehr2FcJKLb
TQ9~Jlk7+Uk6j1phZ2RnQ9pEq>
--- a/browser/devtools/debugger/test/browser_dbg_addon-modules-unpacked.js
+++ b/browser/devtools/debugger/test/browser_dbg_addon-modules-unpacked.js
@@ -3,46 +3,59 @@
 
 // Make sure the add-on actor can see loaded JS Modules from an add-on
 
 const ADDON_URL = EXAMPLE_URL + "addon5.xpi";
 
 function test() {
   Task.spawn(function () {
     let addon = yield addAddon(ADDON_URL);
+    let tab1 = yield addTab("chrome://browser_dbg_addon5/content/test.xul");
+
     let addonDebugger = yield initAddonDebugger(ADDON_URL);
 
     is(addonDebugger.title, "Debugger - Test unpacked add-on with JS Modules", "Saw the right toolbox title.");
 
     // Check the inital list of sources is correct
     let groups = yield addonDebugger.getSourceGroups();
     is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
-    is(groups.length, 1, "Should be only one group.");
+    is(groups[1].name, "chrome://global", "XUL code should be the second group");
+    is(groups.length, 2, "Should be only two groups.");
 
     let sources = groups[0].sources;
-    is(sources.length, 2, "Should be two sources");
-    ok(sources[0].url.endsWith("/browser_dbg_addon5@tests.mozilla.org/bootstrap.js"), "correct url for bootstrap code")
-    is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
-    is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code")
-    is(sources[1].label, "test.jsm", "correct label for addon code")
-
-    // Load a new module and check it appears in the list of sources
-    Cu.import("resource://browser_dbg_addon5/test2.jsm", {});
-
-    groups = yield addonDebugger.getSourceGroups();
-    is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
-    is(groups.length, 1, "Should be only one group.");
-
-    sources = groups[0].sources;
     is(sources.length, 3, "Should be three sources");
     ok(sources[0].url.endsWith("/browser_dbg_addon5@tests.mozilla.org/bootstrap.js"), "correct url for bootstrap code")
     is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
     is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code")
     is(sources[1].label, "test.jsm", "correct label for addon code")
-    is(sources[2].url, "resource://browser_dbg_addon5/test2.jsm", "correct url for addon code")
-    is(sources[2].label, "test2.jsm", "correct label for addon code")
+    is(sources[2].url, "chrome://browser_dbg_addon5/content/testxul.js", "correct url for addon tab code")
+    is(sources[2].label, "testxul.js", "correct label for addon tab code")
+
+    // Load a new module and tab and check they appear in the list of sources
+    Cu.import("resource://browser_dbg_addon5/test2.jsm", {});
+    let tab2 = yield addTab("chrome://browser_dbg_addon5/content/test2.xul");
+
+    groups = yield addonDebugger.getSourceGroups();
+    is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
+    is(groups[1].name, "chrome://global", "XUL code should be the second group");
+    is(groups.length, 2, "Should be only two groups.");
+
+    sources = groups[0].sources;
+    is(sources.length, 5, "Should be five sources");
+    ok(sources[0].url.endsWith("/browser_dbg_addon5@tests.mozilla.org/bootstrap.js"), "correct url for bootstrap code")
+    is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
+    is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code")
+    is(sources[1].label, "test.jsm", "correct label for addon code")
+    is(sources[2].url, "chrome://browser_dbg_addon5/content/testxul.js", "correct url for addon tab code")
+    is(sources[2].label, "testxul.js", "correct label for addon tab code")
+    is(sources[3].url, "resource://browser_dbg_addon5/test2.jsm", "correct url for addon code")
+    is(sources[3].label, "test2.jsm", "correct label for addon code")
+    is(sources[4].url, "chrome://browser_dbg_addon5/content/testxul2.js", "correct url for addon tab code")
+    is(sources[4].label, "testxul2.js", "correct label for addon tab code")
 
     Cu.unload("resource://browser_dbg_addon5/test2.jsm");
     yield addonDebugger.destroy();
+    yield removeTab(tab1);
+    yield removeTab(tab2);
     yield removeAddon(addon);
     finish();
   });
 }
--- a/browser/devtools/debugger/test/browser_dbg_addon-modules.js
+++ b/browser/devtools/debugger/test/browser_dbg_addon-modules.js
@@ -3,46 +3,59 @@
 
 // Make sure the add-on actor can see loaded JS Modules from an add-on
 
 const ADDON_URL = EXAMPLE_URL + "addon4.xpi";
 
 function test() {
   Task.spawn(function () {
     let addon = yield addAddon(ADDON_URL);
+    let tab1 = yield addTab("chrome://browser_dbg_addon4/content/test.xul");
+
     let addonDebugger = yield initAddonDebugger(ADDON_URL);
 
     is(addonDebugger.title, "Debugger - Test add-on with JS Modules", "Saw the right toolbox title.");
 
     // Check the inital list of sources is correct
     let groups = yield addonDebugger.getSourceGroups();
     is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
-    is(groups.length, 1, "Should be only one group.");
+    is(groups[1].name, "chrome://global", "XUL code should be the second group");
+    is(groups.length, 2, "Should be only two groups.");
 
     let sources = groups[0].sources;
-    is(sources.length, 2, "Should be two sources");
-    ok(sources[0].url.endsWith("/browser_dbg_addon4@tests.mozilla.org.xpi!/bootstrap.js"), "correct url for bootstrap code")
-    is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
-    is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code")
-    is(sources[1].label, "test.jsm", "correct label for addon code")
-
-    // Load a new module and check it appears in the list of sources
-    Cu.import("resource://browser_dbg_addon4/test2.jsm", {});
-
-    groups = yield addonDebugger.getSourceGroups();
-    is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
-    is(groups.length, 1, "Should be only one group.");
-
-    sources = groups[0].sources;
     is(sources.length, 3, "Should be three sources");
     ok(sources[0].url.endsWith("/browser_dbg_addon4@tests.mozilla.org.xpi!/bootstrap.js"), "correct url for bootstrap code")
     is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
     is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code")
     is(sources[1].label, "test.jsm", "correct label for addon code")
-    is(sources[2].url, "resource://browser_dbg_addon4/test2.jsm", "correct url for addon code")
-    is(sources[2].label, "test2.jsm", "correct label for addon code")
+    is(sources[2].url, "chrome://browser_dbg_addon4/content/testxul.js", "correct url for addon tab code")
+    is(sources[2].label, "testxul.js", "correct label for addon tab code")
+
+    // Load a new module and tab and check they appear in the list of sources
+    Cu.import("resource://browser_dbg_addon4/test2.jsm", {});
+    let tab2 = yield addTab("chrome://browser_dbg_addon4/content/test2.xul");
+
+    groups = yield addonDebugger.getSourceGroups();
+    is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
+    is(groups[1].name, "chrome://global", "XUL code should be the second group");
+    is(groups.length, 2, "Should be only two groups.");
+
+    sources = groups[0].sources;
+    is(sources.length, 5, "Should be five sources");
+    ok(sources[0].url.endsWith("/browser_dbg_addon4@tests.mozilla.org.xpi!/bootstrap.js"), "correct url for bootstrap code")
+    is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
+    is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code")
+    is(sources[1].label, "test.jsm", "correct label for addon code")
+    is(sources[2].url, "chrome://browser_dbg_addon4/content/testxul.js", "correct url for addon tab code")
+    is(sources[2].label, "testxul.js", "correct label for addon tab code")
+    is(sources[3].url, "resource://browser_dbg_addon4/test2.jsm", "correct url for addon code")
+    is(sources[3].label, "test2.jsm", "correct label for addon code")
+    is(sources[4].url, "chrome://browser_dbg_addon4/content/testxul2.js", "correct url for addon tab code")
+    is(sources[4].label, "testxul2.js", "correct label for addon tab code")
 
     Cu.unload("resource://browser_dbg_addon4/test2.jsm");
     yield addonDebugger.destroy();
+    yield removeTab(tab1);
+    yield removeTab(tab2);
     yield removeAddon(addon);
     finish();
   });
 }
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -113,17 +113,21 @@ function addAddon(aUrl) {
 
   let deferred = promise.defer();
 
   AddonManager.getInstallForURL(aUrl, aInstaller => {
     aInstaller.install();
     let listener = {
       onInstallEnded: function(aAddon, aAddonInstall) {
         aInstaller.removeListener(listener);
-        deferred.resolve(aAddonInstall);
+
+        // Wait for add-on's startup scripts to execute. See bug 997408
+        executeSoon(function() {
+          deferred.resolve(aAddonInstall);
+        });
       }
     };
     aInstaller.addListener(listener);
   }, "application/x-xpinstall");
 
   return deferred.promise;
 }
 
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -608,16 +608,17 @@ toolbarbutton[sdk-button="true"][cui-are
   width: 32px;
 }
 
 #nav-bar #PanelUI-menu-button {
   -moz-padding-start: 7px;
   -moz-padding-end: 5px;
 }
 
+:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-badge-container > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-icon {
   background-color: hsla(0,0%,100%,.3);
   background-image: linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.2));
   border: 1px solid rgb(154,154,154);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
@@ -626,33 +627,34 @@ toolbarbutton[sdk-button="true"][cui-are
 }
 
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
   margin-top: 4px;
   margin-bottom: 4px;
 }
 
-:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):hover:active > .toolbarbutton-icon,
+:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open="true"]) > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon {
   background-color: rgba(154,154,154,.5);
   background-image: linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.4));
   border: 1px solid rgb(154,154,154);
   box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
               0 0 1px hsla(0,0%,0%,.3) inset;
   transition-duration: 10ms;
 }
 
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
   background-color: rgba(90%,90%,90%,.4);
   transition: background-color 150ms;
 }
 
+:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button[open],
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:hover:active,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:hover:active {
   padding: 3px;
 }
 
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before {
   content: "";
   display: -moz-box;
deleted file mode 100644
--- a/browser/themes/linux/devtools/ruleview.css
+++ /dev/null
@@ -1,150 +0,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/. */
-
-.ruleview {
-  height: 100%;
-}
-
-.ruleview-rule-source {
-  -moz-padding-start: 5px;
-  cursor: pointer;
-  text-align: right;
-  float: right;
-  -moz-user-select: none;
-}
-
-.ruleview-header {
-  border-top-width: 1px;
-  border-bottom-width: 1px;
-  border-top-style: solid;
-  border-bottom-style: solid;
-  padding: 1px 4px;
-  margin-top: 4px;
-  -moz-user-select: none;
-  word-wrap: break-word;
-}
-
-.ruleview-rule-source:hover {
-  text-decoration: underline;
-}
-
-.ruleview-rule,
-#noResults {
-  padding: 2px 4px;
-}
-
-#noResults {
-  font: message-box;
-  color: GrayText;
-}
-
-.ruleview-rule + .ruleview-rule {
-  border-top-width: 1px;
-  border-top-style: dotted;
-}
-
-.ruleview-warning {
-  background: url("chrome://browser/skin/devtools/alerticon-warning.png");
-  -moz-margin-start: 5px;
-  display: inline-block;
-  vertical-align: top;
-  width: 13px;
-  height: 12px;
-}
-
-.ruleview-ruleopen {
-  -moz-padding-end: 5px;
-}
-
-.ruleview-ruleclose {
-  cursor: text;
-  padding-right: 20px;
-}
-
-.ruleview-propertylist {
-  list-style: none;
-  padding: 0;
-  margin: 0;
-}
-
-.ruleview-rule:not(:hover) .ruleview-enableproperty {
-  visibility: hidden;
-}
-
-.ruleview-expander {
-  display: inline-block;
-}
-
-.ruleview-newproperty {
-  /* (enable checkbox width: 12px) + (expander width: 15px) */
-  -moz-margin-start: 27px;
-}
-
-.ruleview-namecontainer,
-.ruleview-propertycontainer,
-.ruleview-propertyname,
-.ruleview-propertyvalue {
-  text-decoration: inherit;
-}
-
-.ruleview-computedlist {
-  list-style: none;
-  padding: 0;
-}
-
-.ruleview-computed {
-  -moz-margin-start: 35px;
-}
-
-.ruleview-colorswatch {
-  border-radius: 50%;
-  width: 1em;
-  height: 1em;
-  vertical-align: text-top;
-  -moz-margin-end: 5px;
-}
-
-.ruleview-overridden {
-  text-decoration: line-through;
-}
-
-.theme-light .ruleview-overridden {
-  -moz-text-decoration-color: #667380; /*  Content (Text) - Dark Grey */
-}
-
-.styleinspector-propertyeditor {
-  border: 1px solid #CCC;
-  padding: 0;
-}
-
-.ruleview-property {
-  border-left: 2px solid transparent;
-  clear: right;
-}
-
-.ruleview-property  > * {
-  vertical-align: middle;
-}
-
-.ruleview-property[dirty] {
-  border-left-color: #68E268;
-}
-
-.ruleview-namecontainer > .ruleview-propertyname,
-.ruleview-propertycontainer > .ruleview-propertyvalue {
-  border-bottom: 1px dashed transparent;
-}
-
-.ruleview-namecontainer:hover > .ruleview-propertyname,
-.ruleview-propertycontainer:hover > .ruleview-propertyvalue {
-  border-bottom-color: hsl(0,0%,50%);
-}
-
-.ruleview-selector {
-  word-wrap: break-word;
-}
-
-.ruleview-selector-separator, .ruleview-selector-unmatched {
-  color: #888;
-}
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -100,17 +100,16 @@ browser.jar:
   skin/classic/browser/feeds/feedIcon.png             (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png           (feeds/feedIcon16.png)
   skin/classic/browser/feeds/videoFeedIcon.png        (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png      (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png        (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png      (feeds/feedIcon16.png)
   skin/classic/browser/feeds/subscribe.css            (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css         (feeds/subscribe-ui.css)
-  skin/classic/browser/fonts/ClearSans-Regular.ttf    (../shared/ClearSans-Regular.ttf)
   skin/classic/browser/newtab/newTab.css              (newtab/newTab.css)
   skin/classic/browser/newtab/controls.png            (../shared/newtab/controls.png)
   skin/classic/browser/places/bookmarksMenu.png       (places/bookmarksMenu.png)
   skin/classic/browser/places/bookmarksToolbar.png    (places/bookmarksToolbar.png)
   skin/classic/browser/places/bookmarksToolbar-menuPanel.png (places/bookmarksToolbar-menuPanel.png)
   skin/classic/browser/places/bookmarks-notification-finish.png  (places/bookmarks-notification-finish.png)
   skin/classic/browser/places/bookmarks-menu-arrow.png           (places/bookmarks-menu-arrow.png)
   skin/classic/browser/places/calendar.png            (places/calendar.png)
@@ -196,17 +195,17 @@ browser.jar:
   skin/classic/browser/devtools/command-scratchpad@2x.png     (../shared/devtools/images/command-scratchpad@2x.png)
   skin/classic/browser/devtools/command-tilt.png              (../shared/devtools/images/command-tilt.png)
   skin/classic/browser/devtools/command-tilt@2x.png           (../shared/devtools/images/command-tilt@2x.png)
   skin/classic/browser/devtools/command-pick.png              (../shared/devtools/images/command-pick.png)
   skin/classic/browser/devtools/command-pick@2x.png           (../shared/devtools/images/command-pick@2x.png)
   skin/classic/browser/devtools/command-console.png           (../shared/devtools/images/command-console.png)
   skin/classic/browser/devtools/command-console@2x.png        (../shared/devtools/images/command-console@2x.png)
   skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
-  skin/classic/browser/devtools/ruleview.css          (devtools/ruleview.css)
+* skin/classic/browser/devtools/ruleview.css          (../shared/devtools/ruleview.css)
 * skin/classic/browser/devtools/webconsole.css                  (devtools/webconsole.css)
   skin/classic/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.png                  (devtools/webconsole.png)
   skin/classic/browser/devtools/commandline.css              (devtools/commandline.css)
   skin/classic/browser/devtools/markup-view.css       (../shared/devtools/markup-view.css)
   skin/classic/browser/devtools/editor-error.png       (devtools/editor-error.png)
   skin/classic/browser/devtools/editor-breakpoint.png  (devtools/editor-breakpoint.png)
   skin/classic/browser/devtools/editor-debug-location.png (devtools/editor-debug-location.png)
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -507,31 +507,33 @@ toolbar .toolbarbutton-1 > .toolbarbutto
   transition-duration: 250ms;
 }
 
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],#back-button,#forward-button)) {
   padding: 0 4px;
 }
 
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],[open],#back-button,#forward-button)):hover,
+toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker,
 toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button,
 toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker,
 toolbar .toolbaritem-combined-buttons:hover > .toolbarbutton-combined {
   border-color: hsla(0,0%,0%,.2);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.5),
               0 1px 0 hsla(0,0%,100%,.5) inset;
 }
 
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],[open],#back-button,#forward-button)):hover,
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open]))[buttonover] > .toolbarbutton-menubutton-button,
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open],[buttonover])):hover > .toolbarbutton-menubutton-dropmarker {
   background: hsla(0,0%,100%,.1) linear-gradient(hsla(0,0%,100%,.3), hsla(0,0%,100%,.1)) padding-box;
 }
 
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],#back-button,#forward-button)):-moz-any(:hover:active,[open],[checked]),
+toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]) > .toolbarbutton-menubutton-button[open],
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open]))[buttonover]:active > .toolbarbutton-menubutton-button,
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open],[buttonover])):hover:active > .toolbarbutton-menubutton-dropmarker,
 toolbar .toolbarbutton-1[type="menu-button"][open]:not([disabled]) > .toolbarbutton-menubutton-dropmarker {
   background: hsla(0,0%,0%,.02) linear-gradient(hsla(0,0%,0%,.12), hsla(0,0%,0%,0)) border-box;
   border-color: hsla(0,0%,0%,.3);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.5),
               0 1px 0 hsla(0,0%,0%,.05) inset,
               0 1px 1px hsla(0,0%,0%,.2) inset;
deleted file mode 100644
--- a/browser/themes/osx/devtools/ruleview.css
+++ /dev/null
@@ -1,154 +0,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/. */
-
-.ruleview {
-  height: 100%;
-}
-
-.ruleview-rule-source {
-  -moz-padding-start: 5px;
-  cursor: pointer;
-  text-align: right;
-  float: right;
-  -moz-user-select: none;
-}
-
-.ruleview-header {
-  border-top-width: 1px;
-  border-bottom-width: 1px;
-  border-top-style: solid;
-  border-bottom-style: solid;
-  padding: 1px 4px;
-  -moz-user-select: none;
-  word-wrap: break-word;
-}
-
-.ruleview-rule-pseudo-element {
-  padding-left:20px;
-  border-left: solid 10px;
-}
-
-.ruleview-rule-source:hover {
-  text-decoration: underline;
-}
-
-.ruleview-rule,
-#noResults {
-  padding: 2px 4px;
-}
-
-#noResults {
-  font: message-box;
-  color: GrayText;
-}
-
-.ruleview-rule + .ruleview-rule {
-  border-top-width: 1px;
-  border-top-style: dotted;
-}
-
-.ruleview-warning {
-  background: url("chrome://browser/skin/devtools/alerticon-warning.png");
-  -moz-margin-start: 5px;
-  display: inline-block;
-  vertical-align: top;
-  width: 13px;
-  height: 12px;
-}
-
-.ruleview-ruleopen {
-  -moz-padding-end: 5px;
-}
-
-.ruleview-ruleclose {
-  cursor: text;
-  padding-right: 20px;
-}
-
-.ruleview-propertylist {
-  list-style: none;
-  padding: 0;
-  margin: 0;
-}
-
-.ruleview-rule:not(:hover) .ruleview-enableproperty {
-  visibility: hidden;
-}
-
-.ruleview-expander {
-  display: inline-block;
-}
-
-.ruleview-newproperty {
-  /* (enable checkbox width: 12px) + (expander width: 15px) */
-  -moz-margin-start: 27px;
-}
-
-.ruleview-namecontainer,
-.ruleview-propertycontainer,
-.ruleview-propertyname,
-.ruleview-propertyvalue {
-  text-decoration: inherit;
-}
-
-.ruleview-computedlist {
-  list-style: none;
-  padding: 0;
-}
-
-.ruleview-computed {
-  -moz-margin-start: 35px;
-}
-
-.ruleview-colorswatch {
-  border-radius: 50%;
-  width: 1em;
-  height: 1em;
-  vertical-align: text-top;
-  -moz-margin-end: 5px;
-}
-
-.ruleview-overridden {
-  text-decoration: line-through;
-}
-
-.theme-light .ruleview-overridden {
-  -moz-text-decoration-color: #667380; /*  Content (Text) - Dark Grey */
-}
-
-.styleinspector-propertyeditor {
-  border: 1px solid #CCC;
-  padding: 0;
-}
-
-.ruleview-property {
-  border-left: 2px solid transparent;
-  clear: right;
-}
-
-.ruleview-property  > * {
-  vertical-align: middle;
-}
-
-.ruleview-property[dirty] {
-  border-left-color: #68E268;
-}
-
-.ruleview-namecontainer > .ruleview-propertyname,
-.ruleview-propertycontainer > .ruleview-propertyvalue {
-  border-bottom: 1px dashed transparent;
-}
-
-.ruleview-namecontainer:hover > .ruleview-propertyname,
-.ruleview-propertycontainer:hover > .ruleview-propertyvalue {
-  border-bottom-color: hsl(0,0%,50%);
-}
-
-.ruleview-selector {
-  word-wrap: break-word;
-}
-
-.ruleview-selector-separator, .ruleview-selector-unmatched {
-  color: #888;
-}
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -164,17 +164,16 @@ browser.jar:
   skin/classic/browser/feeds/subscribe.css                  (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css               (feeds/subscribe-ui.css)
   skin/classic/browser/feeds/feedIcon.png                   (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png                 (feeds/feedIcon16.png)
   skin/classic/browser/feeds/videoFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png            (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png            (feeds/feedIcon16.png)
-  skin/classic/browser/fonts/ClearSans-Regular.ttf          (../shared/ClearSans-Regular.ttf)
   skin/classic/browser/newtab/newTab.css                    (newtab/newTab.css)
   skin/classic/browser/newtab/controls.png                  (../shared/newtab/controls.png)
   skin/classic/browser/newtab/controls@2x.png               (newtab/controls@2x.png)
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
   skin/classic/browser/places/allBookmarks.png              (places/allBookmarks.png)
 * skin/classic/browser/places/places.css                    (places/places.css)
@@ -317,17 +316,17 @@ browser.jar:
   skin/classic/browser/devtools/command-scratchpad@2x.png     (../shared/devtools/images/command-scratchpad@2x.png)
   skin/classic/browser/devtools/command-tilt.png              (../shared/devtools/images/command-tilt.png)
   skin/classic/browser/devtools/command-tilt@2x.png           (../shared/devtools/images/command-tilt@2x.png)
   skin/classic/browser/devtools/command-pick.png              (../shared/devtools/images/command-pick.png)
   skin/classic/browser/devtools/command-pick@2x.png           (../shared/devtools/images/command-pick@2x.png)
   skin/classic/browser/devtools/command-console.png           (../shared/devtools/images/command-console.png)
   skin/classic/browser/devtools/command-console@2x.png        (../shared/devtools/images/command-console@2x.png)
   skin/classic/browser/devtools/alerticon-warning.png       (devtools/alerticon-warning.png)
-  skin/classic/browser/devtools/ruleview.css                (devtools/ruleview.css)
+* skin/classic/browser/devtools/ruleview.css                (../shared/devtools/ruleview.css)
   skin/classic/browser/devtools/commandline.css             (devtools/commandline.css)
   skin/classic/browser/devtools/markup-view.css             (../shared/devtools/markup-view.css)
   skin/classic/browser/devtools/editor-error.png             (devtools/editor-error.png)
   skin/classic/browser/devtools/editor-breakpoint.png        (devtools/editor-breakpoint.png)
   skin/classic/browser/devtools/editor-debug-location.png    (devtools/editor-debug-location.png)
 * skin/classic/browser/devtools/webconsole.css                  (devtools/webconsole.css)
   skin/classic/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.png                  (devtools/webconsole.png)
deleted file mode 100644
index fe686f8d2a1343973005977cf21b00b8a388d56a..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/devtools/ruleview.css
@@ -0,0 +1,161 @@
+/* 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/. */
+
+.ruleview {
+  height: 100%;
+}
+
+.ruleview-rule-source {
+  -moz-padding-start: 5px;
+  cursor: pointer;
+  text-align: right;
+  float: right;
+  -moz-user-select: none;
+}
+
+.ruleview-header {
+  border-top-width: 1px;
+  border-bottom-width: 1px;
+  border-top-style: solid;
+  border-bottom-style: solid;
+  padding: 1px 4px;
+  -moz-user-select: none;
+  word-wrap: break-word;
+%ifndef XP_MACOSX
+  margin-top: 4px;
+%endif
+}
+
+.ruleview-rule-pseudo-element {
+  padding-left:20px;
+  border-left: solid 10px;
+}
+
+.ruleview-rule-source:hover {
+  text-decoration: underline;
+}
+
+.ruleview-rule,
+#noResults {
+  padding: 2px 4px;
+}
+
+#noResults {
+  font: message-box;
+  color: GrayText;
+}
+
+.ruleview-rule + .ruleview-rule {
+  border-top-width: 1px;
+  border-top-style: dotted;
+}
+
+.ruleview-warning {
+  background: url("chrome://browser/skin/devtools/alerticon-warning.png");
+  -moz-margin-start: 5px;
+  display: inline-block;
+  vertical-align: top;
+  width: 13px;
+  height: 12px;
+}
+
+.ruleview-ruleopen {
+  -moz-padding-end: 5px;
+}
+
+.ruleview-ruleclose {
+  cursor: text;
+  padding-right: 20px;
+}
+
+.ruleview-propertylist {
+  list-style: none;
+  padding: 0;
+  margin: 0;
+}
+
+.ruleview-rule:not(:hover) .ruleview-enableproperty {
+  visibility: hidden;
+}
+
+.ruleview-expander {
+  display: inline-block;
+}
+
+.ruleview-newproperty {
+  /* (enable checkbox width: 12px) + (expander width: 15px) */
+  -moz-margin-start: 27px;
+}
+
+.ruleview-namecontainer,
+.ruleview-propertycontainer,
+.ruleview-propertyname,
+.ruleview-propertyvalue {
+  text-decoration: inherit;
+}
+
+.ruleview-computedlist {
+  list-style: none;
+  padding: 0;
+}
+
+.ruleview-computed {
+  -moz-margin-start: 35px;
+}
+
+.ruleview-colorswatch {
+  border-radius: 50%;
+  width: 1em;
+  height: 1em;
+  vertical-align: text-top;
+  -moz-margin-end: 5px;
+}
+
+.ruleview-overridden {
+  text-decoration: line-through;
+}
+
+.theme-light .ruleview-overridden {
+  -moz-text-decoration-color: #667380; /*  Content (Text) - Dark Grey */
+}
+
+.styleinspector-propertyeditor {
+  border: 1px solid #CCC;
+  padding: 0;
+}
+
+.ruleview-property {
+  border-left: 3px solid transparent;
+  clear: right;
+}
+
+.ruleview-property  > * {
+  vertical-align: middle;
+}
+
+.theme-dark .ruleview-property[dirty] {
+  border-left-color: #70bf53; /* Green */
+}
+
+.theme-light .ruleview-property[dirty] {
+  border-left-color: #2cbb0f; /* Green */
+}
+
+.ruleview-namecontainer > .ruleview-propertyname,
+.ruleview-propertycontainer > .ruleview-propertyvalue {
+  border-bottom: 1px dashed transparent;
+}
+
+.ruleview-namecontainer:hover > .ruleview-propertyname,
+.ruleview-propertycontainer:hover > .ruleview-propertyvalue {
+  border-bottom-color: hsl(0,0%,50%);
+}
+
+.ruleview-selector {
+  word-wrap: break-word;
+}
+
+.ruleview-selector-separator, .ruleview-selector-unmatched {
+  color: #888;
+}
--- a/browser/themes/shared/incontentprefs/preferences.css
+++ b/browser/themes/shared/incontentprefs/preferences.css
@@ -2,17 +2,17 @@
 /* - 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
 @namespace html "http://www.w3.org/1999/xhtml";
 
 @font-face {
   font-family: "Clear Sans";
-  src: url("chrome://browser/skin/fonts/ClearSans-Regular.ttf");
+  src: url("chrome://browser/content/fonts/ClearSans-Regular.woff") format('woff');
 }
 
 page {
   -moz-appearance: none;
   background-image: linear-gradient(#FFFFFF, #EDEDED 100px);
 }
 
 caption {
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -725,16 +725,17 @@ toolbarbutton[sdk-button="true"][cui-are
   background-repeat: no-repeat;
   background-size: 1px 16px;
 }
 
 @conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
   border-color: hsla(210,4%,10%,.1);
 }
 
+#nav-bar .toolbarbutton-1:not([disabled=true]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container,
 @conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled]):hover > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
   background-color: hsla(210,4%,10%,.08);
@@ -794,17 +795,17 @@ toolbarbutton[sdk-button="true"][cui-are
     background-color: hsla(210,48%,96%,.75);
     box-shadow: 0 0 1px hsla(210,54%,20%,.03),
                 0 0 2px hsla(210,54%,20%,.1);
   }
 %ifdef WINDOWS_AERO
 }
 %endif
 
-#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):hover:active > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open]) > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
   background-color: hsla(210,4%,10%,.12);
   border-top-color: hsla(210,4%,10%,.2);
   box-shadow: 0 1px 0 0 hsla(210,4%,10%,.1) inset;
   transition-duration: 10ms;
deleted file mode 100644
--- a/browser/themes/windows/devtools/ruleview.css
+++ /dev/null
@@ -1,150 +0,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/. */
-
-.ruleview {
-  height: 100%;
-}
-
-.ruleview-rule-source {
-  -moz-padding-start: 5px;
-  cursor: pointer;
-  text-align: right;
-  float: right;
-  -moz-user-select: none;
-}
-
-.ruleview-header {
-  border-top-width: 1px;
-  border-bottom-width: 1px;
-  border-top-style: solid;
-  border-bottom-style: solid;
-  padding: 1px 4px;
-  margin-top: 4px;
-  -moz-user-select: none;
-  word-wrap: break-word;
-}
-
-.ruleview-rule-source:hover {
-  text-decoration: underline;
-}
-
-.ruleview-rule,
-#noResults {
-  padding: 2px 4px;
-}
-
-#noResults {
-  font: message-box;
-  color: GrayText;
-}
-
-.ruleview-rule + .ruleview-rule {
-  border-top-width: 1px;
-  border-top-style: dotted;
-}
-
-.ruleview-warning {
-  background: url("chrome://browser/skin/devtools/alerticon-warning.png");
-  -moz-margin-start: 5px;
-  display: inline-block;
-  vertical-align: top;
-  width: 13px;
-  height: 12px;
-}
-
-.ruleview-ruleopen {
-  -moz-padding-end: 5px;
-}
-
-.ruleview-ruleclose {
-  cursor: text;
-  padding-right: 20px;
-}
-
-.ruleview-propertylist {
-  list-style: none;
-  padding: 0;
-  margin: 0;
-}
-
-.ruleview-rule:not(:hover) .ruleview-enableproperty {
-  visibility: hidden;
-}
-
-.ruleview-expander {
-  display: inline-block;
-}
-
-.ruleview-newproperty {
-  /* (enable checkbox width: 12px) + (expander width: 15px) */
-  -moz-margin-start: 27px;
-}
-
-.ruleview-namecontainer,
-.ruleview-propertycontainer,
-.ruleview-propertyname,
-.ruleview-propertyvalue {
-  text-decoration: inherit;
-}
-
-.ruleview-computedlist {
-  list-style: none;
-  padding: 0;
-}
-
-.ruleview-computed {
-  -moz-margin-start: 35px;
-}
-
-.ruleview-colorswatch {
-  border-radius: 50%;
-  width: 1em;
-  height: 1em;
-  vertical-align: text-top;
-  -moz-margin-end: 5px;
-}
-
-.ruleview-overridden {
-  text-decoration: line-through;
-}
-
-.theme-light .ruleview-overridden {
-  -moz-text-decoration-color: #667380; /*  Content (Text) - Dark Grey */
-}
-
-.styleinspector-propertyeditor {
-  border: 1px solid #CCC;
-  padding: 0;
-}
-
-.ruleview-property {
-  border-left: 2px solid transparent;
-  clear: right;
-}
-
-.ruleview-property  > * {
-  vertical-align: middle;
-}
-
-.ruleview-property[dirty] {
-  border-left-color: #68E268;
-}
-
-.ruleview-namecontainer > .ruleview-propertyname,
-.ruleview-propertycontainer > .ruleview-propertyvalue {
-  border-bottom: 1px dashed transparent;
-}
-
-.ruleview-namecontainer:hover > .ruleview-propertyname,
-.ruleview-propertycontainer:hover > .ruleview-propertyvalue {
-  border-bottom-color: hsl(0,0%,50%);
-}
-
-.ruleview-selector {
-  word-wrap: break-word;
-}
-
-.ruleview-selector-separator, .ruleview-selector-unmatched {
-  color: #888;
-}
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -121,17 +121,16 @@ browser.jar:
         skin/classic/browser/feeds/feedIcon.png                      (feeds/feedIcon.png)
         skin/classic/browser/feeds/feedIcon16.png                    (feeds/feedIcon16.png)
         skin/classic/browser/feeds/audioFeedIcon.png                 (feeds/feedIcon.png)
         skin/classic/browser/feeds/audioFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/videoFeedIcon.png                 (feeds/feedIcon.png)
         skin/classic/browser/feeds/videoFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/subscribe.css                     (feeds/subscribe.css)
         skin/classic/browser/feeds/subscribe-ui.css                  (feeds/subscribe-ui.css)
-        skin/classic/browser/fonts/ClearSans-Regular.ttf             (../shared/ClearSans-Regular.ttf)
         skin/classic/browser/newtab/newTab.css                       (newtab/newTab.css)
         skin/classic/browser/newtab/controls.png                     (../shared/newtab/controls.png)
         skin/classic/browser/places/places.css                       (places/places.css)
 *       skin/classic/browser/places/organizer.css                    (places/organizer.css)
         skin/classic/browser/places/bookmark.png                     (places/bookmark.png)
         skin/classic/browser/places/query.png                        (places/query.png)
         skin/classic/browser/places/bookmarksMenu.png                (places/bookmarksMenu.png)
         skin/classic/browser/places/bookmarksToolbar.png             (places/bookmarksToolbar.png)
@@ -221,17 +220,17 @@ browser.jar:
 *       skin/classic/browser/devtools/dark-theme.css                (../shared/devtools/dark-theme.css)
 *       skin/classic/browser/devtools/light-theme.css               (../shared/devtools/light-theme.css)
         skin/classic/browser/devtools/filters.svg                   (../shared/devtools/filters.svg)
         skin/classic/browser/devtools/controls.png                  (../shared/devtools/images/controls.png)
         skin/classic/browser/devtools/controls@2x.png               (../shared/devtools/images/controls@2x.png)
 *       skin/classic/browser/devtools/widgets.css                   (devtools/widgets.css)
         skin/classic/browser/devtools/commandline-icon.png          (devtools/commandline-icon.png)
         skin/classic/browser/devtools/alerticon-warning.png         (devtools/alerticon-warning.png)
-        skin/classic/browser/devtools/ruleview.css                  (devtools/ruleview.css)
+*       skin/classic/browser/devtools/ruleview.css                  (../shared/devtools/ruleview.css)
         skin/classic/browser/devtools/commandline.css               (devtools/commandline.css)
         skin/classic/browser/devtools/command-paintflashing.png     (../shared/devtools/images/command-paintflashing.png)
         skin/classic/browser/devtools/command-paintflashing@2x.png  (../shared/devtools/images/command-paintflashing@2x.png)
         skin/classic/browser/devtools/command-responsivemode.png    (../shared/devtools/images/command-responsivemode.png)
         skin/classic/browser/devtools/command-responsivemode@2x.png (../shared/devtools/images/command-responsivemode@2x.png)
         skin/classic/browser/devtools/command-scratchpad.png        (../shared/devtools/images/command-scratchpad.png)
         skin/classic/browser/devtools/command-scratchpad@2x.png     (../shared/devtools/images/command-scratchpad@2x.png)
         skin/classic/browser/devtools/command-tilt.png              (../shared/devtools/images/command-tilt.png)
@@ -486,17 +485,16 @@ browser.jar:
         skin/classic/aero/browser/feeds/feedIcon.png                 (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/feedIcon16.png               (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon.png            (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon.png            (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/subscribe.css                (feeds/subscribe.css)
         skin/classic/aero/browser/feeds/subscribe-ui.css             (feeds/subscribe-ui.css)
-        skin/classic/aero/browser/fonts/ClearSans-Regular.ttf        (../shared/ClearSans-Regular.ttf)
         skin/classic/aero/browser/newtab/newTab.css                  (newtab/newTab.css)
         skin/classic/aero/browser/newtab/controls.png                (../shared/newtab/controls.png)
 *       skin/classic/aero/browser/places/places.css                  (places/places-aero.css)
 *       skin/classic/aero/browser/places/organizer.css               (places/organizer-aero.css)
         skin/classic/aero/browser/places/bookmark.png                (places/bookmark-aero.png)
         skin/classic/aero/browser/places/query.png                   (places/query-aero.png)
         skin/classic/aero/browser/places/bookmarksMenu.png           (places/bookmarksMenu-aero.png)
         skin/classic/aero/browser/places/bookmarksToolbar.png        (places/bookmarksToolbar-aero.png)
@@ -597,17 +595,17 @@ browser.jar:
         skin/classic/aero/browser/devtools/command-scratchpad@2x.png (../shared/devtools/images/command-scratchpad@2x.png)
         skin/classic/aero/browser/devtools/command-tilt.png          (../shared/devtools/images/command-tilt.png)
         skin/classic/aero/browser/devtools/command-tilt@2x.png       (../shared/devtools/images/command-tilt@2x.png)
         skin/classic/aero/browser/devtools/command-pick.png          (../shared/devtools/images/command-pick.png)
         skin/classic/aero/browser/devtools/command-pick@2x.png       (../shared/devtools/images/command-pick@2x.png)
         skin/classic/aero/browser/devtools/command-console.png       (../shared/devtools/images/command-console.png)
         skin/classic/aero/browser/devtools/command-console@2x.png    (../shared/devtools/images/command-console@2x.png)
         skin/classic/aero/browser/devtools/alerticon-warning.png     (devtools/alerticon-warning.png)
-        skin/classic/aero/browser/devtools/ruleview.css              (devtools/ruleview.css)
+*       skin/classic/aero/browser/devtools/ruleview.css              (../shared/devtools/ruleview.css)
         skin/classic/aero/browser/devtools/commandline.css           (devtools/commandline.css)
         skin/classic/aero/browser/devtools/markup-view.css           (../shared/devtools/markup-view.css)
         skin/classic/aero/browser/devtools/editor-error.png           (devtools/editor-error.png)
         skin/classic/aero/browser/devtools/editor-breakpoint.png      (devtools/editor-breakpoint.png)
         skin/classic/aero/browser/devtools/editor-debug-location.png  (devtools/editor-debug-location.png)
 *       skin/classic/aero/browser/devtools/webconsole.css                  (devtools/webconsole.css)
         skin/classic/aero/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
         skin/classic/aero/browser/devtools/webconsole.png                  (devtools/webconsole.png)
--- a/dom/alarm/AlarmService.jsm
+++ b/dom/alarm/AlarmService.jsm
@@ -510,16 +510,21 @@ this.AlarmService = {
       case "webapps-clear-data":
         let params =
           aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
         if (!params) {
           debug("Error! Fail to remove alarms for an uninstalled app.");
           return;
         }
 
+        // Only remove alarms for apps.
+        if (params.browserOnly) {
+          return;
+        }
+
         let manifestURL = appsService.getManifestURLByLocalId(params.appId);
         if (!manifestURL) {
           debug("Error! Fail to remove alarms for an uninstalled app.");
           return;
         }
 
         this._db.getAll(
           manifestURL,
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1174,79 +1174,79 @@ Navigator::SendBeacon(const nsAString& a
   }
   bool isForeign = true;
   thirdPartyUtil->IsThirdPartyWindow(mWindow, uri, &isForeign);
   httpChannelInternal->SetForceAllowThirdPartyCookie(!isForeign);
 
   nsCString mimeType;
   if (!aData.IsNull()) {
     nsCOMPtr<nsIInputStream> in;
-  
+
     if (aData.Value().IsString()) {
       nsCString stringData = NS_ConvertUTF16toUTF8(aData.Value().GetAsString());
       nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       rv = strStream->SetData(stringData.BeginReading(), stringData.Length());
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       mimeType.AssignLiteral("text/plain;charset=UTF-8");
       in = strStream;
-  
+
     } else if (aData.Value().IsArrayBufferView()) {
-  
+
       nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
-  
+
       rv = strStream->SetData(reinterpret_cast<char*>(aData.Value().GetAsArrayBufferView().Data()),
                               aData.Value().GetAsArrayBufferView().Length());
-  
+
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       mimeType.AssignLiteral("application/octet-stream");
       in = strStream;
-  
+
     } else if (aData.Value().IsBlob()) {
       nsCOMPtr<nsIDOMBlob> blob = aData.Value().GetAsBlob();
       rv = blob->GetInternalStream(getter_AddRefs(in));
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       nsAutoString type;
       rv = blob->GetType(type);
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       mimeType = NS_ConvertUTF16toUTF8(type);
-  
+
     } else if (aData.Value().IsFormData()) {
       nsFormData& form = aData.Value().GetAsFormData();
       uint64_t len;
       nsAutoCString charset;
       form.GetSendInfo(getter_AddRefs(in),
                        &len,
                        mimeType,
                        charset);
     } else {
       MOZ_ASSERT(false, "switch statements not in sync");
       aRv.Throw(NS_ERROR_FAILURE);
       return false;
     }
-  
+
     nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
     if (!uploadChannel) {
       aRv.Throw(NS_ERROR_FAILURE);
       return false;
     }
     uploadChannel->ExplicitSetUploadStream(in, mimeType, -1,
                                            NS_LITERAL_CSTRING("POST"),
                                            false);
@@ -1263,17 +1263,17 @@ Navigator::SendBeacon(const nsAString& a
                                                                principal,
                                                                true);
 
   // Start a preflight if cross-origin and content type is not whitelisted
   rv = secMan->CheckSameOriginURI(documentURI, uri, false);
   bool crossOrigin = NS_FAILED(rv);
   nsAutoCString contentType, parsedCharset;
   rv = NS_ParseContentType(mimeType, contentType, parsedCharset);
-  if (crossOrigin && 
+  if (crossOrigin &&
       contentType.Length() > 0 &&
       !contentType.Equals(APPLICATION_WWW_FORM_URLENCODED) &&
       !contentType.Equals(MULTIPART_FORM_DATA) &&
       !contentType.Equals(TEXT_PLAIN)) {
     nsCOMPtr<nsIChannel> preflightChannel;
     nsTArray<nsCString> unsafeHeaders;
     unsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
     rv = NS_StartCORSPreflight(channel,
@@ -1543,17 +1543,17 @@ Navigator::GetMozVoicemail(ErrorResult& 
     if (aRv.Failed()) {
       return nullptr;
     }
   }
 
   return mVoicemail;
 }
 
-nsIDOMMozIccManager*
+IccManager*
 Navigator::GetMozIccManager(ErrorResult& aRv)
 {
   if (!mIccManager) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
     NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -203,17 +203,17 @@ public:
   void MozSetMessageHandler(const nsAString& aType,
                             systemMessageCallback* aCallback,
                             ErrorResult& aRv);
   bool MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv);
 #ifdef MOZ_B2G_RIL
   MobileConnectionArray* GetMozMobileConnections(ErrorResult& aRv);
   CellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
   Voicemail* GetMozVoicemail(ErrorResult& aRv);
-  nsIDOMMozIccManager* GetMozIccManager(ErrorResult& aRv);
+  IccManager* GetMozIccManager(ErrorResult& aRv);
 #endif // MOZ_B2G_RIL
 #ifdef MOZ_GAMEPAD
   void GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
 #endif // MOZ_GAMEPAD
 #ifdef MOZ_B2G_FM
   FMRadio* GetMozFMRadio(ErrorResult& aRv);
 #endif
 #ifdef MOZ_B2G_BT
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -142,17 +142,16 @@
 #include "nsIDOMMobileMessageManager.h"
 #include "nsIDOMMozSmsMessage.h"
 #include "nsIDOMMozMmsMessage.h"
 #include "nsIDOMSmsFilter.h"
 #include "nsIDOMSmsSegmentInfo.h"
 #include "nsIDOMMozMobileMessageThread.h"
 
 #ifdef MOZ_B2G_RIL
-#include "nsIDOMIccManager.h"
 #include "nsIDOMMobileConnection.h"
 #endif // MOZ_B2G_RIL
 
 #ifdef MOZ_B2G_FM
 #include "FMRadio.h"
 #endif
 
 #include "nsIDOMGlobalObjectConstructor.h"
@@ -439,21 +438,16 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframeRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframesRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CSSPageRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-#ifdef MOZ_B2G_RIL
-  NS_DEFINE_CLASSINFO_DATA(MozIccManager, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-#endif
-
   NS_DEFINE_CLASSINFO_DATA(CSSFontFeatureValuesRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(UserDataHandler, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(XPathNamespace, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControlElement, nsDOMGenericSH,
@@ -1114,24 +1108,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframesRule, nsIDOMMozCSSKeyframesRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframesRule)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CSSPageRule, nsIDOMCSSPageRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSPageRule)
   DOM_CLASSINFO_MAP_END
 
-#ifdef MOZ_B2G_RIL
-  DOM_CLASSINFO_MAP_BEGIN(MozIccManager, nsIDOMMozIccManager)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozIccManager)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
-  DOM_CLASSINFO_MAP_END
-
-#endif
-
   DOM_CLASSINFO_MAP_BEGIN(CSSFontFeatureValuesRule, nsIDOMCSSFontFeatureValuesRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFeatureValuesRule)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(UserDataHandler, nsIDOMUserDataHandler)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMUserDataHandler)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -85,20 +85,16 @@ DOMCI_CLASS(ContentFrameMessageManager)
 DOMCI_CLASS(ChromeMessageBroadcaster)
 DOMCI_CLASS(ChromeMessageSender)
 
 DOMCI_CLASS(MozCSSKeyframeRule)
 DOMCI_CLASS(MozCSSKeyframesRule)
 
 DOMCI_CLASS(CSSPageRule)
 
-#ifdef MOZ_B2G_RIL
-DOMCI_CLASS(MozIccManager)
-#endif
-
 DOMCI_CLASS(CSSFontFeatureValuesRule)
 
 DOMCI_CLASS(UserDataHandler)
 DOMCI_CLASS(XPathNamespace)
 DOMCI_CLASS(XULControlElement)
 DOMCI_CLASS(XULLabeledControlElement)
 DOMCI_CLASS(XULButtonElement)
 DOMCI_CLASS(XULCheckboxElement)
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -790,16 +790,20 @@ DOMInterfaces = {
 'MozCellBroadcast': {
     'nativeType': 'mozilla::dom::CellBroadcast',
 },
 
 'MozIcc': {
     'nativeType': 'mozilla::dom::Icc',
 },
 
+'MozIccManager': {
+    'nativeType': 'mozilla::dom::IccManager',
+},
+
 'MozMobileConnectionArray': {
     'nativeType': 'mozilla::dom::MobileConnectionArray',
     'resultNotAddRefed': [ 'item' ]
 },
 
 'MozNamedAttrMap': {
     'nativeType': 'nsDOMAttributeMap',
 },
@@ -1880,17 +1884,16 @@ addExternalIface('imgINotificationObserv
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
 addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
 addExternalIface('MozControllers', nativeType='nsIControllers')
 addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
 addExternalIface('MozFrameRequestCallback', nativeType='nsIFrameRequestCallback',
                  notflattened=True)
 addExternalIface('MozIccInfo', headerFile='nsIDOMIccInfo.h')
-addExternalIface('MozIccManager', headerFile='nsIDOMIccManager.h')
 addExternalIface('MozMobileConnection', headerFile='nsIDOMMobileConnection.h')
 addExternalIface('MozMobileMessageManager', headerFile='nsIDOMMobileMessageManager.h')
 addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
 addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
                  notflattened=True)
 addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
 addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject',
                  notflattened=True)
--- a/dom/icc/interfaces/moz.build
+++ b/dom/icc/interfaces/moz.build
@@ -1,13 +1,12 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 XPIDL_SOURCES += [
     'nsIDOMIccInfo.idl',
-    'nsIDOMIccManager.idl',
     'nsIIccProvider.idl',
 ]
 
 XPIDL_MODULE = 'dom_icc'
--- a/dom/icc/src/IccManager.cpp
+++ b/dom/icc/src/IccManager.cpp
@@ -1,178 +1,123 @@
 /* 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/. */
 
 #include "IccManager.h"
-
+#include "mozilla/dom/MozIccManagerBinding.h"
 #include "GeneratedEvents.h"
 #include "Icc.h"
 #include "IccListener.h"
 #include "mozilla/dom/IccChangeEvent.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/Services.h"
-#include "nsIDOMClassInfo.h"
 #include "nsIDOMIccInfo.h"
 
 using namespace mozilla::dom;
 
-DOMCI_DATA(MozIccManager, IccManager)
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(IccManager)
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IccManager,
-                                               DOMEventTargetHelper)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsIccIds)
-  // We did not setup 'mIccListeners' being a participant of cycle collection is
-  // because in Navigator->Invalidate() it will call mIccManager->Shutdown(),
-  // then IccManager will call Shutdown() of each IccListener, this will release
-  // the reference that held by each mIccListener and break the cycle.
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IccManager,
                                                   DOMEventTargetHelper)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IccManager,
                                                 DOMEventTargetHelper)
-  tmp->Unroot();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
+// QueryInterface implementation for IccManager
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IccManager)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMMozIccManager)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozIccManager)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(IccManager, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(IccManager, DOMEventTargetHelper)
 
 IccManager::IccManager(nsPIDOMWindow* aWindow)
-  : mJsIccIds(nullptr)
-  , mRooted(false)
+  : DOMEventTargetHelper(aWindow)
 {
-  BindToOwner(aWindow);
-
   uint32_t numberOfServices =
     mozilla::Preferences::GetUint("ril.numRadioInterfaces", 1);
 
   for (uint32_t i = 0; i < numberOfServices; i++) {
     nsRefPtr<IccListener> iccListener = new IccListener(this, i);
     mIccListeners.AppendElement(iccListener);
   }
 }
 
 IccManager::~IccManager()
 {
   Shutdown();
-  Unroot();
+}
+
+JSObject*
+IccManager::WrapObject(JSContext* aCx)
+{
+  return MozIccManagerBinding::Wrap(aCx, this);
 }
 
 void
 IccManager::Shutdown()
 {
   for (uint32_t i = 0; i < mIccListeners.Length(); i++) {
     mIccListeners[i]->Shutdown();
     mIccListeners[i] = nullptr;
   }
   mIccListeners.Clear();
 }
 
 nsresult
 IccManager::NotifyIccAdd(const nsAString& aIccId)
 {
-  mJsIccIds = nullptr;
+  MozIccManagerBinding::ClearCachedIccIdsValue(this);
 
   IccChangeEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
   init.mIccId = aIccId;
 
   nsRefPtr<IccChangeEvent> event =
     IccChangeEvent::Constructor(this, NS_LITERAL_STRING("iccdetected"), init);
 
   return DispatchTrustedEvent(event);
 }
 
 nsresult
 IccManager::NotifyIccRemove(const nsAString& aIccId)
 {
-  mJsIccIds = nullptr;
+  MozIccManagerBinding::ClearCachedIccIdsValue(this);
 
   IccChangeEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
   init.mIccId = aIccId;
 
   nsRefPtr<IccChangeEvent> event =
     IccChangeEvent::Constructor(this, NS_LITERAL_STRING("iccundetected"), init);
 
   return DispatchTrustedEvent(event);
 }
 
-void
-IccManager::Root()
-{
-  if (!mRooted) {
-    mozilla::HoldJSObjects(this);
-    mRooted = true;
-  }
-}
+// MozIccManager
 
 void
-IccManager::Unroot()
+IccManager::GetIccIds(nsTArray<nsString>& aIccIds)
 {
-  if (mRooted) {
-    mJsIccIds = nullptr;
-    mozilla::DropJSObjects(this);
-    mRooted = false;
+  nsTArray<nsRefPtr<IccListener>>::size_type i;
+  for (i = 0; i < mIccListeners.Length(); ++i) {
+    nsRefPtr<Icc> icc = mIccListeners[i]->GetIcc();
+    if (icc) {
+      aIccIds.AppendElement(icc->GetIccId());
+    }
   }
 }
 
-// nsIDOMMozIccManager
-
-NS_IMETHODIMP
-IccManager::GetIccIds(JS::MutableHandle<JS::Value> aIccIds)
+already_AddRefed<nsISupports>
+IccManager::GetIccById(const nsAString& aIccId) const
 {
-  if (!mJsIccIds) {
-    nsTArray<nsString> iccIds;
-    for (uint32_t i = 0; i < mIccListeners.Length(); i++) {
-      nsRefPtr<Icc> icc = mIccListeners[i]->GetIcc();
-      if (icc) {
-        iccIds.AppendElement(icc->GetIccId());
-      }
-    }
-
-    nsresult rv;
-    nsIScriptContext* sc = GetContextForEventHandlers(&rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    AutoPushJSContext cx(sc->GetNativeContext());
-    JS::Rooted<JSObject*> jsIccIds(cx);
-    rv = nsTArrayToJSArray(cx, iccIds, jsIccIds.address());
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    mJsIccIds = jsIccIds;
-    Root();
-  }
-
-  aIccIds.setObject(*mJsIccIds);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-IccManager::GetIccById(const nsAString& aIccId, nsISupports** aIcc)
-{
-  *aIcc = nullptr;
-
-  for (uint32_t i = 0; i < mIccListeners.Length(); i++) {
+  nsTArray<nsRefPtr<IccListener>>::size_type i;
+  for (i = 0; i < mIccListeners.Length(); ++i) {
     nsRefPtr<Icc> icc = mIccListeners[i]->GetIcc();
     if (icc && aIccId == icc->GetIccId()) {
-      icc.forget(aIcc);
-      return NS_OK;
+      return icc.forget();
     }
   }
-
-  return NS_OK;
+  return nullptr;
 }
-
-NS_IMPL_EVENT_HANDLER(IccManager, iccdetected)
-NS_IMPL_EVENT_HANDLER(IccManager, iccundetected)
--- a/dom/icc/src/IccManager.h
+++ b/dom/icc/src/IccManager.h
@@ -2,58 +2,60 @@
  * 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/. */
 
 #ifndef mozilla_dom_IccManager_h
 #define mozilla_dom_IccManager_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsIDOMIccManager.h"
 #include "nsIIccProvider.h"
 #include "nsTArrayHelpers.h"
 
 namespace mozilla {
 namespace dom {
 
 class IccListener;
 
 class IccManager MOZ_FINAL : public DOMEventTargetHelper
-                           , public nsIDOMMozIccManager
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIDOMMOZICCMANAGER
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
 
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(IccManager,
-                                                         DOMEventTargetHelper)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IccManager, DOMEventTargetHelper)
 
   IccManager(nsPIDOMWindow* aWindow);
   ~IccManager();
 
   void
   Shutdown();
 
   nsresult
   NotifyIccAdd(const nsAString& aIccId);
 
   nsresult
   NotifyIccRemove(const nsAString& aIccId);
 
+  IMPL_EVENT_HANDLER(iccdetected)
+  IMPL_EVENT_HANDLER(iccundetected)
+
+  void
+  GetIccIds(nsTArray<nsString>& aIccIds);
+
+  already_AddRefed<nsISupports>
+  GetIccById(const nsAString& aIccId) const;
+
+  nsPIDOMWindow*
+  GetParentObject() const { return GetOwner(); }
+
+  virtual JSObject*
+  WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
 private:
   nsTArray<nsRefPtr<IccListener>> mIccListeners;
-
-  // Cached iccIds js array object. Cleared whenever the NotifyIccAdd() or
-  // NotifyIccRemove() is called, and then rebuilt once a page looks for the
-  // iccIds attribute.
-  JS::Heap<JSObject*> mJsIccIds;
-  bool mRooted;
-
-  void Root();
-  void Unroot();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_IccManager_h
--- a/dom/push/src/PushService.jsm
+++ b/dom/push/src/PushService.jsm
@@ -364,16 +364,21 @@ this.PushService = {
         debug("webapps-clear-data");
 
         let data = aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
         if (!data) {
           debug("webapps-clear-data: Failed to get information about application");
           return;
         }
 
+        // Only remove push registrations for apps.
+        if (data.browserOnly) {
+          return;
+        }
+
         let appsService = Cc["@mozilla.org/AppsService;1"]
                             .getService(Ci.nsIAppsService);
         let manifestURL = appsService.getManifestURLByLocalId(data.appId);
         if (!manifestURL) {
           debug("webapps-clear-data: No manifest URL found for " + data.appId);
           return;
         }
 
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -639,19 +639,20 @@ NetworkManager.prototype = {
       if (this.isNetworkTypeSecondaryMobile(this.active.type)) {
         gNetworkService.setDNS(this.active);
       } else {
 #endif // MOZ_B2G_RIL
         gNetworkService.setDefaultRouteAndDNS(this.active, oldActive);
 #ifdef MOZ_B2G_RIL
       }
 #endif
-      if (this.active != oldActive) {
-        Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
-      }
+    }
+
+    if (this.active != oldActive) {
+      Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
     }
 
     if (this._manageOfflineStatus) {
       Services.io.offline = !this.active;
     }
   },
 
 #ifdef MOZ_B2G_RIL
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/marionette/head.js
@@ -0,0 +1,134 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_CONTEXT = "chrome";
+
+let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
+
+/**
+ * Wrap DOMRequest onsuccess/onerror events to Promise resolve/reject.
+ *
+ * Fulfill params: A DOMEvent.
+ * Reject params: A DOMEvent.
+ *
+ * @param aRequest
+ *        A DOMRequest instance.
+ *
+ * @return A deferred promise.
+ */
+function wrapDomRequestAsPromise(aRequest) {
+  let deferred = Promise.defer();
+
+  ok(aRequest instanceof DOMRequest,
+     "aRequest is instanceof " + aRequest.constructor);
+
+  aRequest.addEventListener("success", function(aEvent) {
+    deferred.resolve(aEvent);
+  });
+  aRequest.addEventListener("error", function(aEvent) {
+    deferred.reject(aEvent);
+  });
+
+  return deferred.promise;
+}
+
+/**
+ * Get mozSettings value specified by @aKey.
+ *
+ * Resolve if that mozSettings value is retrieved successfully, reject
+ * otherwise.
+ *
+ * Fulfill params: The corresponding mozSettings value of the key.
+ * Reject params: (none)
+ *
+ * @param aKey
+ *        A string.
+ * @param aAllowError [optional]
+ *        A boolean value.  If set to true, an error response won't be treated
+ *        as test failure.  Default: false.
+ *
+ * @return A deferred promise.
+ */
+function getSettings(aKey, aAllowError) {
+  let request = window.navigator.mozSettings.createLock().get(aKey);
+  return wrapDomRequestAsPromise(request)
+    .then(function resolve(aEvent) {
+      log("getSettings(" + aKey + ") - success");
+      return aEvent.target.result[aKey];
+    }, function reject(aEvent) {
+      ok(aAllowError, "getSettings(" + aKey + ") - error");
+    });
+}
+
+/**
+ * Set mozSettings values.
+ *
+ * Resolve if that mozSettings value is set successfully, reject otherwise.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @param aKey
+ *        A string key.
+ * @param aValue
+ *        An object value.
+ * @param aAllowError [optional]
+ *        A boolean value.  If set to true, an error response won't be treated
+ *        as test failure.  Default: false.
+ *
+ * @return A deferred promise.
+ */
+function setSettings(aKey, aValue, aAllowError) {
+  let settings = {};
+  settings[aKey] = aValue;
+  let request = window.navigator.mozSettings.createLock().set(settings);
+  return wrapDomRequestAsPromise(request)
+    .then(function resolve() {
+      log("setSettings(" + JSON.stringify(settings) + ") - success");
+    }, function reject() {
+      ok(aAllowError, "setSettings(" + JSON.stringify(settings) + ") - error");
+    });
+}
+
+/**
+ * Wait for observer event.
+ *
+ * Resolve if that topic event occurs.  Never reject.
+ *
+ * Fulfill params: the subject passed.
+ *
+ * @param aTopic
+ *        A string topic name.
+ *
+ * @return A deferred promise.
+ */
+function waitForObserverEvent(aTopic) {
+  let obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+  let deferred = Promise.defer();
+
+  obs.addObserver(function observer(subject, topic, data) {
+    if (topic === aTopic) {
+      obs.removeObserver(observer, aTopic);
+      deferred.resolve(subject);
+    }
+  }, aTopic, false);
+
+  return deferred.promise;
+}
+
+/**
+ * Basic test routine helper.
+ *
+ * This helper does nothing but clean-ups.
+ *
+ * @param aTestCaseMain
+ *        A function that takes no parameter.
+ */
+function startTestBase(aTestCaseMain) {
+  Promise.resolve()
+    .then(aTestCaseMain)
+    .then(finish, function() {
+      ok(false, 'promise rejects during test.');
+      finish();
+    });
+}
--- a/dom/system/gonk/tests/marionette/manifest.ini
+++ b/dom/system/gonk/tests/marionette/manifest.ini
@@ -5,8 +5,9 @@ qemu = true
 
 [test_geolocation.js]
 disabled = Bug 808783
 [test_fakevolume.js]
 [test_ril_code_quality.py]
 [test_screen_state.js]
 [test_dsds_numRadioInterfaces.js]
 [test_data_connection.js]
+[test_network_active_changed.js]
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/marionette/test_network_active_changed.js
@@ -0,0 +1,54 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+const SETTINGS_KEY_DATA_ENABLED = "ril.data.enabled";
+const TOPIC_NETWORK_ACTIVE_CHANGED = "network-active-changed";
+
+let networkManager =
+  Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager);
+ok(networkManager,
+   "networkManager.constructor is " + networkManager.constructor);
+
+function testInitialState() {
+  return Promise.resolve()
+    .then(() => getSettings(SETTINGS_KEY_DATA_ENABLED))
+    .then((enabled) => {
+      is(enabled, false, "data should be off by default");
+      is(networkManager.active, null,
+         "networkManager.active should be null by default");
+    });
+}
+
+function testActiveNetworkChangedBySwitchingDataCall(aDataCallEnabled) {
+  log("Test active network by switching dataCallEnabled to " + aDataCallEnabled);
+
+  return Promise.resolve()
+    .then(() => setSettings(SETTINGS_KEY_DATA_ENABLED, aDataCallEnabled))
+    .then(() => waitForObserverEvent(TOPIC_NETWORK_ACTIVE_CHANGED))
+    .then((subject) => {
+      if (aDataCallEnabled) {
+        ok(subject instanceof Ci.nsINetworkInterface,
+           "subject should be an instance of nsINetworkInterface");
+        ok(subject instanceof Ci.nsIRilNetworkInterface,
+           "subject should be an instance of nsIRILNetworkInterface");
+        is(subject.type, Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
+           "subject.type should be NETWORK_TYPE_MOBILE");
+      }
+
+      is(subject, networkManager.active,
+         "subject should be equal with networkManager.active");
+    });
+}
+
+// Start test
+startTestBase(function() {
+  return Promise.resolve()
+    .then(() => testInitialState())
+    // Test active network changed by enabling data call.
+    .then(() => testActiveNetworkChangedBySwitchingDataCall(true))
+    // Test active network changed by disabling data call.
+    .then(() => testActiveNetworkChangedBySwitchingDataCall(false));
+});
--- a/dom/telephony/gonk/TelephonyProvider.js
+++ b/dom/telephony/gonk/TelephonyProvider.js
@@ -425,34 +425,59 @@ TelephonyProvider.prototype = {
     if (DEBUG) debug("Dialing " + (aIsEmergency ? "emergency " : "") + aNumber);
 
     if (this.isDialing) {
       if (DEBUG) debug("Already has a dialing call. Drop.");
       aTelephonyCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
       return;
     }
 
-    // For DSDS, if there is aleady a call on SIM X, we cannot place any new
-    // call on other SIM.
-    let callOnOtherSim = false;
-    for (let cid = 0; cid < this._numClients; ++cid) {
-      if (cid === aClientId) {
-        continue;
+    function hasCallsOnOtherClient(aClientId) {
+      for (let cid = 0; cid < this._numClients; ++cid) {
+        if (cid === aClientId) {
+          continue;
+        }
+        if (Object.keys(this._currentCalls[cid]).length !== 0) {
+          return true;
+        }
       }
-      if (Object.keys(this._currentCalls[cid]).length !== 0) {
-        callOnOtherSim = true;
-        break;
-      }
+      return false;
     }
-    if (callOnOtherSim) {
+
+    // For DSDS, if there is aleady a call on SIM 'aClientId', we cannot place
+    // any new call on other SIM.
+    if (hasCallsOnOtherClient.call(this, aClientId)) {
       if (DEBUG) debug("Already has a call on other sim. Drop.");
       aTelephonyCallback.notifyDialError(DIAL_ERROR_OTHER_CONNECTION_IN_USE);
       return;
     }
 
+    // All calls in the conference is regarded as one conference call.
+    function numCallsOnLine(aClientId) {
+      let numCalls = 0;
+      let hasConference = false;
+
+      for (let cid in this._currentCalls[aClientId]) {
+        let call = this._currentCalls[aClientId][cid];
+        if (call.isConference) {
+          hasConference = true;
+        } else {
+          numCalls++;
+        }
+      }
+
+      return hasConference ? numCalls + 1 : numCalls;
+    }
+
+    if (numCallsOnLine.call(this, aClientId) >= 2) {
+      if (DEBUG) debug("Has more than 2 calls on line. Drop.");
+      aTelephonyCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
+      return;
+    }
+
     // we don't try to be too clever here, as the phone is probably in the
     // locked state. Let's just check if it's a number without normalizing
     if (!aIsEmergency) {
       aNumber = gPhoneNumberUtils.normalize(aNumber);
     }
 
     // Validate the number.
     if (!gPhoneNumberUtils.isPlainPhoneNumber(aNumber)) {
--- a/dom/telephony/test/marionette/head.js
+++ b/dom/telephony/test/marionette/head.js
@@ -379,16 +379,18 @@ let emulator = (function() {
       is(call.serviceId, serviceId);
 
       call.onalerting = function onalerting(event) {
         call.onalerting = null;
         log("Received 'onalerting' call event.");
         checkEventCallState(event, call, "alerting");
         deferred.resolve(call);
       };
+    }, cause => {
+      deferred.reject(cause);
     });
 
     return deferred.promise;
   }
 
   /**
    * Answer an incoming call.
    *
@@ -439,16 +441,48 @@ let emulator = (function() {
       receive("call.onconnected");
     };
     call.answer();
 
     return deferred.promise;
   }
 
   /**
+   * Hold a call.
+   *
+   * @param call
+   *        A TelephonyCall object.
+   * @return A deferred promise.
+   */
+  function hold(call) {
+    log("Putting the call on hold.");
+
+    let deferred = Promise.defer();
+
+    let gotHolding = false;
+    call.onholding = function onholding(event) {
+      log("Received 'holding' call event");
+      call.onholding = null;
+      checkEventCallState(event, call, "holding");
+      gotHolding = true;
+    };
+
+    call.onheld = function onheld(event) {
+      log("Received 'held' call event");
+      call.onheld = null;
+      checkEventCallState(event, call, "held");
+      ok(gotHolding);
+      deferred.resolve(call);
+    };
+    call.hold();
+
+    return deferred.promise;
+  }
+
+  /**
    * Simulate an incoming call.
    *
    * @param number
    *        A string.
    * @return A deferred promise.
    */
   function remoteDial(number) {
     log("Simulating an incoming call.");
@@ -1033,16 +1067,17 @@ let emulator = (function() {
   this.gCheckInitialState = checkInitialState;
   this.gClearCalls = clearCalls;
   this.gOutCallStrPool = outCallStrPool;
   this.gInCallStrPool = inCallStrPool;
   this.gCheckState = checkState;
   this.gCheckAll = checkAll;
   this.gDial = dial;
   this.gAnswer = answer;
+  this.gHold = hold;
   this.gRemoteDial = remoteDial;
   this.gRemoteAnswer = remoteAnswer;
   this.gRemoteHangUp = remoteHangUp;
   this.gRemoteHangUpCalls = remoteHangUpCalls;
   this.gAddCallsToConference = addCallsToConference;
   this.gHoldConference = holdConference;
   this.gResumeConference = resumeConference;
   this.gRemoveCallInConference = removeCallInConference;
--- a/dom/telephony/test/marionette/manifest.ini
+++ b/dom/telephony/test/marionette/manifest.ini
@@ -51,8 +51,9 @@ disabled = Bug 821958
 [test_conference_two_calls.js]
 [test_conference_add_error.js]
 [test_conference_remove_error.js]
 [test_conference_two_hangup_one.js]
 [test_conference_two_hold_resume.js]
 [test_conference_two_remove_one.js]
 [test_conference_three_hangup_one.js]
 [test_conference_three_remove_one.js]
+[test_outgoing_when_two_calls_on_line.js]
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_outgoing_when_two_calls_on_line.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+function testReject3rdCall() {
+  let outCall1;
+  let outCall2;
+
+  return gDial("0912345001")
+    .then(call => { outCall1 = call; })
+    .then(() => gRemoteAnswer(outCall1))
+    .then(() => gHold(outCall1))
+    .then(() => gDial("0912345002"))
+    .then(call => { outCall2 = call; })
+    .then(() => gRemoteAnswer(outCall2))
+    .then(() => gDial("0912345003"))
+    .then(call => {
+      ok(false, "The dial request should be rejected");
+    }, cause => {
+      log("Reject 3rd call, cuase: " + cause);
+      is(cause, "InvalidStateError");
+    })
+    .then(() => gRemoteHangUpCalls([outCall1, outCall2]));
+}
+
+startTest(function() {
+  testReject3rdCall()
+    .then(null, () => {
+      ok(false, 'promise rejects during test.');
+    })
+    .then(finish);
+});
rename from dom/icc/interfaces/nsIDOMIccManager.idl
rename to dom/webidl/MozIccManager.webidl
--- a/dom/icc/interfaces/nsIDOMIccManager.idl
+++ b/dom/webidl/MozIccManager.webidl
@@ -1,18 +1,15 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
+ * 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/. */
 
-#include "nsIDOMEventTarget.idl"
-
-interface nsIDOMMozIcc;
-
-[scriptable, builtinclass, uuid(67e40e8e-35ee-40a4-a5b8-414588675133)]
-interface nsIDOMMozIccManager : nsIDOMEventTarget
+[Pref="dom.icc.enabled"]
+interface MozIccManager : EventTarget
 {
   /**
    * STK menu presentation types.
    */
   const unsigned short STK_MENU_TYPE_NOT_SPECIFIED      = 0x00;
   const unsigned short STK_MENU_TYPE_DATA_VALUES        = 0x01;
   const unsigned short STK_MENU_TYPE_NAVIGATION_OPTIONS = 0x03;
 
@@ -226,30 +223,31 @@ interface nsIDOMMozIccManager : nsIDOMEv
    * Next Action Indicator.
    */
   const unsigned short STK_NEXT_ACTION_NULL                  = 0x00;
   const unsigned short STK_NEXT_ACTION_END_PROACTIVE_SESSION = 0x81;
 
   /**
    * Array of iccIds that are currently detected.
    */
-  readonly attribute jsval iccIds;  // DOMString[]
+  [Cached, Pure]
+  readonly attribute sequence<DOMString> iccIds;
 
   /**
    * Get ICC object by iccId.
    *
    * @param iccId
    *        The identifier of the ICC.
    *
    * @return see MozIcc.webidl for the detail.
    */
-  nsISupports getIccById(in DOMString iccId);
+  nsISupports getIccById(DOMString iccId);
 
   /**
    * 'oniccdetected' event is notified whenever a new ICC is detected.
    */
-  [implicit_jscontext] attribute jsval oniccdetected;
+  attribute EventHandler oniccdetected;
 
   /**
    * 'oniccundetected' event is notified whenever an ICC becomes undetected.
    */
-  [implicit_jscontext] attribute jsval oniccundetected;
+  attribute EventHandler oniccundetected;
 };
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -268,18 +268,16 @@ partial interface Navigator {
   readonly attribute MozCellBroadcast mozCellBroadcast;
 };
 
 partial interface Navigator {
   [Throws, Func="Navigator::HasVoicemailSupport"]
   readonly attribute MozVoicemail mozVoicemail;
 };
 
-// nsIMozNavigatorIccManager
-interface MozIccManager;
 partial interface Navigator {
   [Throws, Func="Navigator::HasIccManagerSupport"]
   readonly attribute MozIccManager? mozIccManager;
 };
 #endif // MOZ_B2G_RIL
 
 partial interface Navigator {
   [Throws, Func="Navigator::HasTelephonySupport"]
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -538,16 +538,17 @@ if CONFIG['MOZ_B2G_BT']:
     ]
 
 if CONFIG['MOZ_B2G_RIL']:
     WEBIDL_FILES += [
         'IccCardLockError.webidl',
         'MozCellBroadcast.webidl',
         'MozCellBroadcastEvent.webidl',
         'MozIcc.webidl',
+        'MozIccManager.webidl',
         'MozMobileConnectionArray.webidl',
         'MozVoicemail.webidl',
         'MozVoicemailEvent.webidl',
     ]
 
 if CONFIG['MOZ_NFC']:
     WEBIDL_FILES += [
          'MozNDEFRecord.webidl',
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -486,75 +486,17 @@ abstract public class BrowserApp extends
 
         mBrowserSearchContainer = findViewById(R.id.search_container);
         mBrowserSearch = (BrowserSearch) getSupportFragmentManager().findFragmentByTag(BROWSER_SEARCH_TAG);
         if (mBrowserSearch == null) {
             mBrowserSearch = BrowserSearch.newInstance();
             mBrowserSearch.setUserVisibleHint(false);
         }
 
-        mBrowserToolbar.setOnActivateListener(new BrowserToolbar.OnActivateListener() {
-            public void onActivate() {
-                enterEditingMode();
-            }
-        });
-
-        mBrowserToolbar.setOnCommitListener(new BrowserToolbar.OnCommitListener() {
-            public void onCommit() {
-                commitEditingMode();
-            }
-        });
-
-        mBrowserToolbar.setOnDismissListener(new BrowserToolbar.OnDismissListener() {
-            public void onDismiss() {
-                mBrowserToolbar.cancelEdit();
-            }
-        });
-
-        mBrowserToolbar.setOnFilterListener(new BrowserToolbar.OnFilterListener() {
-            public void onFilter(String searchText, AutocompleteHandler handler) {
-                filterEditingMode(searchText, handler);
-            }
-        });
-
-        mBrowserToolbar.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                if (isHomePagerVisible()) {
-                    mHomePager.onToolbarFocusChange(hasFocus);
-                }
-            }
-        });
-
-        mBrowserToolbar.setOnStartEditingListener(new BrowserToolbar.OnStartEditingListener() {
-            public void onStartEditing() {
-                // Temporarily disable doorhanger notifications.
-                mDoorHangerPopup.disable();
-            }
-        });
-
-        mBrowserToolbar.setOnStopEditingListener(new BrowserToolbar.OnStopEditingListener() {
-            public void onStopEditing() {
-                selectTargetTabForEditingMode();
-
-                // Since the underlying LayerView is set visible in hideHomePager, we would
-                // ordinarily want to call it first. However, hideBrowserSearch changes the
-                // visibility of the HomePager and hideHomePager will take no action if the
-                // HomePager is hidden, so we want to call hideBrowserSearch to restore the
-                // HomePager visibility first.
-                hideBrowserSearch();
-                hideHomePager();
-
-                // Re-enable doorhanger notifications. They may trigger on the selected tab above.
-                mDoorHangerPopup.enable();
-            }
-        });
-
-        // Intercept key events for gamepad shortcuts
-        mBrowserToolbar.setOnKeyListener(this);
+        setBrowserToolbarListeners();
 
         mFindInPageBar = (FindInPageBar) findViewById(R.id.find_in_page);
         mMediaCastingBar = (MediaCastingBar) findViewById(R.id.media_casting);
 
         registerEventListener("CharEncoding:Data");
         registerEventListener("CharEncoding:State");
         registerEventListener("Feedback:LastUrl");
         registerEventListener("Feedback:OpenPlayStore");
@@ -634,16 +576,78 @@ abstract public class BrowserApp extends
 
     @Override
     public void onPause() {
         super.onPause();
         // Register for Prompt:ShowTop so we can foreground this activity even if it's hidden.
         registerEventListener("Prompt:ShowTop");
     }
 
+    private void setBrowserToolbarListeners() {
+        mBrowserToolbar.setOnActivateListener(new BrowserToolbar.OnActivateListener() {
+            public void onActivate() {
+                enterEditingMode();
+            }
+        });
+
+        mBrowserToolbar.setOnCommitListener(new BrowserToolbar.OnCommitListener() {
+            public void onCommit() {
+                commitEditingMode();
+            }
+        });
+
+        mBrowserToolbar.setOnDismissListener(new BrowserToolbar.OnDismissListener() {
+            public void onDismiss() {
+                mBrowserToolbar.cancelEdit();
+            }
+        });
+
+        mBrowserToolbar.setOnFilterListener(new BrowserToolbar.OnFilterListener() {
+            public void onFilter(String searchText, AutocompleteHandler handler) {
+                filterEditingMode(searchText, handler);
+            }
+        });
+
+        mBrowserToolbar.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (isHomePagerVisible()) {
+                    mHomePager.onToolbarFocusChange(hasFocus);
+                }
+            }
+        });
+
+        mBrowserToolbar.setOnStartEditingListener(new BrowserToolbar.OnStartEditingListener() {
+            public void onStartEditing() {
+                // Temporarily disable doorhanger notifications.
+                mDoorHangerPopup.disable();
+            }
+        });
+
+        mBrowserToolbar.setOnStopEditingListener(new BrowserToolbar.OnStopEditingListener() {
+            public void onStopEditing() {
+                selectTargetTabForEditingMode();
+
+                // Since the underlying LayerView is set visible in hideHomePager, we would
+                // ordinarily want to call it first. However, hideBrowserSearch changes the
+                // visibility of the HomePager and hideHomePager will take no action if the
+                // HomePager is hidden, so we want to call hideBrowserSearch to restore the
+                // HomePager visibility first.
+                hideBrowserSearch();
+                hideHomePager();
+
+                // Re-enable doorhanger notifications. They may trigger on the selected tab above.
+                mDoorHangerPopup.enable();
+            }
+        });
+
+        // Intercept key events for gamepad shortcuts
+        mBrowserToolbar.setOnKeyListener(this);
+    }
+
     private void showBookmarkDialog() {
         final Tab tab = Tabs.getInstance().getSelectedTab();
         final Prompt ps = new Prompt(this, new Prompt.PromptCallback() {
             @Override
             public void onPromptFinished(String result) {
                 int itemId = -1;
                 try {
                   itemId = new JSONObject(result).getInt("button");
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -3,26 +3,22 @@
  * 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/. */
 
 package org.mozilla.gecko;
 
 import java.io.BufferedReader;
 import java.io.Closeable;
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.net.Proxy;
-import java.net.URL;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Queue;
@@ -105,17 +101,16 @@ import android.view.ContextThemeWrapper;
 import android.view.HapticFeedbackConstants;
 import android.view.Surface;
 import android.view.SurfaceView;
 import android.view.TextureView;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
 import android.webkit.MimeTypeMap;
 import android.widget.AbsoluteLayout;
-import android.widget.Toast;
 
 public class GeckoAppShell
 {
     private static final String LOGTAG = "GeckoAppShell";
     private static final boolean LOGGING = false;
 
     // We have static members only.
     private GeckoAppShell() { }
--- a/mobile/android/base/WebappImpl.java
+++ b/mobile/android/base/WebappImpl.java
@@ -18,23 +18,23 @@ import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Animation;
 import android.widget.ImageView;
 import android.view.Display;
 
-import java.net.URL;
 import java.io.File;
+import java.net.URI;
 
 public class WebappImpl extends GeckoApp {
     private static final String LOGTAG = "GeckoWebappImpl";
 
-    private URL mOrigin;
+    private URI mOrigin;
     private TextView mTitlebarText = null;
     private View mTitlebar = null;
 
     private View mSplashscreen;
 
     protected int getIndex() { return 0; }
 
     @Override
@@ -64,28 +64,28 @@ public class WebappImpl extends GeckoApp
         if (!action.startsWith(ACTION_WEBAPP_PREFIX)) {
             Log.e(LOGTAG, "Webapp launch, but intent action is " + action + "!");
             return;
         }
 
         // Try to use the origin stored in the WebappAllocator first
         String origin = WebappAllocator.getInstance(this).getAppForIndex(getIndex());
         try {
-            mOrigin = new URL(origin);
-        } catch (java.net.MalformedURLException ex) {
+            mOrigin = new URI(origin);
+        } catch (java.net.URISyntaxException ex) {
             // If we can't parse the this is an app protocol, just settle for not having an origin
             if (!origin.startsWith("app://")) {
                 return;
             }
 
             // If that failed fall back to the origin stored in the shortcut
             Log.i(LOGTAG, "Webapp is not registered with allocator");
             try {
-                mOrigin = new URL(getIntent().getData().toString());
-            } catch (java.net.MalformedURLException ex2) {
+                mOrigin = new URI(getIntent().getData().toString());
+            } catch (java.net.URISyntaxException ex2) {
                 Log.e(LOGTAG, "Unable to parse intent url: ", ex);
             }
         }
     }
 
     @Override
     protected void loadStartupTab(String uri) {
         String action = getIntent().getAction();
@@ -159,38 +159,38 @@ public class WebappImpl extends GeckoApp
 
     @Override
     public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
         switch(msg) {
             case SELECTED:
             case LOCATION_CHANGE:
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     final String urlString = tab.getURL();
-                    final URL url;
+                    final URI uri;
 
                     try {
-                        url = new URL(urlString);
-                    } catch (java.net.MalformedURLException ex) {
+                        uri = new URI(urlString);
+                    } catch (java.net.URISyntaxException ex) {
                         mTitlebarText.setText(urlString);
 
                         // If we can't parse the url, and its an app protocol hide
                         // the titlebar and return, otherwise show the titlebar
                         // and the full url
                         if (!urlString.startsWith("app://")) {
                             mTitlebar.setVisibility(View.VISIBLE);
                         } else {
                             mTitlebar.setVisibility(View.GONE);
                         }
                         return;
                     }
 
-                    if (mOrigin != null && mOrigin.getHost().equals(url.getHost())) {
+                    if (mOrigin != null && mOrigin.getHost().equals(uri.getHost())) {
                         mTitlebar.setVisibility(View.GONE);
                     } else {
-                        mTitlebarText.setText(url.getProtocol() + "://" + url.getHost());
+                        mTitlebarText.setText(uri.getScheme() + "://" + uri.getHost());
                         mTitlebar.setVisibility(View.VISIBLE);
                     }
                 }
                 break;
             case LOADED:
                 if (mSplashscreen != null && mSplashscreen.getVisibility() == View.VISIBLE) {
                     Animation fadeout = AnimationUtils.loadAnimation(this, android.R.anim.fade_out);
                     fadeout.setAnimationListener(new Animation.AnimationListener() {
--- a/mobile/android/base/background/nativecode/NativeCrypto.java
+++ b/mobile/android/base/background/nativecode/NativeCrypto.java
@@ -1,22 +1,40 @@
 /* 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/. */
 
 package org.mozilla.gecko.background.nativecode;
 
+import java.security.GeneralSecurityException;
+
+import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.mozglue.RobocopTarget;
 
-import java.security.GeneralSecurityException;
+import android.util.Log;
 
 @RobocopTarget
 public class NativeCrypto {
   static {
-    System.loadLibrary("mozglue");
+    try {
+      System.loadLibrary("mozglue");
+    } catch (UnsatisfiedLinkError e) {
+      Log.wtf("NativeCrypto", "Couldn't load mozglue. Trying /data/app-lib path.");
+      try {
+        System.load("/data/app-lib/" + AppConstants.ANDROID_PACKAGE_NAME + "/libmozglue.so");
+      } catch (Throwable ee) {
+          try {
+            Log.wtf("NativeCrypto", "Couldn't load mozglue: " + ee + ". Trying /data/data path.");
+            System.load("/data/data/" + AppConstants.ANDROID_PACKAGE_NAME + "/lib/libmozglue.so");
+          } catch (UnsatisfiedLinkError eee) {
+              Log.wtf("NativeCrypto", "Failed every attempt to load mozglue. Giving up.");
+              throw new RuntimeException("Unable to load mozglue", eee);
+          }
+      }
+    }
   }
 
   /**
    * Wrapper to perform PBKDF2-HMAC-SHA-256 in native code.
    */
   public native static byte[] pbkdf2SHA256(byte[] password, byte[] salt, int c, int dkLen)
       throws GeneralSecurityException;
 
--- a/mobile/android/base/db/PasswordsProvider.java
+++ b/mobile/android/base/db/PasswordsProvider.java
@@ -1,27 +1,27 @@
 /* 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/. */
 
 package org.mozilla.gecko.db;
 
-import java.lang.IllegalArgumentException;
 import java.util.HashMap;
+
 import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.NSSBridge;
-import org.mozilla.gecko.db.DBUtils;
+import org.mozilla.gecko.db.BrowserContract.DeletedPasswords;
 import org.mozilla.gecko.db.BrowserContract.Passwords;
-import org.mozilla.gecko.db.BrowserContract.DeletedPasswords;
-import org.mozilla.gecko.db.BrowserContract;
+import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.sqlite.MatrixBlobCursor;
 import org.mozilla.gecko.sqlite.SQLiteBridge;
 import org.mozilla.gecko.sync.Utils;
+
 import android.content.ContentValues;
 import android.content.Intent;
 import android.content.UriMatcher;
 import android.database.Cursor;
 import android.net.Uri;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -71,17 +71,20 @@ public class PasswordsProvider extends S
         PASSWORDS_PROJECTION_MAP.put(Passwords.TIMES_USED, Passwords.TIMES_USED);
 
         URI_MATCHER.addURI(BrowserContract.PASSWORDS_AUTHORITY, "deleted-passwords", DELETED_PASSWORDS);
 
         DELETED_PASSWORDS_PROJECTION_MAP = new HashMap<String, String>();
         DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.ID, DeletedPasswords.ID);
         DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.GUID, DeletedPasswords.GUID);
         DELETED_PASSWORDS_PROJECTION_MAP.put(DeletedPasswords.TIME_DELETED, DeletedPasswords.TIME_DELETED);
-        System.loadLibrary("mozglue");
+
+        // We don't use .loadMozGlue because we're in a different process,
+        // and we just want to reuse code rather than use the loader lock etc.
+        GeckoLoader.doLoadLibrary("mozglue");
     }
 
     public PasswordsProvider() {
         super(LOG_TAG);
     }
 
     @Override
     protected String getDBName(){
--- a/mobile/android/base/mozglue/GeckoLoader.java.in
+++ b/mobile/android/base/mozglue/GeckoLoader.java.in
@@ -1,8 +1,9 @@
+#filter substitution
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko.mozglue;
 
 import android.content.Context;
@@ -15,16 +16,19 @@ import java.io.File;
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
 import java.text.NumberFormat;
 import java.util.Locale;
 
 public final class GeckoLoader {
     private static final String LOGTAG = "GeckoLoader";
 
+    // This matches AppConstants, but we're built earlier.
+    private static final String ANDROID_PACKAGE_NAME = "@ANDROID_PACKAGE_NAME@";
+
     private static volatile Intent sIntent;
     private static File sCacheFile;
     private static File sGREDir;
 
     private static final Object sLibLoadingLock = new Object();
     // Must hold sLibLoadingLock while accessing the following boolean variables.
     private static boolean sSQLiteLibsLoaded;
     private static boolean sNSSLibsLoaded;
@@ -254,25 +258,44 @@ public final class GeckoLoader {
             sNSSLibsLoaded = true;
         }
 
         loadMozGlue();
         loadLibsSetup(context);
         loadNSSLibsNative(apkName, false);
     }
 
+    public static void doLoadLibrary(final String lib) {
+        try {
+            System.loadLibrary(lib);
+        } catch (UnsatisfiedLinkError e) {
+            Log.wtf(LOGTAG, "Couldn't load " + lib + ". Trying /data/app-lib path.");
+            try {
+                System.load("/data/app-lib/" + ANDROID_PACKAGE_NAME + "/lib" + lib + ".so");
+            } catch (Throwable ee) {
+                try {
+                    Log.wtf(LOGTAG, "Couldn't load " + lib + ": " + ee + ". Trying /data/data path.");
+                    System.load("/data/data/" + ANDROID_PACKAGE_NAME + "/lib/lib" + lib + ".so");
+                } catch (Throwable eee) {
+                    Log.wtf(LOGTAG, "Failed every attempt to load " + lib + ". Giving up.");
+                    throw new RuntimeException("Unable to load " + lib, eee);
+                }
+            }
+        }
+    }
+
     public static void loadMozGlue() {
         synchronized (sLibLoadingLock) {
             if (sMozGlueLoaded) {
                 return;
             }
             sMozGlueLoaded = true;
         }
 
-        System.loadLibrary("mozglue");
+        doLoadLibrary("mozglue");
     }
 
     public static void loadGeckoLibs(Context context, String apkName) {
         loadLibsSetup(context);
         loadGeckoLibsNative(apkName);
     }
 
     private static void setupLocaleEnvironment() {
--- a/mobile/android/base/util/GeckoJarReader.java
+++ b/mobile/android/base/util/GeckoJarReader.java
@@ -11,17 +11,18 @@ import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.util.Log;
 import org.mozilla.gecko.mozglue.RobocopTarget;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.net.URL;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.Stack;
 
 /* Reads out of a multiple level deep jar file such as
  *  jar:jar:file:///data/app/org.mozilla.fennec.apk!/omni.ja!/chrome/chrome/content/branding/favicon32.png
  */
 public final class GeckoJarReader {
     private static final String LOGTAG = "GeckoJarReader";
 
@@ -42,16 +43,18 @@ public final class GeckoJarReader {
             // Load the initial jar file as a zip
             zip = getZipFile(jarUrls.pop());
             inputStream = getStream(zip, jarUrls, url);
             if (inputStream != null) {
                 bitmap = new BitmapDrawable(resources, inputStream);
             }
         } catch (IOException ex) {
             Log.e(LOGTAG, "Exception ", ex);
+        } catch (URISyntaxException ex) {
+            Log.e(LOGTAG, "Exception ", ex);
         } finally {
             if (inputStream != null) {
                 try {
                     inputStream.close();
                 } catch(IOException ex) {
                     Log.e(LOGTAG, "Error closing stream", ex);
                 }
             }
@@ -73,34 +76,36 @@ public final class GeckoJarReader {
             zip = getZipFile(jarUrls.pop());
             InputStream input = getStream(zip, jarUrls, url);
             if (input != null) {
                 reader = new BufferedReader(new InputStreamReader(input));
                 text = reader.readLine();
             }
         } catch (IOException ex) {
             Log.e(LOGTAG, "Exception ", ex);
+        } catch (URISyntaxException ex) {
+            Log.e(LOGTAG, "Exception ", ex);
         } finally {
             if (reader != null) {
                 try {
                     reader.close();
                 } catch(IOException ex) {
                     Log.e(LOGTAG, "Error closing reader", ex);
                 }
             }
             if (zip != null) {
                 zip.close();
             }
         }
 
         return text;
     }
 
-    private static NativeZip getZipFile(String url) throws IOException {
-        URL fileUrl = new URL(url);
+    private static NativeZip getZipFile(String url) throws IOException, URISyntaxException {
+        URI fileUrl = new URI(url);
         return new NativeZip(fileUrl.getPath());
     }
 
     @RobocopTarget
     public static InputStream getStream(String url) {
         Stack<String> jarUrls = parseUrl(url);
         try {
             NativeZip zip = getZipFile(jarUrls.pop());
--- a/mobile/android/base/util/JSONUtils.java
+++ b/mobile/android/base/util/JSONUtils.java
@@ -1,51 +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/. */
 
 package org.mozilla.gecko.util;
 
+import java.util.UUID;
+
 import org.json.JSONException;
 import org.json.JSONObject;
 
-import android.util.Log;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.UUID;
-
 public final class JSONUtils {
-    private static final String LOGTAG = "JSONUtils";
-
     private JSONUtils() {}
 
-    public static URL getURL(String name, JSONObject json) {
-        String url = json.optString(name, null);
-        if (url == null) {
-            return null;
-        }
-
-        try {
-            return new URL(url);
-        } catch (MalformedURLException e) {
-            Log.e(LOGTAG, "", new IllegalStateException(name + "=" + url, e));
-            return null;
-        }
-    }
-
-    public static void putURL(String name, URL url, JSONObject json) {
-        String urlString = url.toString();
-        try {
-            json.put(name, urlString);
-        } catch (JSONException e) {
-            throw new IllegalArgumentException(name + "=" + urlString, e);
-        }
-    }
-
     public static UUID getUUID(String name, JSONObject json) {
         String uuid = json.optString(name, null);
         return (uuid != null) ? UUID.fromString(uuid) : null;
     }
 
     public static void putUUID(String name, UUID uuid, JSONObject json) {
         String uuidString = uuid.toString();
         try {
--- a/mobile/android/base/webapp/InstallListener.java
+++ b/mobile/android/base/webapp/InstallListener.java
@@ -2,18 +2,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/. */
 
 package org.mozilla.gecko.webapp;
 
 import java.io.File;
 import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.GeckoThread;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
--- a/mobile/android/base/webapp/WebappImpl.java
+++ b/mobile/android/base/webapp/WebappImpl.java
@@ -2,55 +2,48 @@
  * 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/. */
 
 package org.mozilla.gecko.webapp;
 
 import java.io.File;
 import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
+import java.net.URI;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.GeckoThread;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
-import org.mozilla.gecko.webapp.ApkResources;
-import org.mozilla.gecko.webapp.InstallHelper;
 import org.mozilla.gecko.webapp.InstallHelper.InstallCallback;
 
-import android.content.Context;
 import android.content.Intent;
-import android.content.SharedPreferences;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.Bitmap;
 import android.graphics.Color;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.Display;
 import android.view.View;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 public class WebappImpl extends GeckoApp implements InstallCallback {
     private static final String LOGTAG = "GeckoWebappImpl";
 
-    private URL mOrigin;
+    private URI mOrigin;
     private TextView mTitlebarText = null;
     private View mTitlebar = null;
 
     private View mSplashscreen;
 
     private boolean mIsApk = true;
     private ApkResources mApkResources;
     private String mManifestUrl;
@@ -267,38 +260,38 @@ public class WebappImpl extends GeckoApp
                     // Don't show the titlebar for about:blank, which we load
                     // into the initial tab we create while waiting for the app
                     // to load.
                     if (urlString != null && urlString.equals("about:blank")) {
                         mTitlebar.setVisibility(View.GONE);
                         return;
                     }
 
-                    final URL url;
+                    final URI uri;
 
                     try {
-                        url = new URL(urlString);
-                    } catch (java.net.MalformedURLException ex) {
+                        uri = new URI(urlString);
+                    } catch (java.net.URISyntaxException ex) {
                         mTitlebarText.setText(urlString);
 
                         // If we can't parse the url, and its an app protocol hide
                         // the titlebar and return, otherwise show the titlebar
                         // and the full url
                         if (urlString != null && !urlString.startsWith("app://")) {
                             mTitlebar.setVisibility(View.VISIBLE);
                         } else {
                             mTitlebar.setVisibility(View.GONE);
                         }
                         return;
                     }
 
-                    if (mOrigin != null && mOrigin.getHost().equals(url.getHost())) {
+                    if (mOrigin != null && mOrigin.getHost().equals(uri.getHost())) {
                         mTitlebar.setVisibility(View.GONE);
                     } else {
-                        mTitlebarText.setText(url.getProtocol() + "://" + url.getHost());
+                        mTitlebarText.setText(uri.getScheme() + "://" + uri.getHost());
                         mTitlebar.setVisibility(View.VISIBLE);
                     }
                 }
                 break;
             case LOADED:
                 hideSplash();
                 break;
             case START:
@@ -345,31 +338,31 @@ public class WebappImpl extends GeckoApp
 
     @Override
     public void installErrored(InstallHelper installHelper, Exception exception) {
         Log.e(LOGTAG, "Install errored", exception);
     }
 
     private void setOrigin(String origin) {
         try {
-            mOrigin = new URL(origin);
-        } catch (java.net.MalformedURLException ex) {
+            mOrigin = new URI(origin);
+        } catch (java.net.URISyntaxException ex) {
             // If this isn't an app: URL, just settle for not having an origin.
             if (!origin.startsWith("app://")) {
                 return;
             }
 
             // If that failed fall back to the origin stored in the shortcut.
             if (!mIsApk) {
                 Log.i(LOGTAG, "Origin is app: URL; falling back to intent URL");
                 Uri data = getIntent().getData();
                 if (data != null) {
                     try {
-                        mOrigin = new URL(data.toString());
-                    } catch (java.net.MalformedURLException ex2) {
+                        mOrigin = new URI(data.toString());
+                    } catch (java.net.URISyntaxException ex2) {
                         Log.e(LOGTAG, "Unable to parse intent URL: ", ex);
                     }
                 }
             }
         }
     }
 
     public void launchWebapp(String origin) {
--- a/python/mozbuild/mozbuild/backend/android_eclipse.py
+++ b/python/mozbuild/mozbuild/backend/android_eclipse.py
@@ -233,16 +233,17 @@ class AndroidEclipseBackend(CommonBacken
         defines['IDE_PROJECT_LIBRARY_REFERENCES'] = '\n'.join(
             'android.library.reference.%s=%s' % (i + 1, ref)
             for i, ref in enumerate(sorted(data.included_projects)))
         if data.filtered_resources:
             filteredResources = self._Element_for_filtered_resources(data.filtered_resources)
             defines['IDE_PROJECT_FILTERED_RESOURCES'] = pretty_print(filteredResources).strip()
         else:
             defines['IDE_PROJECT_FILTERED_RESOURCES'] = ''
+        defines['ANDROID_TARGET_SDK'] = self.environment.substs['ANDROID_TARGET_SDK']
 
         copier = FileCopier()
         finder = FileFinder(template_directory)
         for input_filename, f in itertools.chain(finder.find('**'), finder.find('.**')):
             if input_filename == 'AndroidManifest.xml' and not data.is_library:
                 # Main projects supply their own manifests.
                 continue
             copier.add(input_filename, PreprocessedFile(
--- a/python/mozbuild/mozbuild/backend/templates/android_eclipse/project.properties
+++ b/python/mozbuild/mozbuild/backend/templates/android_eclipse/project.properties
@@ -4,11 +4,11 @@
 #
 # This file must be checked in Version Control Systems.
 #
 # To customize properties used by the Ant build system edit
 # "ant.properties", and override values to adapt the script to your
 # project structure.
 
 # Project target.
-target=android-16
+target=android-@ANDROID_TARGET_SDK@
 @IDE_PROJECT_LIBRARY_SETTING@
 @IDE_PROJECT_LIBRARY_REFERENCES@
--- a/python/mozbuild/mozbuild/test/backend/common.py
+++ b/python/mozbuild/mozbuild/test/backend/common.py
@@ -24,16 +24,23 @@ log_manager = LoggingManager()
 log_manager.add_terminal_logging()
 
 
 test_data_path = mozpath.abspath(mozpath.dirname(__file__))
 test_data_path = mozpath.join(test_data_path, 'data')
 
 
 CONFIGS = DefaultOnReadDict({
+    'android_eclipse': {
+        'defines': [],
+        'non_global_defines': [],
+        'substs': [
+            ('ANDROID_TARGET_SDK', '16'),
+        ],
+    },
     'stub0': {
         'defines': [
             ('MOZ_TRUE_1', '1'),
             ('MOZ_TRUE_2', '1'),
         ],
         'non_global_defines': [
             ('MOZ_NONGLOBAL_1', '1'),
             ('MOZ_NONGLOBAL_2', '1'),
--- a/toolkit/components/osfile/modules/osfile_async_front.jsm
+++ b/toolkit/components/osfile/modules/osfile_async_front.jsm
@@ -174,18 +174,18 @@ function summarizeObject(obj) {
     for (let k of Object.keys(obj)) {
       result[k] = summarizeObject(obj[k]);
     }
     return result;
   }
   return obj;
 }
 
-let worker = null;
 let Scheduler = {
+
   /**
    * |true| once we have sent at least one message to the worker.
    * This field is unaffected by resetting the worker.
    */
   launched: false,
 
   /**
    * |true| once shutdown has begun i.e. we should reject any
@@ -233,16 +233,35 @@ let Scheduler = {
   },
 
   /**
    * A timer used to automatically shut down the worker after some time.
    */
   resetTimer: null,
 
   /**
+   * The worker to which to send requests.
+   *
+   * If the worker has never been created or has been reset, this is a
+   * fresh worker, initialized with osfile_async_worker.js.
+   *
+   * @type {PromiseWorker}
+   */
+  get worker() {
+    if (!this._worker) {
+      // Either the worker has never been created or it has been reset
+      this._worker = new PromiseWorker(
+	"resource://gre/modules/osfile/osfile_async_worker.js", LOG);
+    }
+    return this._worker;
+  },
+
+  _worker: null,
+
+  /**
    * Prepare to kill the OS.File worker after a few seconds.
    */
   restartTimer: function(arg) {
     let delay;
     try {
       delay = Services.prefs.getIntPref("osfile.reset_worker_delay");
     } catch(e) {
       // Don't auto-shutdown if we don't have a delay preference set.
@@ -268,34 +287,41 @@ let Scheduler = {
    *   would not cause leaks. Otherwise, assume that the worker will be shutdown
    *   through some other mean.
    */
   kill: function({shutdown, reset}) {
     return Task.spawn(function*() {
 
       yield this.queue;
 
-      if (!this.launched || this.shutdown || !worker) {
+      // Enter critical section: no yield in this block
+      // (we want to make sure that we remain the only
+      // request in the queue).
+
+      if (!this.launched || this.shutdown || !this._worker) {
         // Nothing to kill
         this.shutdown = this.shutdown || shutdown;
-        worker = null;
+        this._worker = null;
         return null;
       }
 
       // Deactivate the queue, to ensure that no message is sent
       // to an obsolete worker (we reactivate it in the |finally|).
       let deferred = Promise.defer();
       this.queue = deferred.promise;
 
+
+      // Exit critical section
+
       let message = ["Meta_shutdown", [reset]];
 
       try {
         Scheduler.latestReceived = [];
         Scheduler.latestSent = [Date.now(), ...message];
-        let promise = worker.post(...message);
+        let promise = this._worker.post(...message);
 
         // Wait for result
         let resources;
         try {
           resources = (yield promise).ok;
 
           Scheduler.latestReceived = [Date.now(), message];
         } catch (ex) {
@@ -324,17 +350,17 @@ let Scheduler = {
               openedDirectoryIterators.join("\n");
           }
 
           LOG("WARNING: File descriptors leaks detected.\n" + msg);
         }
 
         // Make sure that we do not leave an invalid |worker| around.
         if (killed || shutdown) {
-          worker = null;
+          this._worker = null;
         }
 
         this.shutdown = shutdown;
 
         return resources;
 
       } finally {
         // Resume accepting messages. If we have set |shutdown| to |true|,
@@ -371,55 +397,56 @@ let Scheduler = {
    * must be clonable.
    * @return {Promise} A promise conveying the result/error caused by
    * calling |method| with arguments |args|.
    */
   post: function post(method, ...args) {
     if (this.shutdown) {
       LOG("OS.File is not available anymore. The following request has been rejected.",
         method, args);
-      return Promise.reject(new Error("OS.File has been shut down."));
-    }
-    if (!worker) {
-      // Either the worker has never been created or it has been reset
-      worker = new PromiseWorker(
-        "resource://gre/modules/osfile/osfile_async_worker.js", LOG);
+      return Promise.reject(new Error("OS.File has been shut down. Rejecting post to " + method));
     }
     let firstLaunch = !this.launched;
     this.launched = true;
 
     if (firstLaunch && SharedAll.Config.DEBUG) {
       // If we have delayed sending SET_DEBUG, do it now.
-      worker.post("SET_DEBUG", [true]);
+      this.worker.post("SET_DEBUG", [true]);
       Scheduler.Debugging.messagesSent++;
     }
 
     // By convention, the last argument of any message may be an |options| object.
     let options;
     let methodArgs = args[0];
     if (methodArgs) {
       options = methodArgs[methodArgs.length - 1];
     }
     Scheduler.Debugging.messagesQueued++;
-    return this.push(() => Task.spawn(function*() {
+    return this.push(Task.async(function*() {
+      if (this.shutdown) {
+	LOG("OS.File is not available anymore. The following request has been rejected.",
+	  method, args);
+	throw new Error("OS.File has been shut down. Rejecting request to " + method);
+      }
+
       // Update debugging information. As |args| may be quite
       // expensive, we only keep a shortened version of it.
       Scheduler.Debugging.latestReceived = null;
       Scheduler.Debugging.latestSent = [Date.now(), method, summarizeObject(methodArgs)];
 
       // Don't kill the worker just yet
       Scheduler.restartTimer();
 
 
       let data;
       let reply;
       let isError = false;
       try {
         try {
-          data = yield worker.post(method, ...args);
+          data = yield this.worker.post(method, ...args);
         } finally {
           Scheduler.Debugging.messagesReceived++;
         }
         reply = data;
       } catch (error) {
         reply = error;
         isError = true;
         if (error instanceof PromiseWorker.WorkerError) {
@@ -469,25 +496,26 @@ let Scheduler = {
       let durationMs = Math.max(0, data.durationMs);
       // Accumulate (or initialize) outExecutionDuration
       if (typeof options.outExecutionDuration == "number") {
         options.outExecutionDuration += durationMs;
       } else {
         options.outExecutionDuration = durationMs;
       }
       return data.ok;
-    }));
+    }.bind(this)));
   },
 
   /**
    * Post Telemetry statistics.
    *
    * This is only useful on first launch.
    */
   _updateTelemetry: function() {
+    let worker = this.worker;
     let workerTimeStamps = worker.workerTimeStamps;
     if (!workerTimeStamps) {
       // If the first call to OS.File results in an uncaught errors,
       // the timestamps are absent. As this case is a developer error,
       // let's not waste time attempting to extract telemetry from it.
       return;
     }
     let HISTOGRAM_LAUNCH = Services.telemetry.getHistogramById("OSFILE_WORKER_LAUNCH_MS");
@@ -1477,17 +1505,17 @@ AsyncShutdown.profileBeforeChange.addBlo
     } else {
       return Scheduler.queue;
     }
   },
   function getDetails() {
     let result = {
       launched: Scheduler.launched,
       shutdown: Scheduler.shutdown,
-      worker: !!worker,
+      worker: !!Scheduler._worker,
       pendingReset: !!Scheduler.resetTimer,
       latestSent: Scheduler.Debugging.latestSent,
       latestReceived: Scheduler.Debugging.latestReceived,
       messagesSent: Scheduler.Debugging.messagesSent,
       messagesReceived: Scheduler.Debugging.messagesReceived,
       messagesQueued: Scheduler.Debugging.messagesQueued,
       DEBUG: SharedAll.Config.DEBUG
     };
--- a/toolkit/components/osfile/modules/osfile_async_worker.js
+++ b/toolkit/components/osfile/modules/osfile_async_worker.js
@@ -76,17 +76,17 @@ const EXCEPTION_NAMES = {
    let durationMs;
    try {
      let method = data.fun;
      LOG("Calling method", method);
      result = Agent[method].apply(Agent, data.args);
      LOG("Method", method, "succeeded");
    } catch (ex) {
      exn = ex;
-     LOG("Error while calling agent method", exn, exn.stack || "");
+     LOG("Error while calling agent method", exn, exn.moduleStack || exn.stack || "");
    }
 
    if (start) {
      // Record duration
      durationMs = Date.now() - start;
      LOG("Method took", durationMs, "ms");
    }
 
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -151,58 +151,73 @@ this.PlacesUtils = {
 
   /**
    * Determines whether or not a ResultNode is a Bookmark folder.
    * @param   aNode
    *          A result node
    * @returns true if the node is a Bookmark folder, false otherwise
    */
   nodeIsFolder: function PU_nodeIsFolder(aNode) {
+    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+      throw new Error("Invalid Places node");
+    }
     return (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER ||
             aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT);
   },
 
   /**
    * Determines whether or not a ResultNode represents a bookmarked URI.
    * @param   aNode
    *          A result node
    * @returns true if the node represents a bookmarked URI, false otherwise
    */
   nodeIsBookmark: function PU_nodeIsBookmark(aNode) {
+    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+      throw new Error("Invalid Places node");
+    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_URI &&
            aNode.itemId != -1;
   },
 
   /**
    * Determines whether or not a ResultNode is a Bookmark separator.
    * @param   aNode
    *          A result node
    * @returns true if the node is a Bookmark separator, false otherwise
    */
   nodeIsSeparator: function PU_nodeIsSeparator(aNode) {
+    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+      throw new Error("Invalid Places node");
+    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR;
   },
 
   /**
    * Determines whether or not a ResultNode is a URL item.
    * @param   aNode
    *          A result node
    * @returns true if the node is a URL item, false otherwise
    */
   nodeIsURI: function PU_nodeIsURI(aNode) {
+    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+      throw new Error("Invalid Places node");
+    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_URI;
   },
 
   /**
    * Determines whether or not a ResultNode is a Query item.
    * @param   aNode
    *          A result node
    * @returns true if the node is a Query item, false otherwise
    */
   nodeIsQuery: function PU_nodeIsQuery(aNode) {
+    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+      throw new Error("Invalid Places node");
+    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY;
   },
 
   /**
    * Generator for a node's ancestors.
    * @param aNode
    *        A result node
    */
@@ -352,16 +367,19 @@ this.PlacesUtils = {
   /**
    * Determines if a node is read only (children cannot be inserted, sometimes
    * they cannot be removed depending on the circumstance)
    * @param   aNode
    *          A result node
    * @returns true if the node is readonly, false otherwise
    */
   nodeIsReadOnly: function PU_nodeIsReadOnly(aNode) {
+    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+      throw new Error("Invalid Places node");
+    }
     let itemId = aNode.itemId;
     if (itemId != -1) {
       return this._readOnly.indexOf(itemId) != -1;
     }
 
     if (this.nodeIsQuery(aNode) &&
         asQuery(aNode).queryOptions.resultType !=
         Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS)
@@ -371,59 +389,71 @@ this.PlacesUtils = {
 
   /**
    * Determines whether or not a ResultNode is a host container.
    * @param   aNode
    *          A result node
    * @returns true if the node is a host container, false otherwise
    */
   nodeIsHost: function PU_nodeIsHost(aNode) {
+    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+      throw new Error("Invalid Places node");
+    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
            aNode.parent &&
            asQuery(aNode.parent).queryOptions.resultType ==
              Ci.nsINavHistoryQueryOptions.RESULTS_AS_SITE_QUERY;
   },
 
   /**
    * Determines whether or not a ResultNode is a day container.
    * @param   node
    *          A NavHistoryResultNode
    * @returns true if the node is a day container, false otherwise
    */
   nodeIsDay: function PU_nodeIsDay(aNode) {
+    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+      throw new Error("Invalid Places node");
+    }
     var resultType;
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
            aNode.parent &&
            ((resultType = asQuery(aNode.parent).queryOptions.resultType) ==
                Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY ||
              resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY);
   },
 
   /**
    * Determines whether or not a result-node is a tag container.
    * @param   aNode
    *          A result-node
    * @returns true if the node is a tag container, false otherwise
    */
   nodeIsTagQuery: function PU_nodeIsTagQuery(aNode) {
+    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+      throw new Error("Invalid Places node");
+    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
            asQuery(aNode).queryOptions.resultType ==
              Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS;
   },
 
   /**
    * Determines whether or not a ResultNode is a container.
    * @param   aNode
    *          A result node
    * @returns true if the node is a container item, false otherwise
    */
   containerTypes: [Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
                    Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT,
                    Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY],
   nodeIsContainer: function PU_nodeIsContainer(aNode) {
+    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
+      throw new Error("Invalid Places node");
+    }
     return this.containerTypes.indexOf(aNode.type) != -1;
   },
 
   /**
    * Determines whether or not a ResultNode is an history related container.
    * @param   node
    *          A result node
    * @returns true if the node is an history related container, false otherwise
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unit/test_PlacesUtils_nodeIsXXX_invalidArg.js
@@ -0,0 +1,24 @@
+
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function run_test() {
+ let nodeIsMethods = [
+  "nodeIsFolder",
+  "nodeIsBookmark",
+  "nodeIsSeparator",
+  "nodeIsURI",
+  "nodeIsQuery",
+  "nodeIsReadOnly",
+  "nodeIsHost",
+  "nodeIsDay",
+  "nodeIsTagQuery",
+  "nodeIsContainer",
+  "nodeIsHistoryContainer",
+  "nodeIsQuery"
+ ];
+ for (let methodName of nodeIsMethods) {
+  Assert.throws(() => PlacesUtils[methodName](true), /Invalid Places node/);
+ }
+}
+
--- a/toolkit/components/places/tests/unit/xpcshell.ini
+++ b/toolkit/components/places/tests/unit/xpcshell.ini
@@ -112,16 +112,17 @@ fail-if = os == "android"
 skip-if = true
 [test_null_interfaces.js]
 [test_onItemChanged_tags.js]
 [test_pageGuid_bookmarkGuid.js]
 [test_frecency_observers.js]
 [test_placeURIs.js]
 [test_PlacesUtils_asyncGetBookmarkIds.js]
 [test_PlacesUtils_lazyobservers.js]
+[test_PlacesUtils_nodeIsXXX_invalidArg.js]
 [test_placesTxn.js]
 [test_preventive_maintenance.js]
 # Bug 676989: test hangs consistently on Android
 skip-if = os == "android"
 [test_preventive_maintenance_checkAndFixDatabase.js]
 # Bug 676989: test hangs consistently on Android
 skip-if = os == "android"
 [test_preventive_maintenance_runTasks.js]
--- a/toolkit/devtools/server/actors/highlighter.js
+++ b/toolkit/devtools/server/actors/highlighter.js
@@ -66,17 +66,21 @@ let HighlighterActor = protocol.ActorCla
 
   get conn() this._inspector && this._inspector.conn,
 
   /**
    * Can the host support the box model highlighter which requires a parent
    * XUL node to attach itself.
    */
   _supportsBoxModelHighlighter: function() {
-    return this._tabActor.browser && !!this._tabActor.browser.parentNode;
+    // Note that <browser>s on Fennec also have a XUL parentNode but the box
+    // model highlighter doesn't display correctly on Fennec (bug 993190)
+    return this._tabActor.browser &&
+           !!this._tabActor.browser.parentNode &&
+           Services.appinfo.ID !== "{aa3c5121-dab2-40e2-81ca-7ea25febc110}";
   },
 
   destroy: function() {
     protocol.Actor.prototype.destroy.call(this);
     if (this._boxModelHighlighter) {
       this._boxModelHighlighter.off("ready", this._highlighterReady);
       this._boxModelHighlighter.off("hide", this._highlighterHidden);
       this._boxModelHighlighter.destroy();
--- a/toolkit/devtools/server/actors/script.js
+++ b/toolkit/devtools/server/actors/script.js
@@ -19,18 +19,19 @@ let addonManager = null;
 
 /**
  * This is a wrapper around amIAddonManager.mapURIToAddonID which always returns
  * false on B2G to avoid loading the add-on manager there and reports any
  * exceptions rather than throwing so that the caller doesn't have to worry
  * about them.
  */
 function mapURIToAddonID(uri, id) {
-  if (Services.appinfo.ID == B2G_ID)
+  if (Services.appinfo.ID == B2G_ID) {
     return false;
+  }
 
   if (!addonManager) {
     addonManager = Cc["@mozilla.org/addons/integration;1"].
                    getService(Ci.amIAddonManager);
   }
 
   try {
     return addonManager.mapURIToAddonID(uri, id);
@@ -4772,29 +4773,56 @@ function AddonThreadActor(aConnect, aHoo
 AddonThreadActor.prototype = Object.create(ThreadActor.prototype);
 
 update(AddonThreadActor.prototype, {
   constructor: AddonThreadActor,
 
   // A constant prefix that will be used to form the actor ID by the server.
   actorPrefix: "addonThread",
 
+  onAttach: function(aRequest) {
+    if (!this.attached) {
+      Services.obs.addObserver(this, "document-element-inserted", false);
+    }
+    return ThreadActor.prototype.onAttach.call(this, aRequest);
+  },
+
+  disconnect: function() {
+    if (this.attached) {
+      Services.obs.removeObserver(this, "document-element-inserted");
+    }
+    return ThreadActor.prototype.disconnect.call(this);
+  },
+
+  /**
+   * Called when a new DOM document element is created. Check if the DOM was
+   * laoded from an add-on and if so make the window a debuggee.
+   */
+  observe: function(aSubject, aTopic, aData) {
+    let id = {};
+    if (mapURIToAddonID(aSubject.documentURIObject, id) && id.value === this.addonID) {
+      this.dbg.addDebuggee(aSubject.defaultView);
+    }
+  },
+
   /**
    * Override the eligibility check for scripts and sources to make
    * sure every script and source with a URL is stored when debugging
    * add-ons.
    */
   _allowSource: function(aSourceURL) {
     // Hide eval scripts
-    if (!aSourceURL)
+    if (!aSourceURL) {
       return false;
+    }
 
     // XPIProvider.jsm evals some code in every add-on's bootstrap.js. Hide it
-    if (aSourceURL == "resource://gre/modules/addons/XPIProvider.jsm")
+    if (aSourceURL == "resource://gre/modules/addons/XPIProvider.jsm") {
       return false;
+    }
 
     return true;
   },
 
   /**
    * An object that will be used by ThreadActors to tailor their
    * behaviour depending on the debugging context being required (chrome,
    * addon or content). The methods that this object provides must
@@ -4831,44 +4859,72 @@ update(AddonThreadActor.prototype, {
   },
 
   /**
    * Checks if the provided global belongs to the debugged add-on.
    *
    * @param aGlobal Debugger.Object
    */
   _checkGlobal: function ADA_checkGlobal(aGlobal) {
+    let obj = null;
+    try {
+      obj = aGlobal.unsafeDereference();
+    }
+    catch (e) {
+      // Because of bug 991399 we sometimes get bad objects here. If we can't
+      // dereference them then they won't be useful to us
+      return false;
+    }
+
     try {
       // This will fail for non-Sandbox objects, hence the try-catch block.
-      let metadata = Cu.getSandboxMetadata(aGlobal.unsafeDereference());
-      if (metadata)
+      let metadata = Cu.getSandboxMetadata(obj);
+      if (metadata) {
         return metadata.addonID === this.addonID;
+      }
     } catch (e) {
     }
 
+    if (obj instanceof Ci.nsIDOMWindow) {
+      let id = {};
+      if (mapURIToAddonID(obj.document.documentURIObject, id)) {
+        return id.value === this.addonID;
+      }
+      return false;
+    }
+
     // Check the global for a __URI__ property and then try to map that to an
     // add-on
     let uridescriptor = aGlobal.getOwnPropertyDescriptor("__URI__");
-    if (uridescriptor && "value" in uridescriptor) {
+    if (uridescriptor && "value" in uridescriptor && uridescriptor.value) {
+      let uri;
       try {
-        let uri = Services.io.newURI(uridescriptor.value, null, null);
-        let id = {};
-        if (mapURIToAddonID(uri, id)) {
-          return id.value === this.addonID;
-        }
+        uri = Services.io.newURI(uridescriptor.value, null, null);
       }
       catch (e) {
-        DevToolsUtils.reportException("AddonThreadActor.prototype._checkGlobal", e);
+        DevToolsUtils.reportException("AddonThreadActor.prototype._checkGlobal",
+                                      new Error("Invalid URI: " + uridescriptor.value));
+        return false;
+      }
+
+      let id = {};
+      if (mapURIToAddonID(uri, id)) {
+        return id.value === this.addonID;
       }
     }
 
     return false;
   }
 });
 
+AddonThreadActor.prototype.requestTypes = Object.create(ThreadActor.prototype.requestTypes);
+update(AddonThreadActor.prototype.requestTypes, {
+  "attach": AddonThreadActor.prototype.onAttach
+});
+
 /**
  * Manages the sources for a thread. Handles source maps, locations in the
  * sources, etc for ThreadActors.
  */
 function ThreadSources(aThreadActor, aUseSourceMaps, aAllowPredicate,
                        aOnNewSource) {
   this._thread = aThreadActor;
   this._useSourceMaps = aUseSourceMaps;
--- a/toolkit/modules/ShortcutUtils.jsm
+++ b/toolkit/modules/ShortcutUtils.jsm
@@ -29,26 +29,26 @@ let ShortcutUtils = {
     * @param boolean aNoCloverLeaf
     *        Pass true to use a descriptive string instead of the cloverleaf symbol. (OS X only)
     * @return string
     *         A prettified and properly separated modifier keys string.
     */
   prettifyShortcut: function(aElemKey, aNoCloverLeaf) {
     let elemString = "";
     let elemMod = aElemKey.getAttribute("modifiers");
+    let haveCloverLeaf = false;
 
     if (elemMod.match("accel")) {
       if (Services.appinfo.OS == "Darwin") {
         // XXX bug 779642 Use "Cmd-" literal vs. cloverleaf meta-key until
         // Orion adds variable height lines.
         if (aNoCloverLeaf) {
           elemString += "Cmd-";
         } else {
-          elemString += PlatformKeys.GetStringFromName("VK_META") +
-            PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+          haveCloverLeaf = true;
         }
       } else {
         elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
           PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
       }
     }
     if (elemMod.match("access")) {
       if (Services.appinfo.OS == "Darwin") {
@@ -75,16 +75,21 @@ let ShortcutUtils = {
       elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
         PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
     }
     if (elemMod.match("meta")) {
       elemString += PlatformKeys.GetStringFromName("VK_META") +
         PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
     }
 
+    if (haveCloverLeaf) {
+      elemString += PlatformKeys.GetStringFromName("VK_META") +
+        PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    }
+
     let key;
     let keyCode = aElemKey.getAttribute("keycode");
     if (keyCode) {
       try {
         // Some keys might not exist in the locale file, which will throw:
         key = Keys.GetStringFromName(keyCode.toUpperCase());
       } catch (ex) {
         Cu.reportError("Error finding " + keyCode + ": " + ex);
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -13,16 +13,20 @@ const Cr = Components.results;
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
                                   "resource://gre/modules/UpdateChannel.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "OS",
+                                  "resource://gre/modules/osfile.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Task",
+                                  "resource://gre/modules/Task.jsm");
 
 const TOOLKIT_ID                      = "toolkit@mozilla.org"
 const KEY_PROFILEDIR                  = "ProfD";
 const KEY_APPDIR                      = "XCurProcD";
 const FILE_BLOCKLIST                  = "blocklist.xml";
 const PREF_BLOCKLIST_LASTUPDATETIME   = "app.update.lastUpdateTime.blocklist-background-update-timer";
 const PREF_BLOCKLIST_URL              = "extensions.blocklist.url";
 const PREF_BLOCKLIST_ITEM_URL         = "extensions.blocklist.itemURL";
@@ -562,47 +566,47 @@ Blocklist.prototype = {
     request.send(null);
 
     // When the blocklist loads we need to compare it to the current copy so
     // make sure we have loaded it.
     if (!this._addonEntries)
       this._loadBlocklist();
   },
 
-  onXMLLoad: function Blocklist_onXMLLoad(aEvent) {
-    var request = aEvent.target;
+  onXMLLoad: Task.async(function* (aEvent) {
+    let request = aEvent.target;
     try {
       gCertUtils.checkCert(request.channel);
     }
     catch (e) {
       LOG("Blocklist::onXMLLoad: " + e);
       return;
     }
-    var responseXML = request.responseXML;
+    let responseXML = request.responseXML;
     if (!responseXML || responseXML.documentElement.namespaceURI == XMLURI_PARSE_ERROR ||
         (request.status != 200 && request.status != 0)) {
       LOG("Blocklist::onXMLLoad: there was an error during load");
       return;
     }
-    var blocklistFile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
-    if (blocklistFile.exists())
-      blocklistFile.remove(false);
-    var fos = FileUtils.openSafeFileOutputStream(blocklistFile);
-    fos.write(request.responseText, request.responseText.length);
-    FileUtils.closeSafeFileOutputStream(fos);
 
     var oldAddonEntries = this._addonEntries;
     var oldPluginEntries = this._pluginEntries;
     this._addonEntries = [];
     this._pluginEntries = [];
-    this._loadBlocklistFromFile(FileUtils.getFile(KEY_PROFILEDIR,
-                                                  [FILE_BLOCKLIST]));
+
+    this._loadBlocklistFromString(request.responseText);
+    this._blocklistUpdated(oldAddonEntries, oldPluginEntries);
 
-    this._blocklistUpdated(oldAddonEntries, oldPluginEntries);
-  },
+    try {
+      let path = OS.Path.join(OS.Constants.Path.profileDir, FILE_BLOCKLIST);
+      yield OS.File.writeAtomic(path, request.responseText, {tmpPath: path + ".tmp"});
+    } catch (e) {
+      LOG("Blocklist::onXMLLoad: " + e);
+    }
+  }),
 
   onXMLError: function Blocklist_onXMLError(aEvent) {
     try {
       var request = aEvent.target;
       // the following may throw (e.g. a local file or timeout)
       var status = request.status;
     }
     catch (e) {
@@ -699,27 +703,56 @@ Blocklist.prototype = {
 
   _loadBlocklistFromFile: function Blocklist_loadBlocklistFromFile(file) {
     if (!gBlocklistEnabled) {
       LOG("Blocklist::_loadBlocklistFromFile: blocklist is disabled");
       return;
     }
 
     if (!file.exists()) {
-      LOG("Blocklist::_loadBlocklistFromFile: XML File does not exist");
+      LOG("Blocklist::_loadBlocklistFromFile: XML File does not exist " + file.path);
       return;
     }
 
-    var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
-                               .createInstance(Components.interfaces.nsIFileInputStream);
-    fileStream.init(file, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
+    let text = "";
+    let fstream = null;
+    let cstream = null;
+
+    try {
+      fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
+                          .createInstance(Components.interfaces.nsIFileInputStream);
+      cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
+                          .createInstance(Components.interfaces.nsIConverterInputStream);
+
+      fstream.init(file, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
+      cstream.init(fstream, "UTF-8", 0, 0);
+
+      let (str = {}) {
+        let read = 0;
+
+        do {
+          read = cstream.readString(0xffffffff, str); // read as much as we can and put it in str.value
+          text += str.value;
+        } while (read != 0);
+      }
+    } catch (e) {
+      LOG("Blocklist::_loadBlocklistFromFile: Failed to load XML file " + e);
+    } finally {
+      cstream.close();
+      fstream.close();
+    }
+
+    text && this._loadBlocklistFromString(text);
+  },
+
+  _loadBlocklistFromString : function Blocklist_loadBlocklistFromString(text) {
     try {
       var parser = Cc["@mozilla.org/xmlextras/domparser;1"].
                    createInstance(Ci.nsIDOMParser);
-      var doc = parser.parseFromStream(fileStream, "UTF-8", file.fileSize, "text/xml");
+      var doc = parser.parseFromString(text, "text/xml");
       if (doc.documentElement.namespaceURI != XMLURI_BLOCKLIST) {
         LOG("Blocklist::_loadBlocklistFromFile: aborting due to incorrect " +
             "XML Namespace.\r\nExpected: " + XMLURI_BLOCKLIST + "\r\n" +
             "Received: " + doc.documentElement.namespaceURI);
         return;
       }
 
       var childNodes = doc.documentElement.childNodes;
@@ -741,17 +774,16 @@ Blocklist.prototype = {
                                        null);
         }
       }
     }
     catch (e) {
       LOG("Blocklist::_loadBlocklistFromFile: Error constructing blocklist " + e);
       return;
     }
-    fileStream.close();
   },
 
   _processItemNodes: function Blocklist_processItemNodes(itemNodes, prefix, handler) {
     var result = [];
     var itemName = prefix + "Item";
     for (var i = 0; i < itemNodes.length; ++i) {
       var blocklistElement = itemNodes.item(i);
       if (!(blocklistElement instanceof Ci.nsIDOMElement) ||
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -189,19 +189,16 @@ nsWindow::DoDraw(void)
         LOG("  no window to draw, bailing");
         return;
     }
 
     nsWindow *targetWindow = (nsWindow *)sTopWindows[0];
     while (targetWindow->GetLastChild())
         targetWindow = (nsWindow *)targetWindow->GetLastChild();
 
-    nsIntRegion region = sTopWindows[0]->mDirtyRegion;
-    sTopWindows[0]->mDirtyRegion.SetEmpty();
-
     nsIWidgetListener* listener = targetWindow->GetWidgetListener();
     if (listener) {
         listener->WillPaintWindow(targetWindow);
     }
 
     LayerManager* lm = targetWindow->GetLayerManager();
     if (mozilla::layers::LayersBackend::LAYERS_CLIENT == lm->GetBackendType()) {
       // No need to do anything, the compositor will handle drawing
@@ -211,33 +208,33 @@ nsWindow::DoDraw(void)
 
         if(sUsingOMTC)
             targetSurface = sOMTCSurface;
         else
             targetSurface = Framebuffer::BackBuffer();
 
         {
             nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
-            gfxUtils::PathFromRegion(ctx, region);
+            gfxUtils::PathFromRegion(ctx, sVirtualBounds);
             ctx->Clip();
 
             // No double-buffering needed.
             AutoLayerManagerSetup setupLayerManager(
                 targetWindow, ctx, mozilla::layers::BufferMode::BUFFER_NONE,
                 ScreenRotation(EffectiveScreenRotation()));
 
             listener = targetWindow->GetWidgetListener();
             if (listener) {
-                listener->PaintWindow(targetWindow, region);
+                listener->PaintWindow(targetWindow, sVirtualBounds);
             }
         }
 
         if (!sUsingOMTC) {
             targetSurface->Flush();
-            Framebuffer::Present(region);
+            Framebuffer::Present(sVirtualBounds);
         }
     } else {
         NS_RUNTIMEABORT("Unexpected layer manager type");
     }
 
     listener = targetWindow->GetWidgetListener();
     if (listener) {
         listener->DidPaintWindow();
@@ -420,17 +417,16 @@ NS_IMETHODIMP
 nsWindow::Invalidate(const nsIntRect &aRect)
 {
     nsWindow *top = mParent;
     while (top && top->mParent)
         top = top->mParent;
     if (top != sTopWindows[0] && this != sTopWindows[0])
         return NS_OK;
 
-    mDirtyRegion.Or(mDirtyRegion, aRect);
     gDrawRequest = true;
     mozilla::NotifyEvent();
     return NS_OK;
 }
 
 nsIntPoint
 nsWindow::WidgetToScreenOffset()
 {
--- a/widget/gonk/nsWindow.h
+++ b/widget/gonk/nsWindow.h
@@ -112,17 +112,16 @@ public:
     virtual nsIntRect GetNaturalBounds() MOZ_OVERRIDE;
     virtual bool NeedsPaint();
 
     virtual Composer2D* GetComposer2D() MOZ_OVERRIDE;
 
 protected:
     nsWindow* mParent;
     bool mVisible;
-    nsIntRegion mDirtyRegion;
     InputContext mInputContext;
     nsCOMPtr<nsIIdleServiceInternal> mIdleService;
 
     void BringToTop();
 
     // Call this function when the users activity is the direct cause of an
     // event (like a keypress or mouse click).
     void UserActivity();