merge fx-team to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 28 Oct 2014 15:20:23 +0100
changeset 212554 a2d58c6420f41a1a57d2e6b688d6a7a07a27810e
parent 212542 ab91b8407313ec6a230631f656a96ca0f969b669 (current diff)
parent 212553 9d42e896570c1b5494f29846a20c5ab097b5b112 (diff)
child 212646 c0ddb1b098ec15b8d8cc68c08c1b20f65465c9f4
push id27720
push usercbook@mozilla.com
push dateTue, 28 Oct 2014 14:51:21 +0000
treeherdermozilla-central@a2d58c6420f4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge fx-team to mozilla-central a=merge
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1381,16 +1381,18 @@ pref("devtools.timeline.enabled", false)
 
 // Enable perftools via build command
 #ifdef MOZ_DEVTOOLS_PERFTOOLS
   pref("devtools.performance_dev.enabled", true);
 #else
   pref("devtools.performance_dev.enabled", false);
 #endif
 
+pref("devtools.performance.ui.show-timeline-memory", false);
+
 // The default Profiler UI settings
 pref("devtools.profiler.ui.show-platform-data", false);
 
 // The default cache UI setting
 pref("devtools.cache.disabled", false);
 
 // Enable the Network Monitor
 pref("devtools.netmonitor.enabled", true);
--- a/browser/devtools/main.js
+++ b/browser/devtools/main.js
@@ -380,17 +380,17 @@ Tools.webAudioEditor = {
   icon: "chrome://browser/skin/devtools/tool-webaudio.svg",
   invertIconForLightTheme: true,
   url: "chrome://browser/content/devtools/webaudioeditor.xul",
   label: l10n("ToolboxWebAudioEditor1.label", webAudioEditorStrings),
   panelLabel: l10n("ToolboxWebAudioEditor1.panelLabel", webAudioEditorStrings),
   tooltip: l10n("ToolboxWebAudioEditor1.tooltip", webAudioEditorStrings),
 
   isTargetSupported: function(target) {
-    return !target.isAddon && !target.chrome;
+    return !target.isAddon && !target.chrome && target.hasActor("webaudio");
   },
 
   build: function(iframeWindow, toolbox) {
     return new WebAudioEditorPanel(iframeWindow, toolbox);
   }
 };
 
 Tools.scratchpad = {
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/modules/front.js
@@ -0,0 +1,322 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const { Cc, Ci, Cu, Cr } = require("chrome");
+const { extend } = require("sdk/util/object");
+const { Task } = require("resource://gre/modules/Task.jsm");
+
+loader.lazyRequireGetter(this, "Services");
+loader.lazyRequireGetter(this, "promise");
+loader.lazyRequireGetter(this, "EventEmitter",
+  "devtools/toolkit/event-emitter");
+loader.lazyRequireGetter(this, "TimelineFront",
+  "devtools/server/actors/timeline", true);
+loader.lazyRequireGetter(this, "DevToolsUtils",
+  "devtools/toolkit/DevToolsUtils");
+
+loader.lazyImporter(this, "gDevTools",
+  "resource:///modules/devtools/gDevTools.jsm");
+
+let showTimelineMemory = () => Services.prefs.getBoolPref("devtools.performance.ui.show-timeline-memory");
+
+/**
+ * A cache of all PerformanceActorsConnection instances. The keys are Target objects.
+ */
+let SharedPerformanceActors = new WeakMap();
+
+/**
+ * Instantiates a shared PerformanceActorsConnection for the specified target.
+ * Consumers must yield on `open` to make sure the connection is established.
+ *
+ * @param Target target
+ *        The target owning this connection.
+ */
+SharedPerformanceActors.forTarget = function(target) {
+  if (this.has(target)) {
+    return this.get(target);
+  }
+
+  let instance = new PerformanceActorsConnection(target);
+  this.set(target, instance);
+  return instance;
+};
+
+/**
+ * A connection to underlying actors (profiler, memory, framerate, etc)
+ * shared by all tools in a target.
+ *
+ * Use `SharedPerformanceActors.forTarget` to make sure you get the same
+ * instance every time, and the `PerformanceFront` to start/stop recordings.
+ *
+ * @param Target target
+ *        The target owning this connection.
+ */
+function PerformanceActorsConnection(target) {
+  EventEmitter.decorate(this);
+
+  this._target = target;
+  this._client = this._target.client;
+  this._request = this._request.bind(this);
+
+  Services.obs.notifyObservers(null, "performance-actors-connection-created", null);
+}
+
+PerformanceActorsConnection.prototype = {
+
+  /**
+   * Initializes a connection to the profiler and other miscellaneous actors.
+   * If already open, nothing happens.
+   *
+   * @return object
+   *         A promise that is resolved once the connection is established.
+   */
+  open: Task.async(function*() {
+    if (this._connected) {
+      return;
+    }
+
+    // Local debugging needs to make the target remote.
+    yield this._target.makeRemote();
+
+    // Sets `this._profiler`
+    yield this._connectProfilerActor();
+
+    // Sets or shims `this._timeline`
+    yield this._connectTimelineActor();
+
+    this._connected = true;
+
+    Services.obs.notifyObservers(null, "performance-actors-connection-opened", null);
+  }),
+
+  /**
+   * Destroys this connection.
+   */
+  destroy: function () {
+    this._disconnectActors();
+    this._connected = false;
+  },
+
+  /**
+   * Initializes a connection to the profiler actor.
+   */
+  _connectProfilerActor: Task.async(function*() {
+    // Chrome debugging targets have already obtained a reference
+    // to the profiler actor.
+    if (this._target.chrome) {
+      this._profiler = this._target.form.profilerActor;
+    }
+    // Or when we are debugging content processes, we already have the tab
+    // specific one. Use it immediately.
+    else if (this._target.form && this._target.form.profilerActor) {
+      this._profiler = this._target.form.profilerActor;
+    }
+    // Check if we already have a grip to the `listTabs` response object
+    // and, if we do, use it to get to the profiler actor.
+    else if (this._target.root && this._target.root.profilerActor) {
+      this._profiler = this._target.root.profilerActor;
+    }
+    // Otherwise, call `listTabs`.
+    else {
+      this._profiler = (yield listTabs(this._client)).profilerActor;
+    }
+  }),
+
+  /**
+   * Initializes a connection to a timeline actor.
+   */
+  _connectTimelineActor: function() {
+    // Only initialize the timeline front if the respective actor is available.
+    // Older Gecko versions don't have an existing implementation, in which case
+    // all the methods we need can be easily mocked.
+    //
+    // If the timeline actor exists, all underlying actors (memory, framerate) exist,
+    // with the expected methods and behaviour. If using the Performance tool,
+    // and timeline actor does not exist (FxOS devices < Gecko 35),
+    // then just use the mocked actor and do not display timeline data.
+    //
+    // TODO use framework level feature detection from bug 1069673
+    if (this._target.form && this._target.form.timelineActor) {
+      this._timeline = new TimelineFront(this._target.client, this._target.form);
+    } else {
+      this._timeline = {
+        start: () => {},
+        stop: () => {},
+        isRecording: () => false,
+        on: () => {},
+        off: () => {},
+        destroy: () => {}
+      };
+    }
+  },
+
+  /**
+   * Closes the connections to non-profiler actors.
+   */
+  _disconnectActors: function () {
+    this._timeline.destroy();
+  },
+
+  /**
+   * Sends the request over the remote debugging protocol to the
+   * specified actor.
+   *
+   * @param string actor
+   *        The designated actor. Currently supported: "profiler", "timeline".
+   * @param string method
+   *        Method to call on the backend.
+   * @param any args [optional]
+   *        Additional data or arguments to send with the request.
+   * @return object
+   *         A promise resolved with the response once the request finishes.
+   */
+  _request: function(actor, method, ...args) {
+    // Handle requests to the profiler actor.
+    if (actor == "profiler") {
+      let deferred = promise.defer();
+      let data = args[0] || {};
+      data.to = this._profiler;
+      data.type = method;
+      this._client.request(data, deferred.resolve);
+      return deferred.promise;
+    }
+
+    // Handle requests to the timeline actor.
+    if (actor == "timeline") {
+      return this._timeline[method].apply(this._timeline, args);
+    }
+  }
+};
+
+/**
+ * A thin wrapper around a shared PerformanceActorsConnection for the parent target.
+ * Handles manually starting and stopping a recording.
+ *
+ * @param PerformanceActorsConnection connection
+ *        The shared instance for the parent target.
+ */
+function PerformanceFront(connection) {
+  EventEmitter.decorate(this);
+
+  this._request = connection._request;
+
+  // Pipe events from TimelineActor to the PerformanceFront
+  connection._timeline.on("markers", markers => this.emit("markers", markers));
+  connection._timeline.on("memory", (delta, measurement) => this.emit("memory", delta, measurement));
+  connection._timeline.on("ticks", (delta, timestamps) => this.emit("ticks", delta, timestamps));
+}
+
+PerformanceFront.prototype = {
+  /**
+   * Manually begins a recording session.
+   *
+   * @return object
+   *         A promise that is resolved once recording has started.
+   */
+  startRecording: Task.async(function*() {
+    let { isActive, currentTime } = yield this._request("profiler", "isActive");
+
+    // Start the profiler only if it wasn't already active. The built-in
+    // nsIPerformance module will be kept recording, because it's the same instance
+    // for all targets and interacts with the whole platform, so we don't want
+    // to affect other clients by stopping (or restarting) it.
+    if (!isActive) {
+      // Extend the options so that protocol.js doesn't modify
+      // the source object.
+      let options = extend({}, this._customPerformanceOptions);
+      yield this._request("profiler", "startProfiler", options);
+      this._profilingStartTime = 0;
+      this.emit("profiler-activated");
+    } else {
+      this._profilingStartTime = currentTime;
+      this.emit("profiler-already-active");
+    }
+
+    // The timeline actor is target-dependent, so just make sure
+    // it's recording.
+    let withMemory = showTimelineMemory();
+    yield this._request("timeline", "start", { withTicks: true, withMemory: withMemory });
+  }),
+
+  /**
+   * Manually ends the current recording session.
+   *
+   * @return object
+   *         A promise that is resolved once recording has stopped,
+   *         with the profiler and timeline data.
+   */
+  stopRecording: Task.async(function*() {
+    // We'll need to filter out all samples that fall out of current profile's
+    // range. This is necessary because the profiler is continuously running.
+    let profilerData = yield this._request("profiler", "getProfile");
+    filterSamples(profilerData, this._profilingStartTime);
+    offsetSampleTimes(profilerData, this._profilingStartTime);
+
+    yield this._request("timeline", "stop");
+
+    // Join all the acquired data and return it for outside consumers.
+    return {
+      recordingDuration: profilerData.currentTime - this._profilingStartTime,
+      profilerData: profilerData
+    };
+  }),
+
+  /**
+   * Overrides the options sent to the built-in profiler module when activating,
+   * such as the maximum entries count, the sampling interval etc.
+   *
+   * Used in tests and for older backend implementations.
+   */
+  _customPerformanceOptions: {
+    entries: 1000000,
+    interval: 1,
+    features: ["js"]
+  }
+};
+
+/**
+ * Filters all the samples in the provided profiler data to be more recent
+ * than the specified start time.
+ *
+ * @param object profilerData
+ *        The profiler data received from the backend.
+ * @param number profilingStartTime
+ *        The earliest acceptable sample time (in milliseconds).
+ */
+function filterSamples(profilerData, profilingStartTime) {
+  let firstThread = profilerData.profile.threads[0];
+
+  firstThread.samples = firstThread.samples.filter(e => {
+    return e.time >= profilingStartTime;
+  });
+}
+
+/**
+ * Offsets all the samples in the provided profiler data by the specified time.
+ *
+ * @param object profilerData
+ *        The profiler data received from the backend.
+ * @param number timeOffset
+ *        The amount of time to offset by (in milliseconds).
+ */
+function offsetSampleTimes(profilerData, timeOffset) {
+  let firstThreadSamples = profilerData.profile.threads[0].samples;
+
+  for (let sample of firstThreadSamples) {
+    sample.time -= timeOffset;
+  }
+}
+
+/**
+ * A collection of small wrappers promisifying functions invoking callbacks.
+ */
+function listTabs(client) {
+  let deferred = promise.defer();
+  client.listTabs(deferred.resolve);
+  return deferred.promise;
+}
+
+exports.getPerformanceActorsConnection = target => SharedPerformanceActors.forTarget(target);
+exports.PerformanceFront = PerformanceFront;
--- a/browser/devtools/performance/moz.build
+++ b/browser/devtools/performance/moz.build
@@ -1,8 +1,11 @@
 # 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/.
 
 EXTRA_JS_MODULES.devtools.performance += [
+    'modules/front.js',
     'panel.js'
 ]
+
+BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
--- a/browser/devtools/performance/panel.js
+++ b/browser/devtools/performance/panel.js
@@ -1,16 +1,17 @@
 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
+const { PerformanceFront, getPerformanceActorsConnection } = require("devtools/performance/front");
 
 Cu.import("resource://gre/modules/Task.jsm");
 
 loader.lazyRequireGetter(this, "promise");
 loader.lazyRequireGetter(this, "EventEmitter",
   "devtools/toolkit/event-emitter");
 
 function PerformancePanel(iframeWindow, toolbox) {
@@ -22,26 +23,27 @@ function PerformancePanel(iframeWindow, 
 
 exports.PerformancePanel = PerformancePanel;
 
 PerformancePanel.prototype = {
   /**
    * Open is effectively an asynchronous constructor.
    *
    * @return object
-   *         A promise that is resolved when the Profiler completes opening.
+   *         A promise that is resolved when the Performance tool
+   *         completes opening.
    */
   open: Task.async(function*() {
     this.panelWin.gToolbox = this._toolbox;
     this.panelWin.gTarget = this.target;
 
-    // Mock Front for now
-    let gFront = {};
-    EventEmitter.decorate(gFront);
-    this.panelWin.gFront = gFront;
+    this._connection = getPerformanceActorsConnection(this.target);
+    yield this._connection.open();
+
+    this.panelWin.gFront = new PerformanceFront(this._connection);
 
     yield this.panelWin.startupPerformance();
 
     this.isReady = true;
     this.emit("ready");
     return this;
   }),
 
@@ -50,13 +52,16 @@ PerformancePanel.prototype = {
   get target() this._toolbox.target,
 
   destroy: Task.async(function*() {
     // Make sure this panel is not already destroyed.
     if (this._destroyed) {
       return;
     }
 
+    // Destroy the connection to ensure packet handlers are removed from client.
+    this._connection.destroy();
+
     yield this.panelWin.shutdownPerformance();
     this.emit("destroyed");
     this._destroyed = true;
   })
 };
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser.ini
@@ -0,0 +1,30 @@
+[DEFAULT]
+skip-if = e10s # Handle in Bug 1077464 for profiler
+subsuite = devtools
+support-files =
+  doc_simple-test.html
+  head.js
+
+# Commented out tests are profiler tests
+# that need to be moved over to performance tool
+
+[browser_perf-aaa-run-first-leaktest.js]
+[browser_perf-front-basic-timeline-01.js]
+[browser_perf-front-basic-profiler-01.js]
+# bug 1077464
+#[browser_perf-front-profiler-01.js]
+[browser_perf-front-profiler-02.js]
+[browser_perf-front-profiler-03.js]
+[browser_perf-front-profiler-04.js]
+# bug 1077464
+#[browser_perf-front-profiler-05.js]
+# bug 1077464
+#[browser_perf-front-profiler-06.js]
+# needs shared connection with profiler's shared connection
+#[browser_perf-shared-connection-01.js]
+[browser_perf-shared-connection-02.js]
+[browser_perf-shared-connection-03.js]
+# bug 1077464
+#[browser_perf-shared-connection-04.js]
+[browser_perf-data-samples.js]
+[browser_perf-data-massaging-01.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-aaa-run-first-leaktest.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the performance tool leaks on initialization and sudden destruction.
+ * You can also use this initialization format as a template for other tests.
+ */
+
+function spawnTest () {
+  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
+
+  ok(target, "Should have a target available.");
+  ok(toolbox, "Should have a toolbox available.");
+  ok(panel, "Should have a panel available.");
+
+  ok(panel.panelWin.gToolbox, "Should have a toolbox reference on the panel window.");
+  ok(panel.panelWin.gTarget, "Should have a target reference on the panel window.");
+  ok(panel.panelWin.gFront, "Should have a front reference on the panel window.");
+
+  yield teardown(panel);
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-data-massaging-01.js
@@ -0,0 +1,63 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the retrieved profiler data samples are correctly filtered and
+ * normalized before passed to consumers.
+ */
+
+const WAIT_TIME = 1000; // ms
+
+function spawnTest () {
+  let { panel } = yield initPerformance(SIMPLE_URL);
+  let front = panel.panelWin.gFront;
+
+  // Perform the first recording...
+
+  yield front.startRecording();
+  let profilingStartTime = front._profilingStartTime;
+  info("Started profiling at: " + profilingStartTime);
+
+  busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity
+
+  let firstRecordingData = yield front.stopRecording();
+  let firstRecordingFinishTime = firstRecordingData.profilerData.currentTime;
+
+  is(profilingStartTime, 0,
+    "The profiling start time should be 0 for the first recording.");
+  ok(firstRecordingData.recordingDuration >= WAIT_TIME,
+    "The first recording duration is correct.");
+  ok(firstRecordingFinishTime >= WAIT_TIME,
+    "The first recording finish time is correct.");
+
+  // Perform the second recording...
+
+  yield front.startRecording();
+  profilingStartTime = front._profilingStartTime;
+  info("Started profiling at: " + profilingStartTime);
+
+  busyWait(WAIT_TIME); // allow the profiler module to sample more cpu activity
+
+  let secondRecordingData = yield front.stopRecording();
+  let secondRecordingFinishTime = secondRecordingData.profilerData.currentTime;
+  let secondRecordingProfile = secondRecordingData.profilerData.profile;
+  let secondRecordingSamples = secondRecordingProfile.threads[0].samples;
+
+  isnot(profilingStartTime, 0,
+    "The profiling start time should not be 0 on the second recording.");
+  ok(secondRecordingData.recordingDuration >= WAIT_TIME,
+    "The second recording duration is correct.");
+  ok(secondRecordingFinishTime - firstRecordingFinishTime >= WAIT_TIME,
+    "The second recording finish time is correct.");
+
+  ok(secondRecordingSamples[0].time < profilingStartTime,
+    "The second recorded sample times were normalized.");
+  ok(secondRecordingSamples[0].time > 0,
+    "The second recorded sample times were normalized correctly.");
+  ok(!secondRecordingSamples.find(e => e.time + profilingStartTime <= firstRecordingFinishTime),
+    "There should be no samples from the first recording in the second one, " +
+    "even though the total number of frames did not overflow.");
+
+  yield teardown(panel);
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-data-samples.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the retrieved profiler data samples always have a (root) node.
+ * If this ever changes, the |ThreadNode.prototype.insert| function in
+ * browser/devtools/profiler/utils/tree-model.js will have to be changed.
+ */
+
+const WAIT_TIME = 1000; // ms
+
+function spawnTest () {
+  let { panel } = yield initPerformance(SIMPLE_URL);
+  let front = panel.panelWin.gFront;
+
+  yield front.startRecording();
+  busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity
+
+  let recordingData = yield front.stopRecording();
+  let profile = recordingData.profilerData.profile;
+
+  for (let thread of profile.threads) {
+    info("Checking thread: " + thread.name);
+
+    for (let sample of thread.samples) {
+      if (sample.frames[0].location != "(root)") {
+        ok(false, "The sample " + sample.toSource() + " doesn't have a root node.");
+      }
+    }
+  }
+
+  yield teardown(panel);
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-front-basic-profiler-01.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test basic functionality of PerformanceFront
+ */
+
+let WAIT = 1000;
+
+function spawnTest () {
+  let { target, front } = yield initBackend(SIMPLE_URL);
+
+  yield front.startRecording();
+
+  yield busyWait(WAIT);
+
+  let { recordingDuration, profilerData } = yield front.stopRecording();
+
+  ok(recordingDuration > 500, "recordingDuration exists");
+  ok(profilerData, "profilerData exists");
+
+  yield removeTab(target.tab);
+  finish();
+
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-front-basic-timeline-01.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test basic functionality of PerformanceFront, retrieving timeline data.
+ */
+
+function spawnTest () {
+  Services.prefs.setBoolPref("devtools.performance.ui.show-timeline-memory", true);
+
+  let { target, front } = yield initBackend(SIMPLE_URL);
+
+  let lastMemoryDelta = 0;
+  let lastTickDelta = 0;
+
+  let counters = {
+    markers: [],
+    memory: [],
+    ticks: []
+  };
+
+  let deferreds = {
+    markers: Promise.defer(),
+    memory: Promise.defer(),
+    ticks: Promise.defer()
+  }
+
+  front.on("markers", handler);
+  front.on("memory", handler);
+  front.on("ticks", handler);
+
+  yield front.startRecording();
+
+  yield Promise.all(Object.keys(deferreds).map(type => deferreds[type].promise));
+
+  yield front.stopRecording();
+
+  is(counters.markers.length, 1, "one marker event fired.");
+  is(counters.memory.length, 3, "three memory events fired.");
+  is(counters.ticks.length, 3, "three ticks events fired.");
+
+  yield removeTab(target.tab);
+  finish();
+
+  function handler (name, ...args) {
+    if (name === "memory") {
+      let [delta, measurement] = args;
+      is(typeof delta, "number", "received `delta` in memory event");
+      ok(delta > lastMemoryDelta, "received `delta` in memory event");
+      ok(measurement.total, "received `total` in memory event");
+      ok(measurement.domSize, "received `domSize` in memory event");
+      ok(measurement.jsObjectsSize, "received `jsObjectsSize` in memory event");
+
+      counters.memory.push({ delta: delta, measurement: measurement });
+      lastMemoryDelta = delta;
+    } else if (name === "ticks") {
+      let [delta, timestamps] = args;
+      ok(delta > lastTickDelta, "received `delta` in ticks event");
+
+      // First tick doesn't contain any timestamps
+      if (counters.ticks.length) {
+        ok(timestamps.length, "received `timestamps` in ticks event");
+      }
+
+      counters.ticks.push({ delta: delta, timestamps: timestamps});
+      lastTickDelta = delta;
+    } else if (name === "markers") {
+      let [markers] = args;
+      ok(markers[0].start, "received atleast one marker with `start`");
+      ok(markers[0].end, "received atleast one marker with `end`");
+      ok(markers[0].name, "received atleast one marker with `name`");
+      counters.markers.push(markers);
+      front.off(name, handler);
+      deferreds[name].resolve();
+    } else {
+      throw new Error("unknown event");
+    }
+
+    if (name !== "markers" && counters[name].length === 3) {
+      front.off(name, handler);
+      deferreds[name].resolve();
+    }
+  };
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-front-profiler-02.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the profiler connection front does not activate the built-in
+ * profiler module if not necessary, and doesn't deactivate it when
+ * a recording is stopped.
+ */
+
+let test = Task.async(function*() {
+  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
+  let front = panel.panelWin.gFront;
+
+  ok(!nsIProfilerModule.IsActive(),
+    "The built-in profiler module should not have been automatically started.");
+
+  let activated = front.once("profiler-activated");
+  yield front.startRecording();
+  yield activated;
+  yield front.stopRecording();
+  ok(nsIProfilerModule.IsActive(),
+    "The built-in profiler module should still be active (1).");
+
+  let alreadyActive = front.once("profiler-already-active");
+  yield front.startRecording();
+  yield alreadyActive;
+  yield front.stopRecording();
+  ok(nsIProfilerModule.IsActive(),
+    "The built-in profiler module should still be active (2).");
+
+  yield teardown(panel);
+
+  ok(!nsIProfilerModule.IsActive(),
+    "The built-in profiler module should have been automatically stoped.");
+
+  finish();
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-front-profiler-03.js
@@ -0,0 +1,33 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the built-in profiler module doesn't deactivate when the toolbox
+ * is destroyed if there are other consumers using it.
+ */
+
+let test = Task.async(function*() {
+  let { panel: firstPanel } = yield initPerformance(SIMPLE_URL);
+  let firstFront = firstPanel.panelWin.gFront;
+
+  let activated = firstFront.once("profiler-activated");
+  yield firstFront.startRecording();
+  yield activated;
+
+  let { panel: secondPanel } = yield initPerformance(SIMPLE_URL);
+  let secondFront = secondPanel.panelWin.gFront;
+
+  let alreadyActive = secondFront.once("profiler-already-active");
+  yield secondFront.startRecording();
+  yield alreadyActive;
+
+  yield teardown(firstPanel);
+  ok(nsIProfilerModule.IsActive(),
+    "The built-in profiler module should still be active.");
+
+  yield teardown(secondPanel);
+  ok(!nsIProfilerModule.IsActive(),
+    "The built-in profiler module should have been automatically stoped.");
+
+  finish();
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-front-profiler-04.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the built-in profiler module is not reactivated if no other
+ * consumer was using it over the remote debugger protocol, and ensures
+ * that the actor will work properly even in such cases (e.g. the Gecko Profiler
+ * addon was installed and automatically activated the profiler module).
+ */
+
+let test = Task.async(function*() {
+  // Ensure the profiler is already running when the test starts.
+  let ENTRIES = 1000000;
+  let INTERVAL = 1;
+  let FEATURES = ["js"];
+  nsIProfilerModule.StartProfiler(ENTRIES, INTERVAL, FEATURES, FEATURES.length);
+
+  let { panel: firstPanel } = yield initPerformance(SIMPLE_URL);
+  let firstFront = firstPanel.panelWin.gFront;
+
+  let alredyActive = firstFront.once("profiler-already-active");
+  yield firstFront.startRecording();
+  yield alredyActive;
+  ok(firstFront._profilingStartTime > 0, "The profiler was not restarted.");
+
+  let { panel: secondPanel } = yield initPerformance(SIMPLE_URL);
+  let secondFront = secondPanel.panelWin.gFront;
+
+  let alreadyActive = secondFront.once("profiler-already-active");
+  yield secondFront.startRecording();
+  yield alreadyActive;
+  ok(secondFront._profilingStartTime > 0, "The profiler was not restarted.");
+
+  yield teardown(firstPanel);
+  ok(nsIProfilerModule.IsActive(),
+    "The built-in profiler module should still be active.");
+
+  yield teardown(secondPanel);
+  ok(!nsIProfilerModule.IsActive(),
+    "The built-in profiler module should have been automatically stoped.");
+
+  finish();
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-shared-connection-02.js
@@ -0,0 +1,39 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the shared PerformanceActorsConnection is only opened once.
+ */
+
+let gProfilerConnectionsOpened = 0;
+Services.obs.addObserver(profilerConnectionObserver, "performance-actors-connection-opened", false);
+
+function spawnTest () {
+  let { target, panel } = yield initPerformance(SIMPLE_URL);
+
+  is(gProfilerConnectionsOpened, 1,
+    "Only one profiler connection was opened.");
+
+  let sharedConnection = getPerformanceActorsConnection(target);
+
+  ok(sharedConnection,
+    "A shared profiler connection for the current toolbox was retrieved.");
+  is(sharedConnection._request, panel.panelWin.gFront._request,
+    "The same shared profiler connection is used by the panel's front.");
+
+  yield sharedConnection.open();
+  is(gProfilerConnectionsOpened, 1,
+    "No additional profiler connections were opened.");
+
+  yield teardown(panel);
+  finish();
+}
+
+function profilerConnectionObserver(subject, topic, data) {
+  is(topic, "performance-actors-connection-opened", "The correct topic was observed.");
+  gProfilerConnectionsOpened++;
+}
+
+registerCleanupFunction(() => {
+  Services.obs.removeObserver(profilerConnectionObserver, "performance-actors-connection-opened");
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-shared-connection-03.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the shared PerformanceActorsConnection can properly send requests.
+ */
+
+function spawnTest () {
+  let { panel } = yield initPerformance(SIMPLE_URL);
+  let front = panel.panelWin.gFront;
+
+  ok(!nsIProfilerModule.IsActive(),
+    "The built-in profiler module should not have been automatically started.");
+
+  let result = yield front._request("profiler", "startProfiler");
+  is(result.started, true,
+    "The request finished successfully and the profiler should've been started.");
+  ok(nsIProfilerModule.IsActive(),
+    "The built-in profiler module should now be active.");
+
+  result = yield front._request("profiler", "stopProfiler");
+  is(result.started, false,
+    "The request finished successfully and the profiler should've been stopped.");
+  ok(!nsIProfilerModule.IsActive(),
+    "The built-in profiler module should now be inactive.");
+
+  yield teardown(panel);
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/doc_simple-test.html
@@ -0,0 +1,22 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>Profiler test page</title>
+  </head>
+
+  <body>
+    <script type="text/javascript">
+      function test() {
+        var a = "Hello world!";
+      }
+
+      // Prevent this script from being garbage collected.
+      window.setInterval(test, 1);
+    </script>
+  </body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/head.js
@@ -0,0 +1,209 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+
+// Enable logging for all the tests. Both the debugger server and frontend will
+// be affected by this pref.
+let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
+Services.prefs.setBoolPref("devtools.debugger.log", false);
+
+let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
+let { Promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
+let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
+let { DevToolsUtils } = Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm", {});
+let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
+let { getPerformanceActorsConnection, PerformanceFront } = devtools.require("devtools/performance/front");
+let nsIProfilerModule = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
+let TargetFactory = devtools.TargetFactory;
+let mm = null;
+
+const FRAME_SCRIPT_UTILS_URL = "chrome://browser/content/devtools/frame-script-utils.js"
+const EXAMPLE_URL = "http://example.com/browser/browser/devtools/performance/test/";
+const SIMPLE_URL = EXAMPLE_URL + "doc_simple-test.html";
+
+// All tests are asynchronous.
+waitForExplicitFinish();
+
+let gToolEnabled = Services.prefs.getBoolPref("devtools.performance_dev.enabled");
+let gShowTimelineMemory = Services.prefs.getBoolPref("devtools.performance.ui.show-timeline-memory");
+
+gDevTools.testing = true;
+
+/**
+ * Call manually in tests that use frame script utils after initializing
+ * the tool. Must be called after initializing so we can detect
+ * whether or not `content` is a CPOW or not. Call after init but before navigating
+ * to different pages.
+ */
+function loadFrameScripts () {
+  mm = gBrowser.selectedBrowser.messageManager;
+  mm.loadFrameScript(FRAME_SCRIPT_UTILS_URL, false);
+}
+
+registerCleanupFunction(() => {
+  gDevTools.testing = false;
+  info("finish() was called, cleaning up...");
+
+  Services.prefs.setBoolPref("devtools.performance.ui.show-timeline-memory", gShowTimelineMemory);
+  Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
+  Services.prefs.setBoolPref("devtools.performance_dev.enabled", gToolEnabled);
+  // Make sure the profiler module is stopped when the test finishes.
+  nsIProfilerModule.StopProfiler();
+
+  Cu.forceGC();
+});
+
+function addTab(aUrl, aWindow) {
+  info("Adding tab: " + aUrl);
+
+  let deferred = Promise.defer();
+  let targetWindow = aWindow || window;
+  let targetBrowser = targetWindow.gBrowser;
+
+  targetWindow.focus();
+  let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
+  let linkedBrowser = tab.linkedBrowser;
+
+  linkedBrowser.addEventListener("load", function onLoad() {
+    linkedBrowser.removeEventListener("load", onLoad, true);
+    info("Tab added and finished loading: " + aUrl);
+    deferred.resolve(tab);
+  }, true);
+
+  return deferred.promise;
+}
+
+function removeTab(aTab, aWindow) {
+  info("Removing tab.");
+
+  let deferred = Promise.defer();
+  let targetWindow = aWindow || window;
+  let targetBrowser = targetWindow.gBrowser;
+  let tabContainer = targetBrowser.tabContainer;
+
+  tabContainer.addEventListener("TabClose", function onClose(aEvent) {
+    tabContainer.removeEventListener("TabClose", onClose, false);
+    info("Tab removed and finished closing.");
+    deferred.resolve();
+  }, false);
+
+  targetBrowser.removeTab(aTab);
+  return deferred.promise;
+}
+
+function handleError(aError) {
+  ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
+  finish();
+}
+
+function once(aTarget, aEventName, aUseCapture = false) {
+  info("Waiting for event: '" + aEventName + "' on " + aTarget + ".");
+
+  let deferred = Promise.defer();
+
+  for (let [add, remove] of [
+    ["on", "off"], // Use event emitter before DOM events for consistency
+    ["addEventListener", "removeEventListener"],
+    ["addListener", "removeListener"]
+  ]) {
+    if ((add in aTarget) && (remove in aTarget)) {
+      aTarget[add](aEventName, function onEvent(...aArgs) {
+        aTarget[remove](aEventName, onEvent, aUseCapture);
+        deferred.resolve(...aArgs);
+      }, aUseCapture);
+      break;
+    }
+  }
+
+  return deferred.promise;
+}
+
+function test () {
+  Task.spawn(spawnTest).then(finish, handleError);
+}
+
+function initBackend(aUrl) {
+  info("Initializing a performance front.");
+
+  if (!DebuggerServer.initialized) {
+    DebuggerServer.init(() => true);
+    DebuggerServer.addBrowserActors();
+  }
+
+  return Task.spawn(function*() {
+    let tab = yield addTab(aUrl);
+    let target = TargetFactory.forTab(tab);
+
+    yield target.makeRemote();
+
+    yield gDevTools.showToolbox(target, "performance");
+
+    let connection = getPerformanceActorsConnection(target);
+    yield connection.open();
+    let front = new PerformanceFront(connection);
+    return { target, front };
+  });
+}
+
+function initPerformance(aUrl) {
+  info("Initializing a performance pane.");
+
+  return Task.spawn(function*() {
+    let tab = yield addTab(aUrl);
+    let target = TargetFactory.forTab(tab);
+
+    yield target.makeRemote();
+
+    Services.prefs.setBoolPref("devtools.performance_dev.enabled", true);
+    let toolbox = yield gDevTools.showToolbox(target, "performance");
+    let panel = toolbox.getCurrentPanel();
+    return { target, panel, toolbox };
+  });
+}
+
+function* teardown(panel) {
+  info("Destroying the performance tool.");
+
+  let tab = panel.target.tab;
+  yield panel._toolbox.destroy();
+  yield removeTab(tab);
+}
+
+function idleWait(time) {
+  return DevToolsUtils.waitForTime(time);
+}
+
+function consoleMethod (...args) {
+  if (!mm) {
+    throw new Error("`loadFrameScripts()` must be called before using frame scripts.");
+  }
+  mm.sendAsyncMessage("devtools:test:console", args);
+}
+
+function* consoleProfile(connection, label) {
+  let notified = connection.once("profile");
+  consoleMethod("profile", label);
+  yield notified;
+}
+
+function* consoleProfileEnd(connection) {
+  let notified = connection.once("profileEnd");
+  consoleMethod("profileEnd");
+  yield notified;
+}
+
+function busyWait(time) {
+  let start = Date.now();
+  let stack;
+  while (Date.now() - start < time) { stack = Components.stack; }
+}
+
+function idleWait(time) {
+  return DevToolsUtils.waitForTime(time);
+}
+
--- a/browser/devtools/shared/frame-script-utils.js
+++ b/browser/devtools/shared/frame-script-utils.js
@@ -12,11 +12,16 @@ addMessageListener("devtools:test:naviga
   content.location = data.location;
 });
 
 addMessageListener("devtools:test:reload", function ({ data }) {
   data = data || {};
   content.location.reload(data.forceget);
 });
 
+addMessageListener("devtools:test:console", function ({ data }) {
+  let method = data.shift();
+  content.console[method].apply(content.console, data);
+});
+
 addEventListener("load", function() {
   sendAsyncMessage("devtools:test:load");
 }, true);
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -68,17 +68,17 @@
   background-clip: padding-box;
   margin-top: -1px; /* Move up into the TabsToolbar for the inner highlight at the top of the nav-bar */
   /* Position the toolbar above the bottom of background tabs */
   position: relative;
   z-index: 1;
 }
 
 #nav-bar {
-  background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
+  background-image: linear-gradient(@toolbarHighlight@, transparent);
   box-shadow: 0 1px 0 @toolbarHighlight@ inset;
   padding-top: 2px;
   padding-bottom: 2px;
 }
 
 #nav-bar-overflow-button {
   -moz-image-region: rect(-5px, 12px, 11px, -4px);
 }
@@ -1535,71 +1535,66 @@ richlistitem[type~="action"][actiontype=
   list-style-image: url("chrome://browser/skin/reload-stop-go.png");
 }
 
 #urlbar-reload-button {
   -moz-image-region: rect(0, 14px, 14px, 0);
 }
 
 #urlbar-reload-button:not([disabled]):hover {
-  background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.2), hsla(200,100%,70%,0));
+  background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.2), transparent);
   -moz-image-region: rect(14px, 14px, 28px, 0);
 }
 
 #urlbar-reload-button:not([disabled]):hover:active {
-  background-image: radial-gradient(circle closest-side, hsla(200,100%,60%,.1), hsla(200,100%,60%,0));
+  background-image: radial-gradient(circle closest-side, hsla(200,100%,60%,.1), transparent);
   -moz-image-region: rect(28px, 14px, 42px, 0);
 }
 
 #urlbar-reload-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   transform: scaleX(-1);
 }
 
 #urlbar-go-button {
   -moz-image-region: rect(0, 42px, 14px, 28px);
 }
 
 #urlbar-go-button:hover {
-  background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.2), hsla(110,70%,50%,0));
+  background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.2), transparent);
   -moz-image-region: rect(14px, 42px, 28px, 28px);
 }
 
 #urlbar-go-button:hover:active {
-  background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.1), hsla(110,70%,50%,0));
+  background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.1), transparent);
   -moz-image-region: rect(28px, 42px, 42px, 28px);
 }
 
 #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   transform: scaleX(-1);
 }
 
 #urlbar-stop-button {
   -moz-image-region: rect(0, 28px, 14px, 14px);
 }
 
 #urlbar-stop-button:not([disabled]):hover {
-  background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.3), hsla(5,100%,75%,0));
+  background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.3), transparent);
   -moz-image-region: rect(14px, 28px, 28px, 14px);
 }
 
 #urlbar-stop-button:hover:active {
-  background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.1), hsla(5,100%,75%,0));
+  background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.1), transparent);
   -moz-image-region: rect(28px, 28px, 42px, 14px);
 }
 
 /* Popup blocker button */
 #page-report-button {
   list-style-image: url("chrome://browser/skin/Info.png");
 }
 
-/* Loop */
-#loop-call-button {
-  list-style-image: url("chrome://global/skin/loop/loop-call.png");
-}
-
 /* social share panel */
 
 .social-share-frame {
   background: linear-gradient(to bottom, rgba(242,242,242,.99), rgba(242,242,242,.95));
   border-left: 1px solid #f8f8f8;
   width: 330px;
   height: 150px;
   /* we resize our panels dynamically, make it look nice */
@@ -2118,40 +2113,40 @@ toolbarbutton.chevron > .toolbarbutton-i
 .social-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
 %include ../shared/social/chat.inc.css
 
 .chat-titlebar {
   background-color: #d9d9d9;
-  background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
+  background-image: linear-gradient(@toolbarHighlight@, transparent);
 }
 
 .chat-titlebar[selected] {
   background-color: #f0f0f0;
 }
 
 .chatbar-button {
   -moz-appearance: none;
   background-color: #d9d9d9;
-  background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
+  background-image: linear-gradient(@toolbarHighlight@, transparent);
 }
 
 .chatbar-button > .toolbarbutton-icon {
   -moz-margin-end: 0;
 }
 
 .chatbar-button:hover,
 .chatbar-button[open="true"] {
   background-color: #f0f0f0;
 }
 
 .chatbar-button[activity] {
-  background-image: radial-gradient(circle farthest-corner at center 3px, rgb(233,242,252) 3%, rgba(172,206,255,0.75) 40%, rgba(87,151,201,0.5) 80%, rgba(87,151,201,0));
+  background-image: radial-gradient(circle farthest-corner at center 3px, rgb(233,242,252) 3%, rgba(172,206,255,0.75) 40%, rgba(87,151,201,0.5) 80%, transparent);
 }
 
 chatbox {
   border-top-left-radius: 2.5px;
   border-top-right-radius: 2.5px;
 }
 
 /* Customization mode */
--- a/browser/themes/linux/downloads/downloads.css
+++ b/browser/themes/linux/downloads/downloads.css
@@ -164,17 +164,17 @@ richlistitem[type="download"]:last-child
 
 /*** Highlighted list items ***/
 
 #downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
   border-radius: 3px;
   border-top: 1px solid hsla(0,0%,100%,.3);
   border-bottom: 1px solid hsla(0,0%,0%,.2);
   background-color: Highlight;
-  background-image: linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,100%,0));
+  background-image: linear-gradient(hsla(0,0%,100%,.1), transparent);
   color: HighlightText;
   cursor: pointer;
 }
 
 /*** Button icons ***/
 
 .downloadButton.downloadCancel {
   -moz-image-region: rect(0px, 16px, 16px, 0px);
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -20,17 +20,17 @@
   --space-above-tabbar: 9px;
 
   --tabs-toolbar-color: #333;
   --toolbarbutton-hover-background: hsla(0,0%,100%,.1) linear-gradient(hsla(0,0%,100%,.3), hsla(0,0%,100%,.1)) padding-box;
   --toolbarbutton-hover-bordercolor: hsla(0,0%,0%,.2);
   --toolbarbutton-hover-boxshadow: 0 1px 0 hsla(0,0%,100%,.5),
                                    0 1px 0 hsla(0,0%,100%,.5) inset;
 
-  --toolbarbutton-active-background: hsla(0,0%,0%,.02) linear-gradient(hsla(0,0%,0%,.12), hsla(0,0%,0%,0)) border-box;
+  --toolbarbutton-active-background: hsla(0,0%,0%,.02) linear-gradient(hsla(0,0%,0%,.12), transparent) border-box;
   --toolbarbutton-active-boxshadow: 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;
 
   --toolbarbutton-checkedhover-backgroundcolor: hsla(0,0%,0%,.09);
 
   --toolbarbutton-combined-boxshadow: 0 0 0 1px hsla(0,0%,100%,.15);
   --toolbarbutton-combined-backgroundimage: linear-gradient(hsla(0,0%,0%,.15) 0, hsla(0,0%,0%,.15) 18px);
@@ -2123,17 +2123,17 @@ toolbarbutton[sdk-button="true"][cui-are
   padding: 0 3px;
   list-style-image: var(--urlbar-dropmarker-url);
   -moz-image-region: var(--urlbar-dropmarker-region);
 }
 
 .urlbar-history-dropmarker[open="true"],
 .urlbar-history-dropmarker:hover:active {
   -moz-image-region: var(--urlbar-dropmarker-active-region);
-  background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.3), hsla(205,100%,70%,0));
+  background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.3), transparent);
 }
 
 @media (min-resolution: 2dppx) {
   .urlbar-history-dropmarker {
     list-style-image: var(--urlbar-dropmarker-2x-url);
     -moz-image-region: var(--urlbar-dropmarker-2x-region);
   }
 
@@ -2152,17 +2152,17 @@ toolbarbutton[sdk-button="true"][cui-are
 }
 
 .urlbar-icon {
   padding: 0 3px;
 }
 
 .urlbar-icon[open="true"],
 .urlbar-icon:hover:active {
-  background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.3), hsla(205,100%,70%,0));
+  background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.3), transparent);
 }
 
 #urlbar-search-splitter {
   min-width: 8px;
   width: 8px;
   background-image: none;
   margin: 0 -4px;
   position: relative;
@@ -2368,17 +2368,17 @@ richlistitem[type~="action"][actiontype=
   margin: 0;
   -moz-padding-start: 2px;
   -moz-padding-end: 1px;
   background-origin: border-box;
   list-style-image: url("chrome://browser/skin/reload-stop-go.png");
 }
 
 #urlbar > toolbarbutton:not([disabled]):hover:active {
-  background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.3), hsla(205,100%,70%,0));
+  background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.3), transparent);
 }
 
 #urlbar-go-button {
   -moz-image-region: rect(0, 42px, 14px, 28px);
 }
 
 #urlbar-go-button:hover:active {
   -moz-image-region: rect(14px, 42px, 28px, 28px);
@@ -4518,26 +4518,26 @@ menulist.translate-infobar-element > .me
 }
 
 /* === end of social toolbar provider menu === */
 
 %include ../shared/social/chat.inc.css
 
 .chat-titlebar {
   background-color: #d9d9d9;
-  background-image: linear-gradient(rgba(255,255,255,.43), rgba(255,255,255,0));
+  background-image: linear-gradient(rgba(255,255,255,.43), transparent);
 }
 
 .chat-titlebar[selected] {
   background-color: #f0f0f0;
 }
 
 .chatbar-button {
   background-color: #d9d9d9;
-  background-image: linear-gradient(rgba(255,255,255,.43), rgba(255,255,255,0));
+  background-image: linear-gradient(rgba(255,255,255,.43), transparent);
   border-top-left-radius: @toolbarbuttonCornerRadius@;
   border-top-right-radius: @toolbarbuttonCornerRadius@;
 }
 
 .chatbar-button:hover,
 .chatbar-button[open="true"] {
   background-color: #f0f0f0;
 }
--- a/browser/themes/osx/customizableui/panelUIOverlay.css
+++ b/browser/themes/osx/customizableui/panelUIOverlay.css
@@ -7,24 +7,24 @@
 .panel-subviews {
   background-color: hsla(0,0%,100%,.97);
 }
 
 @media (min-resolution: 2dppx) {
   #PanelUI-help[panel-multiview-anchor="true"]::after,
   toolbarbutton[panel-multiview-anchor="true"] {
     background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted@2x.png),
-                      linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
+                      linear-gradient(rgba(255,255,255,0.3), transparent);
     background-size: 16px, auto;
   }
 
   #PanelUI-help[panel-multiview-anchor="true"]:-moz-locale-dir(rtl)::after,
   toolbarbutton[panel-multiview-anchor="true"]:-moz-locale-dir(rtl) {
     background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted-rtl@2x.png),
-                      linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
+                      linear-gradient(rgba(255,255,255,0.3), transparent);
   }
 
   #PanelUI-fxa-status {
     list-style-image: url(chrome://browser/skin/sync-horizontalbar@2x.png);
   }
 
   #PanelUI-fxa-status[status="active"] {
     list-style-image: url(chrome://browser/skin/syncProgress-horizontalbar@2x.png);
--- a/browser/themes/shared/customizableui/customizeMode.inc.css
+++ b/browser/themes/shared/customizableui/customizeMode.inc.css
@@ -347,32 +347,32 @@ toolbarpaletteitem[place="toolbar"] {
 }
 
 #customization-lwtheme-menu-recommended {
   border-top: 1px solid hsla(210,4%,10%,.05);
   border-bottom: 1px solid hsla(210,4%,10%,.05);
 }
 
 #customization-lwtheme-menu-footer {
-  background: linear-gradient(hsla(210,4%,10%,.05) 60%, hsla(210,4%,10%,0)) border-box;
+  background: linear-gradient(hsla(210,4%,10%,.05) 60%, transparent) border-box;
   border-top: 1px solid hsla(210,4%,10%,.05);
   margin-bottom: -10px;
 }
 
 .customization-lwtheme-menu-footeritem {
   -moz-appearance: none;
   -moz-box-flex: 1;
   color: hsl(0,0%,50%);
   border-style: none;
   padding: 10px;
   margin-left: 0;
   margin-right: 0;
 }
 
 .customization-lwtheme-menu-footeritem:hover {
-  background: linear-gradient(hsla(210,4%,10%,.08) 40%, hsla(210,4%,10%,0)) padding-box;
+  background: linear-gradient(hsla(210,4%,10%,.08) 40%, transparent) padding-box;
 }
 
 .customization-lwtheme-menu-footeritem:first-child {
   -moz-border-end: 1px solid hsla(210,4%,10%,.15);
 }
 
 %include customizeTip.inc.css
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -82,19 +82,19 @@
   from { margin-top: -.5em; } to { margin-top: calc(64px - .5em); }
 }
 
 @keyframes whimsyRotate {
   to { transform: perspective(5000px) rotateY(360deg); }
 }
 
 #PanelUI-button {
-  background-image: linear-gradient(to bottom, hsla(0,0%,100%,0), hsla(0,0%,100%,.3) 30%, hsla(0,0%,100%,.3) 70%, hsla(0,0%,100%,0)),
-                    linear-gradient(to bottom, hsla(210,54%,20%,0), hsla(210,54%,20%,.3) 30%, hsla(210,54%,20%,.3) 70%, hsla(210,54%,20%,0)),
-                    linear-gradient(to bottom, hsla(0,0%,100%,0), hsla(0,0%,100%,.3) 30%, hsla(0,0%,100%,.3) 70%, hsla(0,0%,100%,0));
+  background-image: linear-gradient(to bottom, transparent, hsla(0,0%,100%,.3) 30%, hsla(0,0%,100%,.3) 70%, transparent),
+                    linear-gradient(to bottom, transparent, hsla(210,54%,20%,.3) 30%, hsla(210,54%,20%,.3) 70%, transparent),
+                    linear-gradient(to bottom, transparent, hsla(0,0%,100%,.3) 30%, hsla(0,0%,100%,.3) 70%, transparent);
   background-size: 1px calc(100% - 1px), 1px calc(100% - 1px), 1px  calc(100% - 1px) !important;
   background-position: 0px 0px, 1px 0px, 2px 0px;
   background-repeat: no-repeat;
 }
 
 #PanelUI-button:-moz-locale-dir(rtl) {
   background-position: 100% 0, calc(100% - 1px) 0, calc(100% - 2px) 0;
 }
@@ -869,49 +869,49 @@ toolbarbutton[panel-multiview-anchor="tr
   background-color: Highlight;
 }
 
 #PanelUI-help[panel-multiview-anchor="true"] + toolbarseparator {
   display: none;
 }
 
 #PanelUI-help[panel-multiview-anchor="true"] {
-  background-image: linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
+  background-image: linear-gradient(rgba(255,255,255,0.3), transparent);
   background-position: 0;
 }
 
 #PanelUI-help[panel-multiview-anchor="true"]::after {
   content: "";
   position: absolute;
   top: 0;
   height: 100%;
   width: @exitSubviewGutterWidth@;
   background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted.png),
-                    linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
+                    linear-gradient(rgba(255,255,255,0.3), transparent);
   background-repeat: no-repeat;
   background-color: Highlight;
   background-position: left 10px center, 0;
 }
 
 #PanelUI-help[panel-multiview-anchor="true"]:-moz-locale-dir(rtl)::after {
   background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted-rtl.png),
-                    linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
+                    linear-gradient(rgba(255,255,255,0.3), transparent);
   background-position: right 10px center, 0;
 }
 
 toolbarbutton[panel-multiview-anchor="true"] {
   background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted.png),
-                    linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
+                    linear-gradient(rgba(255,255,255,0.3), transparent);
   background-position: right calc(@menuPanelButtonWidth@ / 2 - @exitSubviewGutterWidth@ + 2px) center;
   background-repeat: no-repeat, repeat;
 }
 
 toolbarbutton[panel-multiview-anchor="true"]:-moz-locale-dir(rtl) {
   background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted-rtl.png),
-                    linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
+                    linear-gradient(rgba(255,255,255,0.3), transparent);
   background-position: left calc(@menuPanelButtonWidth@ / 2 - @exitSubviewGutterWidth@ + 2px) center;
 }
 
 toolbarpaletteitem[place="palette"] > .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
 #bookmarks-menu-button[cui-areatype="menu-panel"] > .toolbarbutton-menubutton-dropmarker {
   display: none;
 }
 
@@ -1000,19 +1000,19 @@ toolbarpaletteitem[haswideitem][place="p
   border-top-left-radius: 0;
   border-bottom-left-radius: 0;
 }
 
 .toolbaritem-combined-buttons > separator {
   -moz-appearance: none;
   width: 3px;
   -moz-box-align: stretch;
-  background-image: linear-gradient(to bottom, hsla(0,0%,100%,0), hsla(0,0%,100%,.3) 40%, hsla(0,0%,100%,.3) 60%, hsla(0,0%,100%,0)),
-                    linear-gradient(to bottom, hsla(210,54%,20%,0), hsla(210,54%,20%,.15) 40%, hsla(210,54%,20%,.15) 60%, hsla(210,54%,20%,0)),
-                    linear-gradient(to bottom, hsla(0,0%,100%,0), hsla(0,0%,100%,.3) 40%, hsla(0,0%,100%,.3) 60%, hsla(0,0%,100%,0));
+  background-image: linear-gradient(to bottom, transparent, hsla(0,0%,100%,.3) 40%, hsla(0,0%,100%,.3) 60%, transparent),
+                    linear-gradient(to bottom, transparent, hsla(210,54%,20%,.15) 40%, hsla(210,54%,20%,.15) 60%, transparent),
+                    linear-gradient(to bottom, transparent, hsla(0,0%,100%,.3) 40%, hsla(0,0%,100%,.3) 60%, transparent);
   background-size: 1px, 1px, 1px;
   background-position: 0 0, 1px 0, 2px 0;
   background-repeat: no-repeat;
 }
 
 .toolbaritem-combined-buttons@inAnyPanel@ > separator {
   margin: .5em 0;
   width: 1px;
--- a/browser/themes/shared/devtools/app-manager/device.css
+++ b/browser/themes/shared/devtools/app-manager/device.css
@@ -298,17 +298,17 @@ button {
   float: right;
   padding: 0 5px;
 }
 
 /*****************     HEADER      *****************/
 
 header {
   padding-top: 140px;
-  background-image: linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,0.7));
+  background-image: linear-gradient(to bottom, transparent, rgba(0,0,0,0.7));
   color: #FFF;
   text-shadow: 0 1px 2px rgba(0,0,0,0.8);
   padding: 10px;
 }
 
 
 
 /*****************      APPS & BROWSER TABS      *****************/
--- a/browser/themes/shared/devtools/toolbars.inc.css
+++ b/browser/themes/shared/devtools/toolbars.inc.css
@@ -519,19 +519,19 @@
 #toolbox-dock-bottom:hover,
 #toolbox-dock-side:hover {
   opacity: 1;
 }
 
 .devtools-separator {
   margin: 0 2px;
   width: 2px;
-  background-image: linear-gradient(hsla(204,45%,98%,0), hsla(204,45%,98%,.1), hsla(204,45%,98%,0)),
-                    linear-gradient(hsla(206,37%,4%,0), hsla(206,37%,4%,.6), hsla(206,37%,4%,0)),
-                    linear-gradient(hsla(204,45%,98%,0), hsla(204,45%,98%,.1), hsla(204,45%,98%,0));
+  background-image: linear-gradient(transparent, hsla(204,45%,98%,.1), transparent),
+                    linear-gradient(transparent, hsla(206,37%,4%,.6), transparent),
+                    linear-gradient(transparent, hsla(204,45%,98%,.1), transparent);
   background-size: 1px 100%;
   background-repeat: no-repeat;
   background-position: 0, 1px, 2px;
 }
 
 #toolbox-buttons:empty + .devtools-separator,
 .devtools-separator[invisible] {
   visibility: hidden;
--- a/browser/themes/shared/social/chat.inc.css
+++ b/browser/themes/shared/social/chat.inc.css
@@ -121,17 +121,17 @@ chatbar > chatbox > .chat-titlebar > .ch
   margin-right: 2px;
 }
 
 .chat-titlebar[minimized="true"] {
   border-bottom: none;
 }
 
 .chat-titlebar[activity] {
-  background-image: radial-gradient(ellipse closest-side at center, rgb(255,255,255), rgba(255,255,255,0));
+  background-image: radial-gradient(ellipse closest-side at center, rgb(255,255,255), transparent);
   background-repeat: no-repeat;
   background-size: 100% 20px;
   background-position: 0 -10px;
 }
 
 chatbox[dark=true] > .chat-titlebar,
 chatbox[dark=true] > .chat-titlebar[selected] {
   border-bottom: none;
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -289,17 +289,17 @@
 
 /* Pinned tab separators need position: absolute when positioned (during overflow). */
 #tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned]::before {
   height: 100%;
   position: absolute;
 }
 
 .tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) > .tab-stack > .tab-content {
-  background-image: radial-gradient(farthest-corner at center bottom, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 20%, rgba(127,179,255,0.25) 40%, rgba(127,179,255,0) 70%);
+  background-image: radial-gradient(farthest-corner at center bottom, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 20%, rgba(127,179,255,0.25) 40%, transparent 70%);
   background-position: center bottom @tabToolbarNavbarOverlap@;
   background-repeat: no-repeat;
   background-size: 85% 100%;
 }
 
 /* Background tab separators (3px wide).
    Also show separators beside the selected tab when dragging it. */
 #tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -282,17 +282,17 @@
   /* Position the toolbar above the bottom of background tabs */
   position: relative;
   z-index: 1;
 }
 
 #nav-bar {
   border-top: 1px solid @toolbarShadowColor@ !important;
   background-clip: padding-box;
-  background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
+  background-image: linear-gradient(@toolbarHighlight@, transparent);
   box-shadow: 0 1px 0 @toolbarHighlight@ inset;
 }
 
 %ifdef WINDOWS_AERO
 @media not all and (-moz-windows-compositor) {
 %endif
   #TabsToolbar[collapsed="true"] + #nav-bar {
     border-top-style: none !important;
@@ -872,17 +872,17 @@ toolbarbutton[sdk-button="true"][cui-are
   margin-bottom: @tabToolbarNavbarOverlap@;
 }
 
 #TabsToolbar .toolbarbutton-1:not([disabled=true]):hover,
 #TabsToolbar .toolbarbutton-1[open],
 #TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):hover,
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled=true]):hover,
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled=true]):hover {
-  background-image: linear-gradient(rgba(255,255,255,0), rgba(255,255,255,.5)),
+  background-image: linear-gradient(transparent, rgba(255,255,255,.5)),
                     linear-gradient(transparent, rgba(0,0,0,.25) 30%),
                     linear-gradient(transparent, rgba(0,0,0,.25) 30%);
   background-position: 1px -1px, 0 -1px, 100% -1px;
   background-size: calc(100% - 2px) 100%, 1px 100%, 1px 100%;
   background-repeat: no-repeat;
 }
 
 /* unified back/forward button */
@@ -1218,22 +1218,22 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
 }
 
 .searchbar-engine-button,
 .search-go-container {
   padding: 2px 2px;
 }
 
 .urlbar-icon:hover {
-  background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.3), hsla(200,100%,70%,0));
+  background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.3), transparent);
 }
 
 .urlbar-icon[open="true"],
 .urlbar-icon:hover:active {
-  background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.1), hsla(200,100%,70%,0));
+  background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.1), transparent);
 }
 
 #urlbar-search-splitter {
   min-width: 6px;
   -moz-margin-start: -3px;
   border: none;
   background: transparent;
 }
@@ -1338,23 +1338,23 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
   background-color: transparent;
   border: none;
   width: auto;
   list-style-image: url("chrome://browser/skin/urlbar-history-dropmarker.png");
   -moz-image-region: rect(0px, 11px, 14px, 0px);
 }
 
 .urlbar-history-dropmarker:hover {
-  background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.3), hsla(205,100%,70%,0));
+  background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.3), transparent);
   -moz-image-region: rect(0px, 22px, 14px, 11px);
 }
 
 .urlbar-history-dropmarker:hover:active,
 .urlbar-history-dropmarker[open="true"] {
-  background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.1), hsla(205,100%,70%,0));
+  background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.1), transparent);
   -moz-image-region: rect(0px, 33px, 14px, 22px);
 }
 
 /* page proxy icon */
 
 %include ../shared/identity-block.inc.css
 
 #page-proxy-favicon {
@@ -1490,58 +1490,58 @@ richlistitem[type~="action"][actiontype=
   list-style-image: url("chrome://browser/skin/reload-stop-go.png");
 }
 
 #urlbar-reload-button {
   -moz-image-region: rect(0, 14px, 14px, 0);
 }
 
 #urlbar-reload-button:not([disabled]):hover {
-  background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.2), hsla(200,100%,70%,0));
+  background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.2), transparent);
   -moz-image-region: rect(14px, 14px, 28px, 0);
 }
 
 #urlbar-reload-button:not([disabled]):hover:active {
-  background-image: radial-gradient(circle closest-side, hsla(200,100%,60%,.1), hsla(200,100%,60%,0));
+  background-image: radial-gradient(circle closest-side, hsla(200,100%,60%,.1), transparent);
   -moz-image-region: rect(28px, 14px, 42px, 0);
 }
 
 #urlbar-reload-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   transform: scaleX(-1);
 }
 
 #urlbar-go-button {
   -moz-image-region: rect(0, 42px, 14px, 28px);
 }
 
 #urlbar-go-button:hover {
-  background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.2), hsla(110,70%,50%,0));
+  background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.2), transparent);
   -moz-image-region: rect(14px, 42px, 28px, 28px);
 }
 
 #urlbar-go-button:hover:active {
-  background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.1), hsla(110,70%,50%,0));
+  background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.1), transparent);
   -moz-image-region: rect(28px, 42px, 42px, 28px);
 }
 
 #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   transform: scaleX(-1);
 }
 
 #urlbar-stop-button {
   -moz-image-region: rect(0, 28px, 14px, 14px);
 }
 
 #urlbar-stop-button:not([disabled]):hover {
-  background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.3), hsla(5,100%,75%,0));
+  background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.3), transparent);
   -moz-image-region: rect(14px, 28px, 28px, 14px);
 }
 
 #urlbar-stop-button:hover:active {
-  background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.1), hsla(5,100%,75%,0));
+  background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.1), transparent);
   -moz-image-region: rect(28px, 28px, 42px, 14px);
 }
 
 /* popup blocker button */
 
 #page-report-button {
   list-style-image: url("chrome://browser/skin/urlbar-popup-blocked.png");
   -moz-image-region: rect(0, 16px, 16px, 0);
@@ -2767,27 +2767,27 @@ toolbarpaletteitem[place="palette"] > #s
 .social-panel-frame {
   border-radius: inherit;
 }
 
 %include ../shared/social/chat.inc.css
 
 .chat-titlebar {
   background-color: #c4cfde;
-  background-image: linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,0));
+  background-image: linear-gradient(rgba(255,255,255,.5), transparent);
 }
 
 .chat-titlebar[selected] {
   background-color: #dae3f0;
 }
 
 .chatbar-button {
   -moz-appearance: none;
   background-color: #c4cfde;
-  background-image: linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,0));
+  background-image: linear-gradient(rgba(255,255,255,.5), transparent);
 }
 
 .chatbar-button > .toolbarbutton-icon {
   -moz-margin-end: 0;
 }
 
 .chatbar-button:hover,
 .chatbar-button[open="true"] {
--- a/browser/themes/windows/downloads/allDownloadsViewOverlay-aero.css
+++ b/browser/themes/windows/downloads/allDownloadsViewOverlay-aero.css
@@ -16,20 +16,20 @@
 
   This styling should be kept in sync with the style from the above file.
   */
   #downloadsRichListBox > richlistitem.download[selected] {
     color: inherit;
     background-color: transparent;
     /* four gradients for the bevel highlights on each edge, one for blue background */
     background-image:
-      linear-gradient(to bottom, rgba(255,255,255,0.9) 3px, rgba(255,255,255,0) 3px),
-      linear-gradient(to right, rgba(255,255,255,0.5) 3px, rgba(255,255,255,0) 3px),
-      linear-gradient(to left, rgba(255,255,255,0.5) 3px, rgba(255,255,255,0) 3px),
-      linear-gradient(to top, rgba(255,255,255,0.4) 3px, rgba(255,255,255,0) 3px),
+      linear-gradient(to bottom, rgba(255,255,255,0.9) 3px, transparent 3px),
+      linear-gradient(to right, rgba(255,255,255,0.5) 3px, transparent 3px),
+      linear-gradient(to left, rgba(255,255,255,0.5) 3px, transparent 3px),
+      linear-gradient(to top, rgba(255,255,255,0.4) 3px, transparent 3px),
       linear-gradient(to bottom, rgba(163,196,247,0.3), rgba(122,180,246,0.3));
     background-clip: content-box;
     border-radius: 6px;
     outline: 1px solid rgb(124,163,206);
     -moz-outline-radius: 3px;
     outline-offset: -2px;
   }
 }
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -79,17 +79,17 @@ browser.jar:
         skin/classic/browser/searchbar-dropdown-arrow.png
         skin/classic/browser/Secure24.png
         skin/classic/browser/setDesktopBackground.css
         skin/classic/browser/slowStartup-16.png
         skin/classic/browser/theme-switcher-icon.png
         skin/classic/browser/Toolbar.png                             (Toolbar-XP.png)
         skin/classic/browser/Toolbar-inverted.png
         skin/classic/browser/Toolbar-lunaSilver.png
-        skin/classic/browser/toolbarbutton-dropdown-arrow.png
+        skin/classic/browser/toolbarbutton-dropdown-arrow.png        (toolbarbutton-dropdown-arrow-XPVista7.png)
         skin/classic/browser/toolbarbutton-dropdown-arrow-inverted.png
         skin/classic/browser/undoCloseTab.png                        (../shared/undoCloseTab.png)
         skin/classic/browser/undoCloseTab@2x.png                     (../shared/undoCloseTab@2x.png)
         skin/classic/browser/urlbar-arrow.png
         skin/classic/browser/urlbar-popup-blocked.png
         skin/classic/browser/urlbar-history-dropmarker.png
         skin/classic/browser/notification-pluginNormal.png           (../shared/plugins/notification-pluginNormal.png)
         skin/classic/browser/notification-pluginAlert.png            (../shared/plugins/notification-pluginAlert.png)
@@ -187,23 +187,23 @@ browser.jar:
         skin/classic/browser/preferences/in-content/icons@2x.png     (../shared/incontentprefs/icons@2x.png)
         skin/classic/browser/preferences/applications.css            (preferences/applications.css)
         skin/classic/browser/preferences/aboutPermissions.css        (preferences/aboutPermissions.css)
         skin/classic/browser/social/services-16.png                  (social/services-16.png)
         skin/classic/browser/social/services-64.png                  (social/services-64.png)
         skin/classic/browser/social/chat-icons.svg                   (../shared/social/chat-icons.svg)
         skin/classic/browser/social/gear_default.png                 (../shared/social/gear_default.png)
         skin/classic/browser/social/gear_clicked.png                 (../shared/social/gear_clicked.png)
-        skin/classic/browser/tabbrowser/newtab.png                   (tabbrowser/newtab.png)
+        skin/classic/browser/tabbrowser/newtab.png                   (tabbrowser/newtab-XPVista7.png)
         skin/classic/browser/tabbrowser/newtab-inverted.png          (tabbrowser/newtab-inverted.png)
         skin/classic/browser/tabbrowser/connecting.png               (tabbrowser/connecting.png)
         skin/classic/browser/tabbrowser/loading.png                  (tabbrowser/loading.png)
         skin/classic/browser/tabbrowser/tab-active-middle.png        (tabbrowser/tab-active-middle.png)
         skin/classic/browser/tabbrowser/tab-active-middle@2x.png     (tabbrowser/tab-active-middle@2x.png)
-        skin/classic/browser/tabbrowser/tab-arrow-left.png           (tabbrowser/tab-arrow-left.png)
+        skin/classic/browser/tabbrowser/tab-arrow-left.png           (tabbrowser/tab-arrow-left-XPVista7.png)
         skin/classic/browser/tabbrowser/tab-arrow-left-inverted.png  (tabbrowser/tab-arrow-left-inverted.png)
         skin/classic/browser/tabbrowser/tab-background-start.png     (tabbrowser/tab-background-start.png)
         skin/classic/browser/tabbrowser/tab-background-start@2x.png  (tabbrowser/tab-background-start@2x.png)
         skin/classic/browser/tabbrowser/tab-background-middle.png    (tabbrowser/tab-background-middle.png)
         skin/classic/browser/tabbrowser/tab-background-middle@2x.png (tabbrowser/tab-background-middle@2x.png)
         skin/classic/browser/tabbrowser/tab-background-end.png       (tabbrowser/tab-background-end.png)
         skin/classic/browser/tabbrowser/tab-background-end@2x.png    (tabbrowser/tab-background-end@2x.png)
         skin/classic/browser/tabbrowser/tab-overflow-indicator.png   (../shared/tabbrowser/tab-overflow-indicator.png)
@@ -511,16 +511,17 @@ browser.jar:
         skin/classic/aero/browser/setDesktopBackground.css
         skin/classic/aero/browser/slowStartup-16.png
         skin/classic/aero/browser/theme-switcher-icon.png
         skin/classic/aero/browser/theme-switcher-icon-aero.png
         skin/classic/aero/browser/Toolbar.png
         skin/classic/aero/browser/Toolbar-inverted.png
         skin/classic/aero/browser/Toolbar-aero.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow.png
+        skin/classic/aero/browser/toolbarbutton-dropdown-arrow-XPVista7.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow-inverted.png
         skin/classic/aero/browser/undoCloseTab.png                        (../shared/undoCloseTab.png)
         skin/classic/aero/browser/undoCloseTab@2x.png                     (../shared/undoCloseTab@2x.png)
         skin/classic/aero/browser/urlbar-arrow.png
         skin/classic/aero/browser/urlbar-popup-blocked.png
         skin/classic/aero/browser/urlbar-history-dropmarker.png
         skin/classic/aero/browser/notification-pluginNormal.png     (../shared/plugins/notification-pluginNormal.png)
         skin/classic/aero/browser/notification-pluginAlert.png      (../shared/plugins/notification-pluginAlert.png)
@@ -621,22 +622,24 @@ browser.jar:
         skin/classic/aero/browser/preferences/applications.css       (preferences/applications.css)
         skin/classic/aero/browser/preferences/aboutPermissions.css   (preferences/aboutPermissions.css)
         skin/classic/aero/browser/social/services-16.png             (social/services-16.png)
         skin/classic/aero/browser/social/services-64.png             (social/services-64.png)
         skin/classic/aero/browser/social/chat-icons.svg              (../shared/social/chat-icons.svg)
         skin/classic/aero/browser/social/gear_default.png            (../shared/social/gear_default.png)
         skin/classic/aero/browser/social/gear_clicked.png            (../shared/social/gear_clicked.png)
         skin/classic/aero/browser/tabbrowser/newtab.png              (tabbrowser/newtab.png)
+        skin/classic/aero/browser/tabbrowser/newtab-XPVista7.png     (tabbrowser/newtab-XPVista7.png)
         skin/classic/aero/browser/tabbrowser/newtab-inverted.png     (tabbrowser/newtab-inverted.png)
         skin/classic/aero/browser/tabbrowser/connecting.png          (tabbrowser/connecting.png)
         skin/classic/aero/browser/tabbrowser/loading.png             (tabbrowser/loading.png)
         skin/classic/aero/browser/tabbrowser/tab-active-middle.png   (tabbrowser/tab-active-middle.png)
         skin/classic/aero/browser/tabbrowser/tab-active-middle@2x.png (tabbrowser/tab-active-middle@2x.png)
         skin/classic/aero/browser/tabbrowser/tab-arrow-left.png      (tabbrowser/tab-arrow-left.png)
+        skin/classic/aero/browser/tabbrowser/tab-arrow-left-XPVista7.png (tabbrowser/tab-arrow-left-XPVista7.png)
         skin/classic/aero/browser/tabbrowser/tab-arrow-left-inverted.png (tabbrowser/tab-arrow-left-inverted.png)
         skin/classic/aero/browser/tabbrowser/tab-background-start.png    (tabbrowser/tab-background-start.png)
         skin/classic/aero/browser/tabbrowser/tab-background-start@2x.png (tabbrowser/tab-background-start@2x.png)
         skin/classic/aero/browser/tabbrowser/tab-background-middle.png   (tabbrowser/tab-background-middle.png)
         skin/classic/aero/browser/tabbrowser/tab-background-middle@2x.png (tabbrowser/tab-background-middle@2x.png)
         skin/classic/aero/browser/tabbrowser/tab-background-end.png      (tabbrowser/tab-background-end.png)
         skin/classic/aero/browser/tabbrowser/tab-background-end@2x.png   (tabbrowser/tab-background-end@2x.png)
         skin/classic/aero/browser/tabbrowser/tab-overflow-indicator.png  (../shared/tabbrowser/tab-overflow-indicator.png)
@@ -870,10 +873,19 @@ browser.jar:
 % override chrome://browser/skin/menuPanel-small.png       chrome://browser/skin/menuPanel-small-aero.png          os=WINNT osversion=6.1
 
 % override chrome://browser/skin/theme-switcher-icon.png   chrome://browser/skin/theme-switcher-icon-aero.png      os=WINNT osversion=6
 % override chrome://browser/skin/theme-switcher-icon.png   chrome://browser/skin/theme-switcher-icon-aero.png      os=WINNT osversion=6.1
 
 % override chrome://browser/skin/sync-horizontalbar.png          chrome://browser/skin/sync-horizontalbar-XPVista7.png          os=WINNT osversion<6.2
 % override chrome://browser/skin/syncProgress-horizontalbar.png  chrome://browser/skin/syncProgress-horizontalbar-XPVista7.png  os=WINNT osversion<6.2
 
+% override chrome://browser/skin/toolbarbutton-dropdown-arrow.png  chrome://browser/skin/toolbarbutton-dropdown-arrow-XPVista7.png  os=WINNT osversion=6
+% override chrome://browser/skin/toolbarbutton-dropdown-arrow.png  chrome://browser/skin/toolbarbutton-dropdown-arrow-XPVista7.png  os=WINNT osversion=6.1
+
+% override chrome://browser/skin/tabbrowser/newtab.png     chrome://browser/skin/tabbrowser/newtab-XPVista7.png    os=WINNT osversion=6
+% override chrome://browser/skin/tabbrowser/newtab.png     chrome://browser/skin/tabbrowser/newtab-XPVista7.png    os=WINNT osversion=6.1
+
+% override chrome://browser/skin/tabbrowser/tab-arrow-left.png     chrome://browser/skin/tabbrowser/tab-arrow-left-XPVista7.png    os=WINNT osversion=6
+% override chrome://browser/skin/tabbrowser/tab-arrow-left.png     chrome://browser/skin/tabbrowser/tab-arrow-left-XPVista7.png    os=WINNT osversion=6.1
+
 % override chrome://browser/skin/loop/toolbar.png          chrome://browser/skin/loop/toolbar-XPVista7.png         os=WINNT osversion=6
 % override chrome://browser/skin/loop/toolbar.png          chrome://browser/skin/loop/toolbar-XPVista7.png         os=WINNT osversion=6.1
--- a/browser/themes/windows/places/organizer-aero.css
+++ b/browser/themes/windows/places/organizer-aero.css
@@ -27,17 +27,17 @@
 }
 
 @media (-moz-windows-compositor) {
   #placesToolbox {
     border-top: none;
   }
 
   #placesToolbar {
-    background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
+    background-image: linear-gradient(@toolbarHighlight@, transparent);
   }
 }
 
 @media (-moz-windows-default-theme) {
   #placesView > splitter {
     border: 0;
     -moz-border-end: 1px solid #A9B7C9;
     min-width: 0;
copy from browser/themes/windows/tabbrowser/newtab.png
copy to browser/themes/windows/tabbrowser/newtab-XPVista7.png
index 7cea7bdd8f7f073156e7fe505fa842ded15195c0..f4cf55ffce71954c594d5bed27666d7bcc0ef9ac
GIT binary patch
literal 105
zc%17D@N?(olHy`uVBq!ia0vp^0zfRp!3HFQtmCqPl!2#<V@SoV<RAb4+q+gwkaS>D
zIL9C^KK;Lf%_N?J!or{aJj-r0T#Pti(!gY+!^6PvKHYfRq}vWTK)no}u6{1-oD!M<
DXL26&
copy from browser/themes/windows/tabbrowser/tab-arrow-left.png
copy to browser/themes/windows/tabbrowser/tab-arrow-left-XPVista7.png
index 951d5cbe57e67709286b7bd7a1aec7ccec0ed5fe..1dd8a226f753f38eb6a40bbdeeef0e35af7d32b8
GIT binary patch
literal 122
zc%17D@N?(olHy`uVBq!ia0vp^{6H+o$P6Scj-)&SQfvV}A+9nqGA=GIe`X(+2Z}J3
z1o;IsI6S+N2IMGtx;Tb#Tu)ALU}Kk%;5RTZH`rio@S#y~0^<`V*2W+M28N_REXHYe
Srw##CGkCiCxvX<aXaWE<EFI_o
copy from browser/themes/windows/toolbarbutton-dropdown-arrow.png
copy to browser/themes/windows/toolbarbutton-dropdown-arrow-XPVista7.png
index 5f892f532efdb3742322674f4ee9b4adbb5cd93a..08d9da1d1245845502678a3b126b79be0c23b2d8
GIT binary patch
literal 91
zc%17D@N?(olHy`uVBq!ia0vp^oIuRZ!3HF6%}!4MQc9jKjv*Ss$qG_CcI^0bymg_M
pLc;<k35695Y#dq(7z_*;7-aX!Y-HteDFdoz@O1TaS?83{1ORpU6|MjP
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2868,17 +2868,17 @@ nsDocShell::PopProfileTimelineMarkers(JS
   // docShell level but we can only be sure that a paint did happen in a
   // docShell if an Layer marker type was recorded too.
 
   nsTArray<mozilla::dom::ProfileTimelineMarker> profileTimelineMarkers;
 
   // If we see an unpaired START, we keep it around for the next call
   // to PopProfileTimelineMarkers.  We store the kept START objects in
   // this array.
-  decltype(mProfileTimelineMarkers) keptMarkers;
+  nsTArray<InternalProfileTimelineMarker*> keptMarkers;
 
   for (uint32_t i = 0; i < mProfileTimelineMarkers.Length(); ++i) {
     ProfilerMarkerTracing* startPayload = static_cast<ProfilerMarkerTracing*>(
       mProfileTimelineMarkers[i]->mPayload);
     const char* startMarkerName = mProfileTimelineMarkers[i]->mName.get();
 
     bool hasSeenPaintedLayer = false;
 
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -98,16 +98,17 @@ import android.graphics.drawable.Drawabl
 import android.net.Uri;
 import android.nfc.NdefMessage;
 import android.nfc.NdefRecord;
 import android.nfc.NfcAdapter;
 import android.nfc.NfcEvent;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.StrictMode;
+import android.support.v4.app.DialogFragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.content.LocalBroadcastManager;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -147,16 +148,17 @@ public class BrowserApp extends GeckoApp
     private static final int TABS_ANIMATION_DURATION = 450;
 
     private static final String ADD_SHORTCUT_TOAST = "add_shortcut_toast";
     public static final String GUEST_BROWSING_ARG = "--guest";
 
     private static final String STATE_ABOUT_HOME_TOP_PADDING = "abouthome_top_padding";
 
     private static final String BROWSER_SEARCH_TAG = "browser_search";
+    private static final String ONBOARD_STARTPANE_TAG = "startpane_dialog";
 
     // Request ID for startActivityForResult.
     private static final int ACTIVITY_REQUEST_PREFERENCES = 1001;
 
     public static final String PREF_STARTPANE_ENABLED = "startpane_enabled";
 
     private BrowserSearch mBrowserSearch;
     private View mBrowserSearchContainer;
@@ -623,26 +625,26 @@ public class BrowserApp extends GeckoApp
     private void checkStartPane(Context context, String intentAction) {
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
 
         try {
             final SharedPreferences prefs = GeckoSharedPrefs.forProfile(this);
 
             if (prefs.getBoolean(PREF_STARTPANE_ENABLED, false)) {
                 if (!Intent.ACTION_VIEW.equals(intentAction)) {
-                    final Intent startIntent = new Intent(this, StartPane.class);
-                    context.startActivity(startIntent);
+                    final DialogFragment dialog = new StartPane();
+                    dialog.show(getSupportFragmentManager(), ONBOARD_STARTPANE_TAG);
                 }
                 // Don't bother trying again to show the v1 minimal first run.
                 prefs.edit().putBoolean(PREF_STARTPANE_ENABLED, false).apply();
             }
         } finally {
             StrictMode.setThreadPolicy(savedPolicy);
         }
-      }
+    }
 
     private Class<?> getMediaPlayerManager() {
         if (AppConstants.MOZ_MEDIA_PLAYER) {
             try {
                 return Class.forName("org.mozilla.gecko.MediaPlayerManager");
             } catch(Exception ex) {
                 // Ignore failures
                 Log.e(LOGTAG, "No native casting support", ex);
--- a/mobile/android/base/ReadingListHelper.java
+++ b/mobile/android/base/ReadingListHelper.java
@@ -22,23 +22,18 @@ import android.content.ContentValues;
 import android.content.Context;
 import android.net.Uri;
 import android.util.Log;
 import android.widget.Toast;
 
 public final class ReadingListHelper implements GeckoEventListener, NativeEventListener {
     private static final String LOGTAG = "ReadingListHelper";
 
-    private static final int READER_ADD_SUCCESS = 0;
-    private static final int READER_ADD_FAILED = 1;
-    private static final int READER_ADD_DUPLICATE = 2;
-
     protected final Context context;
 
-
     public ReadingListHelper(Context context) {
         this.context = context;
 
         EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener) this,
             "Reader:AddToList", "Reader:FaviconRequest");
         EventDispatcher.getInstance().registerGeckoThreadListener((NativeEventListener) this,
             "Reader:ListStatusRequest", "Reader:RemoveFromList");
     }
@@ -81,26 +76,16 @@ public final class ReadingListHelper imp
         }
     }
 
     /**
      * A page can be added to the ReadingList by long-tap of the page-action
      * icon, or by tapping the readinglist-add icon in the ReaderMode banner.
      */
     private void handleAddToList(JSONObject message) {
-        final int result = message.optInt("result", READER_ADD_FAILED);
-        if (result != READER_ADD_SUCCESS) {
-            if (result == READER_ADD_FAILED) {
-                showToast(R.string.reading_list_failed, Toast.LENGTH_SHORT);
-            } else if (result == READER_ADD_DUPLICATE) {
-                showToast(R.string.reading_list_duplicate, Toast.LENGTH_SHORT);
-            }
-            return;
-        }
-
         final ContentValues values = new ContentValues();
         final String url = message.optString("url");
 
         values.put(ReadingListItems.URL, url);
         values.put(ReadingListItems.TITLE, message.optString("title"));
         values.put(ReadingListItems.LENGTH, message.optInt("length"));
         values.put(ReadingListItems.EXCERPT, message.optString("excerpt"));
 
--- a/mobile/android/base/StartPane.java
+++ b/mobile/android/base/StartPane.java
@@ -1,77 +1,75 @@
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.fxa.activities.FxAccountGetStartedActivity;
-import org.mozilla.gecko.util.HardwareUtils;
 
-import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
 import android.view.GestureDetector;
+import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
 import android.widget.Button;
 
-public class StartPane extends Activity {
+public class StartPane extends DialogFragment {
 
     @Override
-    public void onCreate(Bundle bundle) {
-        super.onCreate(bundle);
-        setContentView(R.layout.onboard_start_pane);
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setStyle(DialogFragment.STYLE_NO_TITLE, 0);
+    }
 
-        final Button accountButton = (Button) findViewById(R.id.button_account);
-        accountButton.setOnClickListener(new OnClickListener() {
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+        final View view = inflater.inflate(R.layout.onboard_start_pane, container, false);
+        final Button browserButton = (Button) view.findViewById(R.id.button_browser);
+        browserButton.setOnClickListener(new OnClickListener() {
 
             @Override
             public void onClick(View v) {
                 Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.BUTTON, "firstrun-sync");
-                showAccountSetup();
+
+                // StartPane is on the stack above the browser, so just dismiss this Fragment.
+                StartPane.this.dismiss();
             }
         });
 
-        final Button browserButton = (Button) findViewById(R.id.button_browser);
-        browserButton.setOnClickListener(new OnClickListener() {
+        final Button accountButton = (Button) view.findViewById(R.id.button_account);
+        accountButton.setOnClickListener(new OnClickListener() {
 
             @Override
             public void onClick(View v) {
                 Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.BUTTON, "firstrun-browser");
-                showBrowser();
+
+                final Intent intent = new Intent(getActivity(), FxAccountGetStartedActivity.class);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                startActivity(intent);
+                StartPane.this.dismiss();
             }
         });
 
-        if (!HardwareUtils.isTablet() && !HardwareUtils.isTelevision()) {
-            addDismissHandler();
-        }
-    }
-
-    private void showBrowser() {
-        // StartPane is on the stack above the browser, so just kill this activity.
-        finish();
-    }
-
-    private void showAccountSetup() {
-        final Intent intent = new Intent(this, FxAccountGetStartedActivity.class);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        startActivity(intent);
-        finish();
+        addDismissHandler(view);
+        return view;
     }
 
     // Add handler for dismissing the StartPane on a single click.
-    private void addDismissHandler() {
-        final GestureDetector gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
+    private void addDismissHandler(View view) {
+        final GestureDetector gestureDetector = new GestureDetector(getActivity(), new GestureDetector.SimpleOnGestureListener() {
             @Override
             public boolean onSingleTapUp(MotionEvent e) {
-                StartPane.this.finish();
+                StartPane.this.dismiss();
                 return true;
             }
         });
 
-        findViewById(R.id.onboard_content).setOnTouchListener(new OnTouchListener() {
+        view.findViewById(R.id.onboard_content).setOnTouchListener(new OnTouchListener() {
             @Override
             public boolean onTouch(View v, MotionEvent event) {
                 return gestureDetector.onTouchEvent(event);
             }
         });
     }
 }
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -354,18 +354,16 @@ size. -->
 <!-- Localization note (site_settings_*) : These strings are used in the "Site Settings"
      dialog that appears after selecting the "Edit Site Settings" context menu item. -->
 <!ENTITY site_settings_title3       "Site Settings">
 <!ENTITY site_settings_cancel       "Cancel">
 <!ENTITY site_settings_clear        "Clear">
 <!ENTITY site_settings_no_settings  "There are no settings to clear.">
 
 <!ENTITY reading_list_added "Page added to your Reading List">
-<!ENTITY reading_list_failed "Failed to add page to your Reading List">
-<!ENTITY reading_list_duplicate "Page already in your Reading List">
 
 <!-- Localization note (reading_list_time_minutes) : This string is used in the "Reading List"
      panel on the home page to give the user an estimate of how many minutes it will take to
      read an article. The word "minute" should be abbreviated if possible. -->
 <!ENTITY reading_list_time_minutes "&formatD;min">
 <!ENTITY reading_list_time_over_an_hour "Over an hour">
 
 <!-- Localization note : These strings are used as alternate text for accessibility.
--- a/mobile/android/base/resources/drawable/edit_text_default.xml
+++ b/mobile/android/base/resources/drawable/edit_text_default.xml
@@ -5,18 +5,20 @@
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 
     <!-- Make sure the border only appears at the bottom of the background -->
     <item
         android:top="-2dp"
         android:right="-2dp"
         android:left="-2dp">
         <shape>
-            <!-- Padding creates vertical space between the text and the underline -->
+            <!-- Padding creates vertical space between the text and the underline,
+                 as well as right padding for search icon/clear button -->
             <padding
                 android:top="@dimen/search_bar_padding_y"
-                android:bottom="@dimen/search_bar_padding_y"/>
+                android:bottom="@dimen/search_bar_padding_y"
+                android:right="@dimen/search_bar_padding_right"/>
             <solid android:color="@android:color/transparent"/>
             <stroke android:width="1dp" android:color="@color/edit_text_default"/>
         </shape>
     </item>
 
 </layer-list>
--- a/mobile/android/base/resources/drawable/edit_text_focused.xml
+++ b/mobile/android/base/resources/drawable/edit_text_focused.xml
@@ -5,19 +5,21 @@
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 
     <!-- Make sure the border only appears at the bottom of the background -->
     <item
         android:top="-3dp"
         android:right="-3dp"
         android:left="-3dp">
         <shape>
-            <!-- Padding creates vertical space between the text and the underline -->
+            <!-- Padding creates vertical space between the text and the underline,
+                 as well as right padding for search icon/clear button -->
             <padding
                 android:top="@dimen/search_bar_padding_y"
-                android:bottom="@dimen/search_bar_padding_y"/>
+                android:bottom="@dimen/search_bar_padding_y"
+                android:right="@dimen/search_bar_padding_right"/>
             <solid android:color="@android:color/transparent"/>
             <!-- We apply a color filter to set the color for the selected search engine -->
             <stroke android:width="2dp" android:color="@android:color/white"/>
         </shape>
     </item>
 
 </layer-list>
--- a/mobile/android/base/resources/layout/onboard_start_pane.xml
+++ b/mobile/android/base/resources/layout/onboard_start_pane.xml
@@ -1,37 +1,37 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              style="@style/OnboardStartLayout"
+              android:layout_height="match_parent"
+              android:layout_width="wrap_content"
               android:orientation="vertical"
-              android:background="@color/onboard_start"
-              android:windowIsFloating="true">
+              android:background="@color/onboard_start">
 
     <ScrollView android:id="@+id/onboard_content"
                 android:layout_width="match_parent"
                 android:layout_height="0dp"
                 android:layout_weight="1"
                 android:fillViewport="true" >
 
         <LinearLayout android:orientation="vertical"
                       android:layout_width="match_parent"
                       android:layout_height="wrap_content">
 
             <!-- Empty spacer view -->
             <View android:layout_width="0dp"
                   android:layout_height="0dp"
                   android:layout_weight="1"/>
 
-            <RelativeLayout android:layout_width="match_parent"
-                            android:layout_height="wrap_content"
+            <RelativeLayout android:layout_width="wrap_content"
+                            android:layout_height="match_parent"
                             android:paddingTop="15dp">
 
                 <ImageView android:id="@+id/image_shield"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_alignParentTop="true"
                            android:layout_centerHorizontal="true"
                            android:paddingRight="92dp"
@@ -54,44 +54,45 @@
                            android:layout_below="@id/image_shield"
                            android:layout_marginTop="23dp"
                            android:src="@drawable/large_icon"
                            android:contentDescription="@string/onboard_empty_contentDescription"/>
 
                 <ImageView android:id="@+id/image_sync"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
+                           android:layout_centerHorizontal="true"
                            android:layout_below="@id/image_shield"
-                           android:layout_toLeftOf="@id/image_logo"
-                           android:layout_marginRight="30dp"
+                           android:paddingRight="200dp"
                            android:src="@drawable/onboard_start_sync"
                            android:contentDescription="@string/onboard_empty_contentDescription"/>
 
                 <ImageView android:id="@+id/image_addon"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
-                           android:layout_below="@id/image_private"
-                           android:layout_toRightOf="@id/image_logo"
-                           android:layout_marginLeft="30dp"
+                           android:layout_centerHorizontal="true"
+                           android:layout_below="@id/image_shield"
+                           android:paddingLeft="200dp"
                            android:src="@drawable/onboard_start_addon"
                            android:contentDescription="@string/onboard_empty_contentDescription"/>
 
                 <TextView android:id="@+id/text_message"
-                          android:layout_width="wrap_content"
+                          android:layout_width="match_parent"
                           android:layout_height="wrap_content"
                           android:layout_below="@id/image_logo"
                           android:layout_centerHorizontal="true"
                           android:layout_marginTop="30dp"
+                          android:gravity="center"
                           android:padding="10sp"
                           android:text="@string/onboard_start_message"
                           android:textAppearance="@style/OnboardStartTextAppearance"
                           android:textSize="23sp" />
 
                 <TextView android:layout_width="295dp"
-                          android:layout_height="wrap_content"
+                          android:layout_height="match_parent"
                           android:layout_gravity="center"
                           android:gravity="center"
                           android:layout_below="@id/text_message"
                           android:layout_centerHorizontal="true"
                           android:lineSpacingExtra="12sp"
                           android:padding="10sp"
                           android:text="@string/onboard_start_subtext"
                           android:textAppearance="@style/OnboardStartTextAppearance.Subtext" />
@@ -119,9 +120,9 @@
                 android:text="@string/onboard_start_button_account"/>
 
         <Button android:id="@+id/button_browser"
                 style="@style/Widget.Onboard.Start.Button"
                 android:layout_marginTop="3px"
                 android:text="@string/onboard_start_button_browser"/>
 
     </LinearLayout>
-</LinearLayout>
+</LinearLayout>
\ No newline at end of file
--- a/mobile/android/base/resources/values-large-v11/styles.xml
+++ b/mobile/android/base/resources/values-large-v11/styles.xml
@@ -163,18 +163,13 @@
     </style>
 
     <style name="TabsPanelItem.TextAppearance.Linkified.LearnMore">
         <item name="android:layout_height">match_parent</item>
         <item name="android:gravity">center</item>
         <item name="android:layout_gravity">center</item>
     </style>
 
-    <style name="OnboardStartLayout">
-        <item name="android:layout_height">wrap_content</item>
-        <item name="android:layout_width">400dp</item>
-    </style>
-
     <style name="TextAppearance.UrlBar.Title" parent="TextAppearance.Medium">
         <item name="android:textSize">16sp</item>
     </style>
 
 </resources>
--- a/mobile/android/base/resources/values/search_dimens.xml
+++ b/mobile/android/base/resources/values/search_dimens.xml
@@ -9,16 +9,19 @@
     <dimen name="progress_bar_height">3dp</dimen>
 
     <!-- Size of the text for query input and suggestions -->
     <dimen name="query_text_size">16sp</dimen>
 
     <dimen name="search_row_padding">15dp</dimen>
     <dimen name="search_bar_padding_y">10dp</dimen>
 
+    <!-- Padding to account for search engine icon/clear button -->
+    <dimen name="search_bar_padding_right">25dp</dimen>
+
     <dimen name="search_history_drawable_padding">10dp</dimen>
 
     <!-- Widget Buttons -->
     <dimen name="widget_header_height">70dp</dimen>
     <dimen name="widget_button_offset">-50dp</dimen>
     <dimen name="widget_button_padding">45dp</dimen>
     <dimen name="widget_text_size">14sp</dimen>
     <dimen name="widget_padding">7dp</dimen>
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -830,20 +830,16 @@
 
     <!-- Make the share overlay activity appear like an overlay. -->
     <style name="ShareOverlayActivity">
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:backgroundDimEnabled">true</item>
     </style>
-    <style name="OnboardStartLayout">
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">match_parent</item>
-    </style>
 
     <style name="OnboardStartTextAppearance">
         <item name="android:textColor">#5F636B</item>
     </style>
 
     <style name="OnboardStartTextAppearance.Subtext">
         <item name="android:textSize">18sp</item>
     </style>
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -289,18 +289,16 @@
   <string name="edit_mode_cancel">&edit_mode_cancel;</string>
 
   <string name="site_settings_title">&site_settings_title3;</string>
   <string name="site_settings_cancel">&site_settings_cancel;</string>
   <string name="site_settings_clear">&site_settings_clear;</string>
   <string name="site_settings_no_settings">&site_settings_no_settings;</string>
 
   <string name="reading_list_added">&reading_list_added;</string>
-  <string name="reading_list_failed">&reading_list_failed;</string>
-  <string name="reading_list_duplicate">&reading_list_duplicate;</string>
   <string name="reading_list_time_minutes">&reading_list_time_minutes;</string>
   <string name="reading_list_time_over_an_hour">&reading_list_time_over_an_hour;</string>
 
   <string name="page_action_dropmarker_description">&page_action_dropmarker_description;</string>
 
   <string name="contextmenu_open_new_tab">&contextmenu_open_new_tab;</string>
   <string name="contextmenu_open_private_tab">&contextmenu_open_private_tab;</string>
   <string name="contextmenu_remove">&contextmenu_remove;</string>
--- a/mobile/android/chrome/content/Reader.js
+++ b/mobile/android/chrome/content/Reader.js
@@ -5,20 +5,16 @@
 "use strict";
 
 let Reader = {
   // Version of the cache database schema
   DB_VERSION: 1,
 
   DEBUG: 0,
 
-  READER_ADD_SUCCESS: 0,
-  READER_ADD_FAILED: 1,
-  READER_ADD_DUPLICATE: 2,
-
   // Don't try to parse the page if it has too many elements (for memory and
   // performance reasons)
   MAX_ELEMS_TO_PARSE: 3000,
 
   _requests: {},
 
   get isEnabledForParseOnLoad() {
     delete this.isEnabledForParseOnLoad;
@@ -33,17 +29,17 @@ let Reader = {
     readerModeCallback: function(tabID) {
       Messaging.sendRequest({
         type: "Reader:Toggle",
         tabID: tabID
       });
     },
 
     readerModeActiveCallback: function(tabID) {
-      Reader.addTabToReadingList(tabID);
+      Reader._addTabToReadingList(tabID);
       UITelemetry.addEvent("save.1", "pageaction", null, "reader");
     },
   },
 
   updatePageAction: function(tab) {
     if (this.pageAction.id) {
       PageActions.remove(this.pageAction.id);
       delete this.pageAction.id;
@@ -88,60 +84,59 @@ let Reader = {
         if (aData.startsWith("reader.parse-on-load.")) {
           this.isEnabledForParseOnLoad = this.getStateForParseOnLoad();
         }
         break;
       }
     }
   },
 
-  addTabToReadingList: function(tabID) {
+  _addTabToReadingList: function(tabID) {
     let tab = BrowserApp.getTabForId(tabID);
     let currentURI = tab.browser.currentURI;
-    let url = currentURI.spec;
     let urlWithoutRef = currentURI.specIgnoringRef;
 
-    let sendResult = function(result, article) {
-      article = article || {};
-
-      Messaging.sendRequest({
-        type: "Reader:AddToList",
-        result: result,
-        title: truncate(article.title, MAX_TITLE_LENGTH),
-        url: truncate(url, MAX_URI_LENGTH),
-        length: article.length,
-        excerpt: article.excerpt
-      });
-    }.bind(this);
-
-    let handleArticle = function(article) {
-      if (!article) {
-        sendResult(this.READER_ADD_FAILED, null);
+    this.getArticleFromCache(urlWithoutRef, (article) => {
+      // If the article is already in the cache, just use that.
+      if (article) {
+        this.addArticleToReadingList(article);
         return;
       }
 
-      this.storeArticleInCache(article, function(success) {
-        let result = (success ? this.READER_ADD_SUCCESS : this.READER_ADD_FAILED);
-        sendResult(result, article);
-      }.bind(this));
-    }.bind(this);
+      // Otherwise, get the article data from the tab.
+      this.getArticleForTab(tabID, urlWithoutRef, (article) => {
+        if (article) {
+          this.addArticleToReadingList(article);
+        } else {
+          // If there was a problem getting the article, just store the
+          // URL and title from the tab.
+          this.addArticleToReadingList({
+            url: urlWithoutRef,
+            title: tab.browser.contentDocument.title,
+          });
+        }
+      });
+    });
+  },
 
-    this.getArticleFromCache(urlWithoutRef, function (article) {
-      // If the article is already in reading list, bail
-      if (article) {
-        sendResult(this.READER_ADD_DUPLICATE, null);
-        return;
-      }
+  addArticleToReadingList: function(article) {
+    if (!article || !article.url) {
+      Cu.reportError("addArticleToReadingList requires article with valid URL");
+      return;
+    }
 
-      if (tabID != null) {
-        this.getArticleForTab(tabID, urlWithoutRef, handleArticle);
-      } else {
-        this.parseDocumentFromURL(urlWithoutRef, handleArticle);
-      }
-    }.bind(this));
+    Messaging.sendRequest({
+      type: "Reader:AddToList",
+      url: truncate(article.url, MAX_URI_LENGTH),
+      title: truncate(article.title || "", MAX_TITLE_LENGTH),
+      length: article.length || 0,
+      excerpt: article.excerpt || "",
+    });
+
+    this.storeArticleInCache(article);
   },
 
   getStateForParseOnLoad: function Reader_getStateForParseOnLoad() {
     let isEnabled = Services.prefs.getBoolPref("reader.parse-on-load.enabled");
     let isForceEnabled = Services.prefs.getBoolPref("reader.parse-on-load.force-enabled");
     // For low-memory devices, don't allow reader mode since it takes up a lot of memory.
     // See https://bugzilla.mozilla.org/show_bug.cgi?id=792603 for details.
     return isForceEnabled || (isEnabled && !BrowserApp.isOnLowMemoryPlatform);
@@ -256,36 +251,33 @@ let Reader = {
 
       request.onsuccess = function(event) {
         this.log("Got article from the cache DB: " + event.target.result);
         callback(event.target.result);
       }.bind(this);
     }.bind(this));
   },
 
-  storeArticleInCache: function Reader_storeArticleInCache(article, callback) {
+  storeArticleInCache: function Reader_storeArticleInCache(article) {
     this._getCacheDB(function(cacheDB) {
       if (!cacheDB) {
-        callback(false);
         return;
       }
 
       let transaction = cacheDB.transaction(cacheDB.objectStoreNames, "readwrite");
       let articles = transaction.objectStore(cacheDB.objectStoreNames[0]);
 
       let request = articles.add(article);
 
       request.onerror = function(event) {
         this.log("Error storing article in the cache DB: " + article.url);
-        callback(false);
       }.bind(this);
 
       request.onsuccess = function(event) {
         this.log("Stored article in the cache DB: " + article.url);
-        callback(true);
       }.bind(this);
     }.bind(this));
   },
 
   removeArticleFromCache: function Reader_removeArticleFromCache(url) {
     this._getCacheDB(function(cacheDB) {
       if (!cacheDB) {
         return;
--- a/mobile/android/chrome/content/WebcompatReporter.js
+++ b/mobile/android/chrome/content/WebcompatReporter.js
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
+Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 var WebcompatReporter = {
   menuItem: null,
   menuItemEnabled: null,
   init: function() {
     Services.obs.addObserver(this, "DesktopMode:Change", false);
@@ -73,15 +74,19 @@ var WebcompatReporter = {
     };
     NativeWindow.toast.show(message, "long", options);
   },
 
   reportIssue: function(url) {
     let webcompatURL = new URL("http://webcompat.com/");
     webcompatURL.searchParams.append("open", "1");
     webcompatURL.searchParams.append("url", url);
-    BrowserApp.addTab(webcompatURL.href);
+    if (PrivateBrowsingUtils.isBrowserPrivate(BrowserApp.selectedTab.browser)) {
+      BrowserApp.addTab(webcompatURL.href, {parentId: BrowserApp.selectedTab.id, isPrivate: true});
+    } else {
+      BrowserApp.addTab(webcompatURL.href);
+    }
   }
 };
 
 XPCOMUtils.defineLazyGetter(WebcompatReporter, "strings", function() {
   return Services.strings.createBundle("chrome://browser/locale/webcompatReporter.properties");
 });
--- a/mobile/android/chrome/content/aboutReader.js
+++ b/mobile/android/chrome/content/aboutReader.js
@@ -315,35 +315,19 @@ AboutReader.prototype = {
     });
   },
 
   _onReaderToggle: function Reader_onToggle() {
     if (!this._article)
       return;
 
     if (this._isReadingListItem == 0) {
-      let uptime = UITelemetry.uptimeMillis();
-      gChromeWin.Reader.storeArticleInCache(this._article, function(success) {
-        let result = gChromeWin.Reader.READER_ADD_FAILED;
-        if (success) {
-          result = gChromeWin.Reader.READER_ADD_SUCCESS;
-          UITelemetry.addEvent("save.1", "button", uptime, "reader");
-        }
-
-        let json = JSON.stringify({ fromAboutReader: true, url: this._article.url });
+      gChromeWin.Reader.addArticleToReadingList(this._article);
 
-        Messaging.sendRequest({
-          type: "Reader:AddToList",
-          result: result,
-          title: this._article.title,
-          url: this._article.url,
-          length: this._article.length,
-          excerpt: this._article.excerpt
-        });
-      }.bind(this));
+      UITelemetry.addEvent("save.1", "button", null, "reader");
     } else {
       Messaging.sendRequest({
         type: "Reader:RemoveFromList",
         url: this._article.url
       });
 
       UITelemetry.addEvent("unsave.1", "button", null, "reader");
     }
--- a/toolkit/devtools/server/actors/timeline.js
+++ b/toolkit/devtools/server/actors/timeline.js
@@ -207,17 +207,17 @@ let TimelineActor = exports.TimelineActo
     this._startTime = this.docShells[0].now();
 
     for (let docShell of this.docShells) {
       docShell.recordProfileTimelineMarkers = true;
     }
 
     if (withMemory) {
       this._memoryActor = new MemoryActor(this.conn, this.tabActor);
-      events.emit(this, "memory", Date.now(), this._memoryActor.measure());
+      events.emit(this, "memory", this._startTime, this._memoryActor.measure());
     }
     if (withTicks) {
       this._framerateActor = new FramerateActor(this.conn, this.tabActor);
       this._framerateActor.startRecording();
     }
 
     this._pullTimelineData();
     return this._startTime;
--- a/toolkit/themes/osx/global/tabprompts.css
+++ b/toolkit/themes/osx/global/tabprompts.css
@@ -31,17 +31,17 @@ tabmodalprompt {
 button {
   -moz-appearance: none;
   padding: 2px 0;
   margin: 0;
   -moz-margin-start: 8px;
   border-radius: 2px;
   color: black !important;
   background-color: hsl(0,0%,90%);
-  background-image: linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,0));
+  background-image: linear-gradient(hsla(0,0%,100%,.7), transparent);
   background-clip: padding-box;
   border: 1px solid;
   border-color: hsl(0,0%,65%) hsl(0,0%,60%) hsl(0,0%,50%);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.9) inset,
               0 1px 2px hsla(0,0%,0%,.1);
 }
 
 
@@ -49,17 +49,17 @@ button[default=true] {
   background-color: hsl(0,0%,79%);
 }
 
 button:hover {
   background-color: hsl(0,0%,96%);
 }
 
 button:hover:active {
-  background-image: linear-gradient(hsla(0,0%,100%,.2), hsla(0,0%,100%,0));
+  background-image: linear-gradient(hsla(0,0%,100%,.2), transparent);
   background-color: hsl(0,0%,70%);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
               0 1px 3px hsla(0,0%,0%,.2);
 }
 
 button:focus {
   box-shadow: 0 0 1px -moz-mac-focusring inset,
               0 0 4px 1px -moz-mac-focusring,
--- a/toolkit/themes/osx/mozapps/extensions/extensions.css
+++ b/toolkit/themes/osx/mozapps/extensions/extensions.css
@@ -792,25 +792,25 @@
 #detail-screenshot {
   -moz-margin-end: 2em;
   max-width: 300px;
   max-height: 300px;
 }
 
 #detail-screenshot[loading] {
   background-image: url("chrome://global/skin/icons/loading_16.png"),
-                    linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0));
+                    linear-gradient(rgba(255, 255, 255, 0.5), transparent);
   background-position: 50% 50%;
   background-repeat: no-repeat;
   border-radius: 3px;
 }
 
 #detail-screenshot[loading="error"] {
   background-image: url("chrome://global/skin/media/error.png"),
-                    linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0));
+                    linear-gradient(rgba(255, 255, 255, 0.5), transparent);
 }
 
 #detail-desc-container {
   margin-bottom: 2em;
 }
 
 #detail-desc, #detail-fulldesc {
   -moz-margin-start: 6px;
@@ -1147,33 +1147,33 @@ button.button-link:not([disabled="true"]
 .header-button {
   -moz-appearance: none;
   padding: 0 4px;
   margin: 0;
   height: 22px;
   border: 1px solid rgba(60,73,97,0.5);
   border-radius: @toolbarbuttonCornerRadius@;
   box-shadow: inset 0 1px rgba(255,255,255,0.25), 0 1px rgba(255,255,255,0.25);
-  background: linear-gradient(rgba(255,255,255,0.45), rgba(255,255,255,0));
+  background: linear-gradient(rgba(255,255,255,0.45), transparent);
   background-clip: padding-box;
 }
 
 .header-button .toolbarbutton-text {
   display: none;
 }
 
 .header-button[disabled="true"] .toolbarbutton-icon {
   opacity: 0.4;
 }
 
 .header-button:not([disabled="true"]):active:hover,
 .header-button[open="true"] {
   border-color: rgba(45,54,71,0.7);
   box-shadow: inset 0 0 4px rgb(45,54,71), 0 1px rgba(255,255,255,0.25);
-  background-image: linear-gradient(rgba(45,54,71,0.6), rgba(45,54,71,0));
+  background-image: linear-gradient(rgba(45,54,71,0.6), transparent);
 }
 
 /*** telemetry experiments ***/
 
 #detail-experiment-container {
   font-size: 80%;
   margin-bottom: 1em;
 }
--- a/toolkit/themes/windows/global/autocomplete.css
+++ b/toolkit/themes/windows/global/autocomplete.css
@@ -111,20 +111,20 @@ treechildren.autocomplete-treebody::-moz
   -moz-appearance: menuitem is almost right, but the hover effect is not
   transparent and is lighter than desired.
   */
   .autocomplete-richlistitem[selected="true"] {
     color: inherit;
     background-color: transparent;
     /* four gradients for the bevel highlights on each edge, one for blue background */
     background-image:
-      linear-gradient(to bottom, rgba(255,255,255,0.9) 3px, rgba(255,255,255,0) 3px),
-      linear-gradient(to right, rgba(255,255,255,0.5) 3px, rgba(255,255,255,0) 3px),
-      linear-gradient(to left, rgba(255,255,255,0.5) 3px, rgba(255,255,255,0) 3px),
-      linear-gradient(to top, rgba(255,255,255,0.4) 3px, rgba(255,255,255,0) 3px),
+      linear-gradient(to bottom, rgba(255,255,255,0.9) 3px, transparent 3px),
+      linear-gradient(to right, rgba(255,255,255,0.5) 3px, transparent 3px),
+      linear-gradient(to left, rgba(255,255,255,0.5) 3px, transparent 3px),
+      linear-gradient(to top, rgba(255,255,255,0.4) 3px, transparent 3px),
       linear-gradient(to bottom, rgba(163,196,247,0.3), rgba(122,180,246,0.3));
     background-clip: content-box;
     border-radius: 6px;
     outline: 1px solid rgb(124,163,206);
     -moz-outline-radius: 3px;
     outline-offset: -2px;
   }
 }
--- a/toolkit/themes/windows/global/inContentUI.css
+++ b/toolkit/themes/windows/global/inContentUI.css
@@ -33,32 +33,32 @@ html|html {
   }
 }
 
 @media (-moz-windows-glass) {
   *|*:root {
     /* Blame shorlander for this monstrosity. */
     background-image: /* Side gradients */
                       linear-gradient(to right,
-                                      rgba(255,255,255,0.2), rgba(255,255,255,0) 40%,
-                                      rgba(255,255,255,0) 60%, rgba(255,255,255,0.2)),
+                                      rgba(255,255,255,0.2), transparent 40%,
+                                      transparent 60%, rgba(255,255,255,0.2)),
                       /* Aero-style light beams */
                       -moz-linear-gradient(left 32deg,
                                            /* First light beam */
-                                           rgba(255,255,255,0) 19.5%, rgba(255,255,255,0.1) 20%,
+                                           transparent 19.5%, rgba(255,255,255,0.1) 20%,
                                            rgba(255,255,255,0.1) 21.5%, rgba(255,255,255,0.2) 22%,
                                            rgba(255,255,255,0.2) 25.5%, rgba(255,255,255,0.1) 26%,
-                                           rgba(255,255,255,0.1) 27.5%, rgba(255,255,255,0) 28%,
+                                           rgba(255,255,255,0.1) 27.5%, transparent 28%,
                                            /* Second light beam */
-                                           rgba(255,255,255,0) 49.5%, rgba(255,255,255,0.1) 50%,
+                                           transparent 49.5%, rgba(255,255,255,0.1) 50%,
                                            rgba(255,255,255,0.1) 52.5%, rgba(255,255,255,0.2) 53%,
                                            rgba(255,255,255,0.2) 54.5%, rgba(255,255,255,0.1) 55%,
-                                           rgba(255,255,255,0.1) 57.5%, rgba(255,255,255,0) 58%,
+                                           rgba(255,255,255,0.1) 57.5%, transparent 58%,
                                            /* Third light beam */
-                                           rgba(255,255,255,0) 87%, rgba(255,255,255,0.2) 90%),
+                                           transparent 87%, rgba(255,255,255,0.2) 90%),
                       /* Texture */
                       url("chrome://global/skin/inContentUI/background-texture.png");
   }
 }
 %endif
 
 /* Content */
 *|*.main-content {
@@ -83,17 +83,17 @@ html|html {
 @media (-moz-windows-glass) {
   /* Buttons */
   *|button,
   menulist,
   colorpicker[type="button"] {
     -moz-appearance: none;
     color: black;
     padding: 0 5px;
-    background: linear-gradient(rgba(251, 252, 253, 0.95), rgba(246, 247, 248, 0) 49%, 
+    background: linear-gradient(rgba(251, 252, 253, 0.95), transparent 49%, 
                                 rgba(211, 212, 213, 0.45) 51%, rgba(225, 226, 229, 0.3));
     background-clip: padding-box;
     border-radius: 3px;
     border: 1px solid rgba(31, 64, 100, 0.4);
     border-top-color: rgba(31, 64, 100, 0.3);
     box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.25) inset,
                 0 0 2px 1px rgba(255, 255, 255, 0.25) inset;
   }
--- a/toolkit/themes/windows/mozapps/extensions/extensions.css
+++ b/toolkit/themes/windows/mozapps/extensions/extensions.css
@@ -785,25 +785,25 @@
 #detail-screenshot {
   -moz-margin-end: 2em;
   max-width: 300px;
   max-height: 300px;
 }
 
 #detail-screenshot[loading] {
   background-image: url("chrome://global/skin/icons/loading_16.png"),
-                    linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0));
+                    linear-gradient(rgba(255, 255, 255, 0.5), transparent);
   background-position: 50% 50%;
   background-repeat: no-repeat;
   border-radius: 3px;
 }
 
 #detail-screenshot[loading="error"] {
   background-image: url("chrome://global/skin/media/error.png"),
-                    linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0));
+                    linear-gradient(rgba(255, 255, 255, 0.5), transparent);
 }
 
 #detail-desc-container {
   margin-bottom: 2em;
 }
 
 #detail-desc, #detail-fulldesc {
   -moz-margin-start: 6px;
@@ -1156,17 +1156,17 @@ button.button-link:not([disabled="true"]
   box-shadow: none;
 }
 
 .header-button {
   -moz-appearance: none;
   padding: 1px 3px;
   color: #444;
   text-shadow: 0 0 3px white;
-  background: linear-gradient(rgba(251, 252, 253, 0.95), rgba(246, 247, 248, 0) 49%, 
+  background: linear-gradient(rgba(251, 252, 253, 0.95), transparent 49%, 
                               rgba(211, 212, 213, 0.45) 51%, rgba(225, 226, 229, 0.3));
   background-clip: padding-box;
   border: 1px solid rgba(31, 64, 100, 0.4);
   border-top-color: rgba(31, 64, 100, 0.3);
   box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.25) inset,
               0 0 2px 1px rgba(255, 255, 255, 0.25) inset;
 }