Bug 870375 - back out bug 869011 for startup crashes on devices
authorMichael Wu <mwu@mozilla.com>
Thu, 09 May 2013 13:01:22 -0400
changeset 138112 7ef0ed6ea2db75c5d0f8109195d91c818d3ac594
parent 138110 6e6ec8a3432106fe2fa2b782bf26507504cb2097 (diff)
parent 138111 2795d46a9d46bbaea4ad86810c18b766d881069b (current diff)
child 138113 17f93f12b0843cf6c52e90bc88d8b2117cc745ec
push id3752
push userlsblakk@mozilla.com
push dateMon, 13 May 2013 17:21:10 +0000
treeherdermozilla-aurora@1580544aef0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs870375, 869011
milestone23.0a1
Bug 870375 - back out bug 869011 for startup crashes on devices
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -434,23 +434,26 @@ nsAccUtils::TextLength(Accessible* aAcce
   return text.Length();
 }
 
 bool
 nsAccUtils::MustPrune(Accessible* aAccessible)
 { 
   roles::Role role = aAccessible->Role();
 
-  // We don't prune buttons any more however AT don't expect children inside of
-  // button in general, we allow menu buttons to have children to make them
-  // accessible.
-  return role == roles::MENUITEM || 
-    role == roles::COMBOBOX_OPTION ||
-    role == roles::OPTION ||
-    role == roles::ENTRY ||
-    role == roles::FLAT_EQUATION ||
-    role == roles::PASSWORD_TEXT ||
-    role == roles::TOGGLE_BUTTON ||
-    role == roles::GRAPHIC ||
-    role == roles::SLIDER ||
-    role == roles::PROGRESSBAR ||
-    role == roles::SEPARATOR;
+  // Don't prune the tree for certain roles if the tree is more complex than
+  // a single text leaf.
+  return
+    (role == roles::MENUITEM ||
+     role == roles::COMBOBOX_OPTION ||
+     role == roles::OPTION ||
+     role == roles::ENTRY ||
+     role == roles::FLAT_EQUATION ||
+     role == roles::PASSWORD_TEXT ||
+     role == roles::PUSHBUTTON ||
+     role == roles::TOGGLE_BUTTON ||
+     role == roles::GRAPHIC ||
+     role == roles::SLIDER ||
+     role == roles::PROGRESSBAR ||
+     role == roles::SEPARATOR) &&
+    aAccessible->ContentChildCount() == 1 &&
+    aAccessible->ContentChildAt(0)->IsTextLeaf();
 }
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -1065,32 +1065,32 @@ HyperTextAccessible::GetTextAtOffset(int
 {
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   int32_t offset = ConvertMagicOffset(aOffset);
   if (offset < 0)
     return NS_ERROR_INVALID_ARG;
 
-  EWordMovementType wordMovementType = eDefaultBehavior;
-  bool moveForwardThenBack = true;
-
   switch (aBoundaryType) {
     case BOUNDARY_CHAR:
       return GetCharAt(aOffset, eGetAt, aText, aStartOffset, aEndOffset) ?
         NS_OK : NS_ERROR_INVALID_ARG;
 
     case BOUNDARY_WORD_START:
       *aEndOffset = FindWordBoundary(offset, eDirNext, eStartWord);
       *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eStartWord);
       return GetText(*aStartOffset, *aEndOffset, aText);
 
     case BOUNDARY_WORD_END:
-      *aStartOffset = FindWordBoundary(offset, eDirPrevious, eEndWord);
-      *aEndOffset = FindWordBoundary(*aStartOffset, eDirNext, eEndWord);
+      // Ignore the spec and follow what WebKitGtk does because Orca expects it,
+      // i.e. return a next word at word end offset of the current word
+      // (WebKitGtk behavior) instead the current word (AKT spec).
+      *aEndOffset = FindWordBoundary(offset, eDirNext, eEndWord);
+      *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eEndWord);
       return GetText(*aStartOffset, *aEndOffset, aText);
 
     case BOUNDARY_LINE_START:
     case BOUNDARY_LINE_END:
     case BOUNDARY_ATTRIBUTE_RANGE:
       return GetTextHelper(eGetAt, aBoundaryType, aOffset,
                            aStartOffset, aEndOffset, aText);
 
--- a/accessible/src/windows/msaa/IUnknownImpl.cpp
+++ b/accessible/src/windows/msaa/IUnknownImpl.cpp
@@ -2,16 +2,18 @@
 /* vim: set 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/. *
  */
 
 #include "IUnknownImpl.h"
 
+#include "nsDebug.h"
+
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 namespace mozilla {
 namespace a11y {
 
 HRESULT
--- a/accessible/tests/mochitest/hittest/test_general.html
+++ b/accessible/tests/mochitest/hittest/test_general.html
@@ -44,17 +44,17 @@ if (!MAC) {
       testChildAtPoint(txt, -1, 1, null, null);
 
       // ::MustPrune case, point is outside of root accessible.
       testChildAtPoint(txt, -10000, 10000, null, null);
 
       // Not specific case, point is inside of btn accessible.
       var btn = getAccessible("btn");
       var btnText = btn.firstChild;
-      testChildAtPoint(btn, 1, 1, btnText, btnText);
+      testChildAtPoint(btn, 1, 1, btn, btn);
   
       // Not specific case, point is outside of btn accessible.
       testChildAtPoint(btn, -1, 1, null, null);
 
       // Out of flow accessible testing, do not return out of flow accessible
       // because it's not a child of the accessible even visually it is.
       var rectArea = getNode("area").getBoundingClientRect();
       var outOfFlow = getNode("outofflow");
--- a/accessible/tests/mochitest/text/test_multiline.html
+++ b/accessible/tests/mochitest/text/test_multiline.html
@@ -331,29 +331,19 @@
                        "editable", kOk, kOk, kOk,
                        "editablebr", kTodo, kTodo, kTodo,
                        "textarea", kOk, kOk, kOk);
       testTextAtOffset(9, BOUNDARY_WORD_START, "two ", 9, 13, IDs);
       testTextAtOffset(13, BOUNDARY_WORD_START, "words\n", 13, 19, IDs);
 
       // BOUNDARY_WORD_END
       testTextAtOffset(0, BOUNDARY_WORD_END, "oneword", 0, 7, IDs);
-      testTextAtOffset(8, BOUNDARY_WORD_END, "\n\ntwo", 7, 12,
-                       "div", kOk, kOk, kOk,
-                       "divbr", kTodo, kTodo, kTodo,
-                       "editable", kOk, kOk, kOk,
-                       "editablebr", kTodo, kTodo, kTodo,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(9, BOUNDARY_WORD_END, "\n\ntwo", 7, 12,
-                       "div", kOk, kOk, kOk,
-                       "divbr", kTodo, kTodo, kTodo,
-                       "editable", kOk, kOk, kOk,
-                       "editablebr", kTodo, kTodo, kTodo,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(12, BOUNDARY_WORD_END, "\n\ntwo", 7, 12, IDs);
+      testTextAtOffset(8, BOUNDARY_WORD_END, "\n\ntwo", 7, 12, IDs);
+      testTextAtOffset(9, BOUNDARY_WORD_END, "\n\ntwo", 7, 12, IDs);
+      testTextAtOffset(12, BOUNDARY_WORD_END, " words", 12, 18, IDs);
       testTextAtOffset(13, BOUNDARY_WORD_END, " words", 12, 18,
                        "div", kOk, kOk, kOk,
                        "divbr", kOk, kOk, kOk,
                        "editable", kOk, kOk, kOk,
                        "editablebr", kOk, kOk, kOk,
                        "textarea", kOk, kOk, kOk);
 
       // BOUNDARY_LINE_START
--- a/accessible/tests/mochitest/text/test_singleline.html
+++ b/accessible/tests/mochitest/text/test_singleline.html
@@ -310,20 +310,20 @@
       testTextAtOffset(9, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
       testTextAtOffset(10, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
       testTextAtOffset(14, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
       testTextAtOffset(15, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
 
       // BOUNDARY_WORD_END
       testTextAtOffset(0, BOUNDARY_WORD_END, "hello", 0, 5, IDs);
       testTextAtOffset(1, BOUNDARY_WORD_END, "hello", 0, 5, IDs);
-      testTextAtOffset(5, BOUNDARY_WORD_END, "hello", 0, 5, IDs);
+      testTextAtOffset(5, BOUNDARY_WORD_END, " my", 5, 8, IDs);
       testTextAtOffset(6, BOUNDARY_WORD_END, " my", 5, 8, IDs);
       testTextAtOffset(7, BOUNDARY_WORD_END, " my", 5, 8, IDs);
-      testTextAtOffset(8, BOUNDARY_WORD_END, " my", 5, 8, IDs);
+      testTextAtOffset(8, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
       testTextAtOffset(9, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
       testTextAtOffset(10, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
       testTextAtOffset(14, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
       testTextAtOffset(15, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
 
       // BOUNDARY_LINE_START
       testTextAtOffset(0, BOUNDARY_LINE_START, "hello my friend", 0, 15,
                        "input", kOk, kOk, kOk,
--- a/accessible/tests/mochitest/text/test_whitespaces.html
+++ b/accessible/tests/mochitest/text/test_whitespaces.html
@@ -337,30 +337,31 @@
                        "input", kOk, kOk, kOk,
                        "div", kOk, kOk, kOk,
                        "editable", kOk, kOk, kOk,
                        "textarea", kTodo, kOk, kTodo);
 
       // BOUNDARY_WORD_END
       testTextAtOffset(0, BOUNDARY_WORD_END, "Brave", 0, 5, IDs);
       testTextAtOffset(4, BOUNDARY_WORD_END, "Brave", 0, 5, IDs);
-      testTextAtOffset(5, BOUNDARY_WORD_END, "Brave", 0, 5, IDs);
+      testTextAtOffset(5, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
       testTextAtOffset(6, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
       testTextAtOffset(8, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
-      testTextAtOffset(9, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
+      testTextAtOffset(9, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
       testTextAtOffset(10, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
       testTextAtOffset(11, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
       testTextAtOffset(15, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextAtOffset(16, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
+      testTextAtOffset(16, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
       testTextAtOffset(17, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
       testTextAtOffset(18, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
       testTextAtOffset(19, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
       testTextAtOffset(20, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
       testTextAtOffset(21, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
-      testTextAtOffset(22, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
+      testTextAtOffset(22, BOUNDARY_WORD_END, "   ran", 16, 22, ["input", "div", "editable"]);
+      testTextAtOffset(22, BOUNDARY_WORD_END, "   ran\n", 16, 23, [ "textarea" ]);
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
--- a/addon-sdk/mach_commands.py
+++ b/addon-sdk/mach_commands.py
@@ -20,17 +20,18 @@ from mach.decorators import (
 
 class JetpackRunner(MozbuildObject):
     """Run jetpack tests."""
     def run_tests(self, **kwargs):
         self._run_make(target='jetpack-tests')
 
 @CommandProvider
 class MachCommands(MachCommandBase):
-    @Command('jetpack-test', help='Runs the jetpack test suite.')
+    @Command('jetpack-test', category='testing',
+        description='Runs the jetpack test suite.')
     def run_jetpack_test(self, **params):
         # We should probably have a utility function to ensure the tree is
         # ready to run tests. Until then, we just create the state dir (in
         # case the tree wasn't built with mach).
         self._ensure_state_subdir_exists('.')
 
         jetpack = self._spawn(JetpackRunner)
 
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/data/testLocalXhr.json
@@ -0,0 +1,1 @@
+{}
--- a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/communicating-with-other-scripts.md
+++ b/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/communicating-with-other-scripts.md
@@ -16,17 +16,17 @@ included using `<script>` tags)
 ## main.js ##
 
 Your content scripts can communicate with your add-on's "main.js"
 (or any other modules you're written for your add-on) by sending it messages,
 using either the `port.emit()` API or the `postMessage()` API. See the
 articles on
 [using `postMessage()`](dev-guide/guides/content-scripts/using-postmessage.html)
 and
-[using `port`](dev-guide/guides/content-scripts//using-port.html) for details.
+[using `port`](dev-guide/guides/content-scripts/using-port.html) for details.
 
 ## Content Scripts ##
 
 Content scripts loaded into the same document can interact
 with each other directly as well as with the web content itself. However,
 content scripts which have been loaded into different documents
 cannot interact with each other.
 
--- a/addon-sdk/source/lib/sdk/context-menu.js
+++ b/addon-sdk/source/lib/sdk/context-menu.js
@@ -6,17 +6,17 @@
 module.metadata = {
   "stability": "stable"
 };
 
 const { Class, mix } = require("./core/heritage");
 const { addCollectionProperty } = require("./util/collection");
 const { ns } = require("./core/namespace");
 const { validateOptions, getTypeOf } = require("./deprecated/api-utils");
-const { URL } = require("./url");
+const { URL, isValidURI } = require("./url");
 const { WindowTracker, browserWindowIterator } = require("./deprecated/window-utils");
 const { isBrowser, getInnerId } = require("./window/utils");
 const { Ci } = require("chrome");
 const { MatchPattern } = require("./page-mod/match-pattern");
 const { Worker } = require("./content/worker");
 const { EventTarget } = require("./event/target");
 const { emit } = require('./event/core');
 const { when } = require('./system/unload');
@@ -259,17 +259,23 @@ let labelledItemRules =  mix(baseItemRul
   label: {
     map: stringOrNull,
     is: ["string"],
     ok: function (v) !!v,
     msg: "The item must have a non-empty string label."
   },
   image: {
     map: stringOrNull,
-    is: ["string", "undefined", "null"]
+    is: ["string", "undefined", "null"],
+    ok: function (url) {
+      if (!url)
+        return true;
+      return isValidURI(url);
+    },
+    msg: "Image URL validation failed"
   }
 });
 
 // Additional validation rules for Item
 let itemRules = mix(labelledItemRules, {
   data: {
     map: stringOrNull,
     is: ["string", "undefined", "null"]
--- a/addon-sdk/source/lib/sdk/io/data.js
+++ b/addon-sdk/source/lib/sdk/io/data.js
@@ -5,50 +5,75 @@
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
 
 const { Cc, Ci, Cu } = require("chrome");
 const base64 = require("../base64");
+const { defer } = require("../core/promise");
+const { newURI } = require("../url/utils");
 
 const IOService = Cc["@mozilla.org/network/io-service;1"].
   getService(Ci.nsIIOService);
 
+const { deprecateFunction } = require('../util/deprecate');
 const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm");
 const FaviconService = Cc["@mozilla.org/browser/favicon-service;1"].
                           getService(Ci.nsIFaviconService);
-const { deprecateFunction } = require("../util/deprecate");
+const AsyncFavicons = FaviconService.QueryInterface(Ci.mozIAsyncFavicons);
 
 const PNG_B64 = "data:image/png;base64,";
 const DEF_FAVICON_URI = "chrome://mozapps/skin/places/defaultFavicon.png";
 let   DEF_FAVICON = null;
 
 /**
+ * Takes URI of the page and returns a promise that resolves
+ * to the page's favicon URI.
+ * @param {String} uri
+ * @param {Function} (callback)
+ * @returns {Promise}
+ */
+
+exports.getFavicon = function getFavicon(uri, callback) {
+  let pageURI = newURI(uri);
+  let deferred = defer();
+  AsyncFavicons.getFaviconURLForPage(pageURI, function (aURI) {
+    if (aURI && aURI.spec)
+      deferred.resolve(aURI.spec.toString());
+    else
+      deferred.reject(null);
+  });
+  if (callback) deferred.promise.then(callback, callback);
+  return deferred.promise;
+};
+
+/**
  * Takes URI of the page and returns associated favicon URI.
  * If page under passed uri has no favicon then base64 encoded data URI of
  * default faveicon is returned.
  * @param {String} uri
  * @returns {String}
  */
-exports.getFaviconURIForLocation = function getFaviconURIForLocation(uri) {
+function getFaviconURIForLocation(uri) {
   let pageURI = NetUtil.newURI(uri);
   try {
     return FaviconService.getFaviconDataAsDataURL(
                   FaviconService.getFaviconForPage(pageURI));
   }
   catch(e) {
     if (!DEF_FAVICON) {
       DEF_FAVICON = PNG_B64 +
                     base64.encode(getChromeURIContent(DEF_FAVICON_URI));
     }
     return DEF_FAVICON;
   }
 }
+exports.getFaviconURIForLocation = getFaviconURIForLocation;
 
 /**
  * Takes chrome URI and returns content under that URI.
  * @param {String} chromeURI
  * @returns {String}
  */
 function getChromeURIContent(chromeURI) {
   let channel = IOService.newChannel(chromeURI, null, null);
--- a/addon-sdk/source/lib/sdk/test/httpd.js
+++ b/addon-sdk/source/lib/sdk/test/httpd.js
@@ -506,17 +506,17 @@ nsHttpServer.prototype =
       }
 
       var socket = new ServerSocket(this._port,
                                     loopback, // true = localhost, false = everybody
                                     maxConnections);
       dumpn(">>> listening on port " + socket.port + ", " + maxConnections +
             " pending connections");
       socket.asyncListen(this);
-      this._identity._initialize(port, host, true);
+      this._identity._initialize(socket.port, host, true);
       this._socket = socket;
     }
     catch (e)
     {
       dumpn("!!! could not start server on port " + port + ": " + e);
       throw Cr.NS_ERROR_NOT_AVAILABLE;
     }
   },
@@ -5173,17 +5173,16 @@ function server(port, basePath)
 
   // if you're running this, you probably want to see debugging info
   DEBUG = true;
 
   var srv = new nsHttpServer();
   if (lp)
     srv.registerDirectory("/", lp);
   srv.registerContentType("sjs", SJS_TYPE);
-  srv.identity.setPrimary("http", "localhost", port);
   srv.start(port);
 
   var thread = gThreadManager.currentThread;
   while (!srv.isStopped())
     thread.processNextEvent(true);
 
   // get rid of any pending requests
   while (thread.hasPendingEvents())
@@ -5200,17 +5199,16 @@ function startServerAsync(port, basePath
                .createInstance(Ci.nsILocalFile);
     lp.initWithPath(basePath);
   }
 
   var srv = new nsHttpServer();
   if (lp)
     srv.registerDirectory("/", lp);
   srv.registerContentType("sjs", "sjs");
-  srv.identity.setPrimary("http", "localhost", port);
   srv.start(port);
   return srv;
 }
 
 exports.nsHttpServer = nsHttpServer;
 exports.ScriptableInputStream = ScriptableInputStream;
 exports.server = server;
 exports.startServerAsync = startServerAsync;
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/lib/sdk/url/utils.js
@@ -0,0 +1,21 @@
+/* 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";
+
+module.metadata = {
+  "stability": "experimental"
+};
+
+const { Cc, Ci, Cr } = require("chrome");
+const IOService = Cc["@mozilla.org/network/io-service;1"].
+                    getService(Ci.nsIIOService);
+const { isValidURI } = require("../url");
+    
+function newURI (uri) {
+  if (!isValidURI(uri))
+    throw new Error("malformed URI: " + uri);
+  return IOService.newURI(uri, null, null);
+}
+exports.newURI = newURI;
--- a/addon-sdk/source/python-lib/cuddlefish/__init__.py
+++ b/addon-sdk/source/python-lib/cuddlefish/__init__.py
@@ -894,17 +894,19 @@ def run(arguments=sys.argv[1:], target_c
         # Generate xpi filepath
         xpi_path = XPI_FILENAME % target_cfg.name
         print >>stdout, "Exporting extension to %s." % xpi_path
         build_xpi(template_root_dir=app_extension_dir,
                   manifest=manifest_rdf,
                   xpi_path=xpi_path,
                   harness_options=harness_options,
                   limit_to=used_files,
-                  extra_harness_options=extra_harness_options)
+                  extra_harness_options=extra_harness_options,
+                  bundle_sdk=True,
+                  pkgdir=options.pkgdir)
     else:
         from cuddlefish.runner import run_app
 
         if options.profiledir:
             options.profiledir = os.path.expanduser(options.profiledir)
             options.profiledir = os.path.abspath(options.profiledir)
 
         if options.addons is not None:
@@ -926,17 +928,18 @@ def run(arguments=sys.argv[1:], target_c
                              extra_environment=extra_environment,
                              norun=options.no_run,
                              used_files=used_files,
                              enable_mobile=options.enable_mobile,
                              mobile_app_name=options.mobile_app_name,
                              env_root=env_root,
                              is_running_tests=(command == "test"),
                              overload_modules=options.overload_modules,
-                             bundle_sdk=options.bundle_sdk)
+                             bundle_sdk=options.bundle_sdk,
+                             pkgdir=options.pkgdir)
         except ValueError, e:
             print ""
             print "A given cfx option has an inappropriate value:"
             print >>sys.stderr, "  " + "  \n  ".join(str(e).split("\n"))
             retval = -1
         except Exception, e:
             if str(e).startswith(MOZRUNNER_BIN_NOT_FOUND):
                 print >>sys.stderr, MOZRUNNER_BIN_NOT_FOUND_HELP.strip()
--- a/addon-sdk/source/python-lib/cuddlefish/runner.py
+++ b/addon-sdk/source/python-lib/cuddlefish/runner.py
@@ -25,17 +25,17 @@ FILTER_ONLY_CONSOLE_FROM_ADB = re.compil
 
 # Used to detect the currently running test
 PARSEABLE_TEST_NAME = re.compile(r'TEST-START \| ([^\n]+)\n')
 
 # Maximum time we'll wait for tests to finish, in seconds.
 # The purpose of this timeout is to recover from infinite loops.  It should be
 # longer than the amount of time any test run takes, including those on slow
 # machines running slow (debug) versions of Firefox.
-RUN_TIMEOUT = 30 * 60 # 30 minutes
+RUN_TIMEOUT = 45 * 60 # 45 minutes
 
 # Maximum time we'll wait for tests to emit output, in seconds.
 # The purpose of this timeout is to recover from hangs.  It should be longer
 # than the amount of time any test takes to report results.
 OUTPUT_TIMEOUT = 60 # one minute
 
 def follow_file(filename):
     """
@@ -407,17 +407,18 @@ def run_app(harness_root_dir, manifest_r
             parseable=False, enforce_timeouts=False,
             logfile=None, addons=None, args=None, extra_environment={},
             norun=None,
             used_files=None, enable_mobile=False,
             mobile_app_name=None,
             env_root=None,
             is_running_tests=False,
             overload_modules=False,
-            bundle_sdk=True):
+            bundle_sdk=True,
+            pkgdir=""):
     if binary:
         binary = os.path.expanduser(binary)
 
     if addons is None:
         addons = []
     else:
         addons = list(addons)
 
@@ -511,17 +512,18 @@ def run_app(harness_root_dir, manifest_r
     # We delete it below after getting mozrunner to create the profile.
     from cuddlefish.xpi import build_xpi
     xpi_path = tempfile.mktemp(suffix='cfx-tmp.xpi')
     build_xpi(template_root_dir=harness_root_dir,
               manifest=manifest_rdf,
               xpi_path=xpi_path,
               harness_options=harness_options,
               limit_to=used_files,
-              bundle_sdk=bundle_sdk)
+              bundle_sdk=bundle_sdk,
+              pkgdir=pkgdir)
     addons.append(xpi_path)
 
     starttime = last_output_time = time.time()
 
     # Redirect runner output to a file so we can catch output not generated
     # by us.
     # In theory, we could do this using simple redirection on all platforms
     # other than Windows, but this way we only have a single codepath to
--- a/addon-sdk/source/python-lib/cuddlefish/xpi.py
+++ b/addon-sdk/source/python-lib/cuddlefish/xpi.py
@@ -18,32 +18,63 @@ def make_zipfile_path(localroot, localpa
 
 def mkzipdir(zf, path):
     dirinfo = zipfile.ZipInfo(path)
     dirinfo.external_attr = int("040755", 8) << 16L
     zf.writestr(dirinfo, "")
 
 def build_xpi(template_root_dir, manifest, xpi_path,
               harness_options, limit_to=None, extra_harness_options={},
-              bundle_sdk=True):
+              bundle_sdk=True, pkgdir=""):
+    IGNORED_FILES = [".hgignore", ".DS_Store", "install.rdf",
+                     "application.ini", xpi_path]
+
+    files_to_copy = {} # maps zipfile path to local-disk abspath
+    dirs_to_create = set() # zipfile paths, no trailing slash
+
     zf = zipfile.ZipFile(xpi_path, "w", zipfile.ZIP_DEFLATED)
 
     open('.install.rdf', 'w').write(str(manifest))
     zf.write('.install.rdf', 'install.rdf')
     os.remove('.install.rdf')
 
     # Handle add-on icon
     if 'icon' in harness_options:
         zf.write(str(harness_options['icon']), 'icon.png')
         del harness_options['icon']
 
     if 'icon64' in harness_options:
         zf.write(str(harness_options['icon64']), 'icon64.png')
         del harness_options['icon64']
 
+    # chrome.manifest
+    if os.path.isfile(os.path.join(pkgdir, 'chrome.manifest')):
+      files_to_copy['chrome.manifest'] = os.path.join(pkgdir, 'chrome.manifest')
+
+    # chrome folder (would contain content, skin, and locale folders typically)
+    folder = 'chrome'
+    if os.path.exists(os.path.join(pkgdir, folder)):
+      dirs_to_create.add('chrome')
+      # cp -r folder
+      abs_dirname = os.path.join(pkgdir, folder)
+      for dirpath, dirnames, filenames in os.walk(abs_dirname):
+          goodfiles = list(filter_filenames(filenames, IGNORED_FILES))
+          dirnames[:] = filter_dirnames(dirnames)
+          for dirname in dirnames:
+            arcpath = make_zipfile_path(template_root_dir,
+                                        os.path.join(dirpath, dirname))
+            dirs_to_create.add(arcpath)
+          for filename in goodfiles:
+              abspath = os.path.join(dirpath, filename)
+              arcpath = ZIPSEP.join(
+                  [folder,
+                   make_zipfile_path(abs_dirname, os.path.join(dirpath, filename)),
+                   ])
+              files_to_copy[str(arcpath)] = str(abspath)
+
     # Handle simple-prefs
     if 'preferences' in harness_options:
         from options_xul import parse_options, validate_prefs
 
         validate_prefs(harness_options["preferences"])
 
         opts_xul = parse_options(harness_options["preferences"],
                                  harness_options["jetpackID"])
@@ -58,22 +89,16 @@ def build_xpi(template_root_dir, manifes
 
     else:
         open('.prefs.js', 'wb').write("")
 
     zf.write('.prefs.js', 'defaults/preferences/prefs.js')
     os.remove('.prefs.js')
 
 
-    IGNORED_FILES = [".hgignore", ".DS_Store", "install.rdf",
-                     "application.ini", xpi_path]
-
-    files_to_copy = {} # maps zipfile path to local-disk abspath
-    dirs_to_create = set() # zipfile paths, no trailing slash
-
     for dirpath, dirnames, filenames in os.walk(template_root_dir):
         filenames = list(filter_filenames(filenames, IGNORED_FILES))
         dirnames[:] = filter_dirnames(dirnames)
         for dirname in dirnames:
             arcpath = make_zipfile_path(template_root_dir,
                                         os.path.join(dirpath, dirname))
             dirs_to_create.add(arcpath)
         for filename in filenames:
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/chrome/chrome.manifest
@@ -0,0 +1,5 @@
+content    test    chrome/content/
+skin       test    classic/1.0 chrome/skin/
+
+locale     test  en-US  chrome/locale/en-US/
+locale     test  ja-JP  chrome/locale/ja-JP/
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/chrome/chrome/content/new-window.xul
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        windowtype="test:window">
+</dialog>
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/chrome/chrome/locale/en-US/description.properties
@@ -0,0 +1,1 @@
+test=Test
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/chrome/chrome/locale/ja-JP/description.properties
@@ -0,0 +1,1 @@
+test=テスト
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/chrome/chrome/skin/style.css
@@ -0,0 +1,1 @@
+test{}
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/chrome/main.js
@@ -0,0 +1,68 @@
+/* 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 { Cu, Cc, Ci } = require('chrome');
+const Request = require('sdk/request').Request;
+const { WindowTracker } = require('sdk/deprecated/window-utils');
+const { close, open } = require('sdk/window/helpers');
+
+const XUL_URL = 'chrome://test/content/new-window.xul'
+
+const { Services } = Cu.import('resource://gre/modules/Services.jsm', {});
+const { NetUtil } = Cu.import('resource://gre/modules/NetUtil.jsm', {});
+
+exports.testChromeSkin = function(assert, done) {
+  let skinURL = 'chrome://test/skin/style.css';
+
+  Request({
+    url: skinURL,
+    overrideMimeType: 'text/plain',
+    onComplete: function (response) {
+      assert.equal(response.text, 'test{}\n', 'chrome.manifest skin folder was registered!');
+      done();
+    }
+  }).get();
+
+  assert.pass('requesting ' + skinURL);
+}
+
+exports.testChromeContent = function(assert, done) {
+  let wt = WindowTracker({
+    onTrack: function(window) {
+      if (window.document.documentElement.getAttribute('windowtype') === 'test:window') {
+      	assert.pass('test xul window was opened');
+        wt.unload();
+
+      	close(window).then(done, assert.fail);
+      }
+    }
+  });
+
+  open(XUL_URL).then(
+    assert.pass.bind(assert, 'opened ' + XUL_URL),
+    assert.fail);
+
+  assert.pass('opening ' + XUL_URL);
+}
+
+exports.testChromeLocale = function(assert) {
+  let jpLocalePath = Cc['@mozilla.org/chrome/chrome-registry;1'].
+                       getService(Ci.nsIChromeRegistry).
+                       convertChromeURL(NetUtil.newURI('chrome://test/locale/description.properties')).
+                       spec.replace(/(en\-US|ja\-JP)/, 'ja-JP');
+  let enLocalePath = jpLocalePath.replace(/ja\-JP/, 'en-US');
+
+  let jpStringBundle = Services.strings.createBundle(jpLocalePath);
+  assert.equal(jpStringBundle.GetStringFromName('test'),
+               'テスト',
+               'locales ja-JP folder was copied correctly');
+
+  let enStringBundle = Services.strings.createBundle(enLocalePath);
+  assert.equal(enStringBundle.GetStringFromName('test'),
+               'Test',
+               'locales en-US folder was copied correctly');
+}
+
+require('sdk/test/runner').runTestsFromModule(module);
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/chrome/package.json
@@ -0,0 +1,3 @@
+{
+  "id": "test-chrome"
+}
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/favicon-helpers.js
@@ -0,0 +1,74 @@
+/* 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 { Cc, Ci, Cu } = require('chrome');
+const { Loader } = require('sdk/test/loader');
+const loader = Loader(module);
+const file = require('sdk/io/file');
+const httpd = loader.require('sdk/test/httpd');
+const { pathFor } = require('sdk/system');
+const { startServerAsync } = httpd;
+const basePath = pathFor('ProfD');
+const { atob } = Cu.import("resource://gre/modules/Services.jsm", {});
+const historyService = Cc["@mozilla.org/browser/nav-history-service;1"]
+                       .getService(Ci.nsINavHistoryService);
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+const ObserverShimMethods = ['onBeginUpdateBatch', 'onEndUpdateBatch',
+  'onVisit', 'onTitleChanged', 'onDeleteURI', 'onClearHistory',
+  'onPageChanged', 'onDeleteVisits'];
+
+/*
+ * Shims NavHistoryObserver
+ */
+
+let noop = function () {}
+let NavHistoryObserver = function () {};
+ObserverShimMethods.forEach(function (method) {
+  NavHistoryObserver.prototype[method] = noop;
+});
+NavHistoryObserver.prototype.QueryInterface = XPCOMUtils.generateQI([
+  Ci.nsINavHistoryObserver
+]);
+
+/*
+ * Uses history observer to watch for an onPageChanged event,
+ * which detects when a favicon is updated in the registry.
+ */
+function onFaviconChange (uri, callback) {
+  let observer = Object.create(NavHistoryObserver.prototype, {
+    onPageChanged: {
+      value: function onPageChanged(aURI, aWhat, aValue, aGUID) {
+        if (aWhat !== Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON)
+          return;
+        if (aURI.spec !== uri)
+          return;
+        historyService.removeObserver(this);
+        callback(aValue);
+      }
+    }
+  });
+  historyService.addObserver(observer, false);
+}
+exports.onFaviconChange = onFaviconChange;
+
+/*
+ * Takes page content, a page path, and favicon binary data
+ */
+function serve ({name, favicon, port, host}) {
+  let faviconTag = '<link rel="icon" type="image/x-icon" href="/'+ name +'.ico"/>';
+  let content = '<html><head>' + faviconTag + '<title>'+name+'</title></head><body></body></html>';
+  let srv = startServerAsync(port, basePath);
+  let pagePath = file.join(basePath, name + '.html');
+  let iconPath = file.join(basePath, name + '.ico');
+  let pageStream = file.open(pagePath, 'w');
+  let iconStream = file.open(iconPath, 'wb');
+  iconStream.write(favicon);
+  iconStream.close();
+  pageStream.write(content);
+  pageStream.close();
+  return srv;
+}
+exports.serve = serve;
+
+let binFavicon = exports.binFavicon = atob('AAABAAEAEBAAAAAAAABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAEAAAAAAAAAAAAAAAEAAAABAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAwMDAAMDcwADwyqYABAQEAAgICAAMDAwAERERABYWFgAcHBwAIiIiACkpKQBVVVUATU1NAEJCQgA5OTkAgHz/AFBQ/wCTANYA/+zMAMbW7wDW5+cAkKmtAAAAMwAAAGYAAACZAAAAzAAAMwAAADMzAAAzZgAAM5kAADPMAAAz/wAAZgAAAGYzAABmZgAAZpkAAGbMAABm/wAAmQAAAJkzAACZZgAAmZkAAJnMAACZ/wAAzAAAAMwzAADMZgAAzJkAAMzMAADM/wAA/2YAAP+ZAAD/zAAzAAAAMwAzADMAZgAzAJkAMwDMADMA/wAzMwAAMzMzADMzZgAzM5kAMzPMADMz/wAzZgAAM2YzADNmZgAzZpkAM2bMADNm/wAzmQAAM5kzADOZZgAzmZkAM5nMADOZ/wAzzAAAM8wzADPMZgAzzJkAM8zMADPM/wAz/zMAM/9mADP/mQAz/8wAM///AGYAAABmADMAZgBmAGYAmQBmAMwAZgD/AGYzAABmMzMAZjNmAGYzmQBmM8wAZjP/AGZmAABmZjMAZmZmAGZmmQBmZswAZpkAAGaZMwBmmWYAZpmZAGaZzABmmf8AZswAAGbMMwBmzJkAZszMAGbM/wBm/wAAZv8zAGb/mQBm/8wAzAD/AP8AzACZmQAAmTOZAJkAmQCZAMwAmQAAAJkzMwCZAGYAmTPMAJkA/wCZZgAAmWYzAJkzZgCZZpkAmWbMAJkz/wCZmTMAmZlmAJmZmQCZmcwAmZn/AJnMAACZzDMAZsxmAJnMmQCZzMwAmcz/AJn/AACZ/zMAmcxmAJn/mQCZ/8wAmf//AMwAAACZADMAzABmAMwAmQDMAMwAmTMAAMwzMwDMM2YAzDOZAMwzzADMM/8AzGYAAMxmMwCZZmYAzGaZAMxmzACZZv8AzJkAAMyZMwDMmWYAzJmZAMyZzADMmf8AzMwAAMzMMwDMzGYAzMyZAMzMzADMzP8AzP8AAMz/MwCZ/2YAzP+ZAMz/zADM//8AzAAzAP8AZgD/AJkAzDMAAP8zMwD/M2YA/zOZAP8zzAD/M/8A/2YAAP9mMwDMZmYA/2aZAP9mzADMZv8A/5kAAP+ZMwD/mWYA/5mZAP+ZzAD/mf8A/8wAAP/MMwD/zGYA/8yZAP/MzAD/zP8A//8zAMz/ZgD//5kA///MAGZm/wBm/2YAZv//AP9mZgD/Zv8A//9mACEApQBfX18Ad3d3AIaGhgCWlpYAy8vLALKysgDX19cA3d3dAOPj4wDq6uoA8fHxAPj4+ADw+/8ApKCgAICAgAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8ACgoKCgoKCgoKCgoKCgoKCgoKCgoHAQEMbQoKCgoKCgoAAAdDH/kgHRIAAAAAAAAAAADrHfn5ASQQAAAAAAAAAArsBx0B+fkgHesAAAAAAAD/Cgwf+fn5IA4dEus/IvcACgcMAfkg+QEB+SABHushbf8QHR/5HQH5+QEdHetEHx4K7B/5+QH5+fkdDBL5+SBE/wwdJfkf+fn5AR8g+fkfEArsCh/5+QEeJR/5+SAeBwAACgoe+SAlHwFAEhAfAAAAAPcKHh8eASYBHhAMAAAAAAAA9EMdIB8gHh0dBwAAAAAAAAAA7BAdQ+wHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AADwfwAAwH8AAMB/AAAAPwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAgAcAAIAPAADADwAA8D8AAP//AAA');
--- a/addon-sdk/source/test/test-content-symbiont.js
+++ b/addon-sdk/source/test/test-content-symbiont.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 "use strict";
 
 const { Cc, Ci } = require('chrome');
 const { Symbiont } = require('sdk/content/symbiont');
-const self = require("sdk/self");
+const self = require('sdk/self');
+const { close } = require('sdk/window/helpers');
 
 function makeWindow() {
   let content =
     '<?xml version="1.0"?>' +
     '<window ' +
     'xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">' +
     '<iframe id="content" type="content"/>' +
     '</window>';
@@ -73,19 +73,19 @@ exports["test:communication with worker 
     assert.equal(message, 1, "Program gets message via onMessage.");
     contentSymbiont.removeListener('message', onMessage1);
     contentSymbiont.on('message', onMessage2);
     contentSymbiont.postMessage(2);
   };
 
   function onMessage2(message) {
     if (5 == message) {
-      window.close();
-      done();
-    } else {
+      close(window).then(done);
+    }
+    else {
       assert.equal(message, 3, "Program gets message via onMessage2.");
       contentSymbiont.postMessage(4)
     }
   }
 
   window.addEventListener("load", function onLoad() {
     window.removeEventListener("load", onLoad, false);
     let frame = window.document.getElementById("content");
--- a/addon-sdk/source/test/test-content-worker.js
+++ b/addon-sdk/source/test/test-content-worker.js
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use stirct";
 
 const { Cc, Ci } = require("chrome");
 const { setTimeout } = require("sdk/timers");
 const { LoaderWithHookedConsole } = require("sdk/test/loader");
 const { Worker } = require("sdk/content/worker");
+const { close } = require("sdk/window/helpers");
 
 const DEFAULT_CONTENT_URL = "data:text/html;charset=utf-8,foo";
 
 function makeWindow(contentURL) {
   let content =
     "<?xml version=\"1.0\"?>" +
     "<window " +
     "xmlns=\"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul\">" +
@@ -59,18 +60,18 @@ function WorkerTest(url, callback) {
       let browser = chromeWindow.document.createElement("browser");
       browser.setAttribute("type", "content");
       chromeWindow.document.documentElement.appendChild(browser);
       // Wait for about:blank load event ...
       listenOnce(browser, "load", function onAboutBlankLoad() {
         // ... before loading the expected doc and waiting for its load event
         loadAndWait(browser, url, function onDocumentLoaded() {
           callback(assert, browser, function onTestDone() {
-            chromeWindow.close();
-            done();
+
+            close(chromeWindow).then(done);
           });
         });
       });
     }, true);
   };
 }
 
 exports["test:sample"] = WorkerTest(
@@ -313,18 +314,17 @@ exports["test:chrome is unwrapped"] = fu
       window: window,
       contentScript: "new " + function WorkerScope() {
         self.postMessage(window.documentValue);
       },
       contentScriptWhen: "ready",
       onMessage: function(msg) {
         assert.ok(msg,
           "content script has an unwrapped access to chrome document");
-        window.close();
-        done();
+        close(window).then(done);
       }
     });
 
   });
 }
 
 exports["test:nothing is leaked to content script"] = WorkerTest(
   DEFAULT_CONTENT_URL,
--- a/addon-sdk/source/test/test-context-menu.js
+++ b/addon-sdk/source/test/test-context-menu.js
@@ -2692,16 +2692,57 @@ exports.testItemImage = function (test) 
     test.assertEqual(item.image, null, "Should have set the image correctly");
     test.assertEqual(menu.image, null, "Should have set the image correctly");
     test.checkMenu([item, menu], [], []);
 
     test.done();
   });
 };
 
+// Test image URL validation.
+exports.testItemImageValidURL = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+ 
+  test.assertRaises(function(){
+      new loader.cm.Item({
+        label: "item 1",
+        image: "foo"
+      })
+    }, "Image URL validation failed"
+  );
+
+  test.assertRaises(function(){
+      new loader.cm.Item({
+        label: "item 2",
+        image: false
+      })
+    }, "Image URL validation failed"
+  );
+
+  test.assertRaises(function(){
+      new loader.cm.Item({
+        label: "item 3",
+        image: 0
+      })
+    }, "Image URL validation failed"
+  );
+   
+  let imageURL = require("sdk/self").data.url("moz_favicon.ico");
+  let item4 = new loader.cm.Item({ label: "item 4", image: imageURL });
+  let item5 = new loader.cm.Item({ label: "item 5", image: null });
+  let item6 = new loader.cm.Item({ label: "item 6", image: undefined });
+
+  test.assertEqual(item4.image, imageURL, "Should be proper image URL");
+  test.assertEqual(item5.image, null, "Should be null image");
+  test.assertEqual(item6.image, undefined, "Should be undefined image");
+
+  test.done();
+}
+
 
 // Menu.destroy should destroy the item tree rooted at that menu.
 exports.testMenuDestroy = function (test) {
   test = new TestHelper(test);
   let loader = test.newLoader();
 
   let menu = loader.cm.Menu({
     label: "menu",
--- a/addon-sdk/source/test/test-frame-utils.js
+++ b/addon-sdk/source/test/test-frame-utils.js
@@ -1,71 +1,59 @@
 /* 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 { open } = require('sdk/window/utils');
 const { create } = require('sdk/frame/utils');
+const { open, close } = require('sdk/window/helpers');
 
 exports['test frame creation'] = function(assert, done) {
-  let window = open('data:text/html;charset=utf-8,Window');
-  window.addEventListener('DOMContentLoaded', function windowReady() {
-
+  open('data:text/html;charset=utf-8,Window').then(function (window) {
     let frame = create(window.document);
 
     assert.equal(frame.getAttribute('type'), 'content',
                  'frame type is content');
     assert.ok(frame.contentWindow, 'frame has contentWindow');
     assert.equal(frame.contentWindow.location.href, 'about:blank',
                  'by default "about:blank" is loaded');
     assert.equal(frame.docShell.allowAuth, false, 'auth disabled by default');
     assert.equal(frame.docShell.allowJavascript, false, 'js disabled by default');
     assert.equal(frame.docShell.allowPlugins, false,
                  'plugins disabled by default');
-    window.close();
-    done();
-  }, false);
+    close(window).then(done);
+  });
 };
 
 exports['test fram has js disabled by default'] = function(assert, done) {
-  let window = open('data:text/html;charset=utf-8,window');
-  window.addEventListener('DOMContentLoaded', function windowReady() {
-    window.removeEventListener('DOMContentLoaded', windowReady, false);
+  open('data:text/html;charset=utf-8,window').then(function (window) {
     let frame = create(window.document, {
       uri: 'data:text/html;charset=utf-8,<script>document.documentElement.innerHTML' +
            '= "J" + "S"</script>',
     });
     frame.contentWindow.addEventListener('DOMContentLoaded', function ready() {
       frame.contentWindow.removeEventListener('DOMContentLoaded', ready, false);
       assert.ok(!~frame.contentDocument.documentElement.innerHTML.indexOf('JS'),
                 'JS was executed');
 
-      window.close();
-      done();
+      close(window).then(done);
     }, false);
-
-  }, false);
+  });
 };
 
 exports['test frame with js enabled'] = function(assert, done) {
-  let window = open('data:text/html;charset=utf-8,window');
-  window.addEventListener('DOMContentLoaded', function windowReady() {
-    window.removeEventListener('DOMContentLoaded', windowReady, false);
+  open('data:text/html;charset=utf-8,window').then(function (window) {
     let frame = create(window.document, {
       uri: 'data:text/html;charset=utf-8,<script>document.documentElement.innerHTML' +
            '= "J" + "S"</script>',
       allowJavascript: true
     });
     frame.contentWindow.addEventListener('DOMContentLoaded', function ready() {
       frame.contentWindow.removeEventListener('DOMContentLoaded', ready, false);
       assert.ok(~frame.contentDocument.documentElement.innerHTML.indexOf('JS'),
                 'JS was executed');
 
-      window.close();
-      done();
+      close(window).then(done);
     }, false);
-
-  }, false);
+  });
 };
 
 require('test').run(exports);
--- a/addon-sdk/source/test/test-httpd.js
+++ b/addon-sdk/source/test/test-httpd.js
@@ -72,8 +72,21 @@ exports.testDynamicServer = function (te
 
   function done() {
     srv.stop(function() {
       test.done();
     });
   }
 
 }
+
+exports.testAutomaticPortSelection = function (test) {
+  const srv = httpd.startServerAsync(-1);
+
+  test.waitUntilDone();
+
+  const port = srv.identity.primaryPort;
+  test.assert(0 <= port && port <= 65535);
+
+  srv.stop(function() {
+    test.done();
+  });
+}
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/test-io-data.js
@@ -0,0 +1,112 @@
+/* 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 { Cc, Ci, Cu } = require('chrome');
+const { getFavicon, getFaviconURIForLocation } = require('sdk/io/data');
+const tabs = require('sdk/tabs');
+const open = tabs.open;
+const port = 8099;
+const host = 'http://localhost:' + port;
+const { onFaviconChange, serve, binFavicon } = require('./favicon-helpers');
+const { once } = require('sdk/system/events');
+const faviconService = Cc["@mozilla.org/browser/favicon-service;1"].
+                         getService(Ci.nsIFaviconService);
+
+exports.testGetFaviconCallbackSuccess = function (assert, done) {
+  let name = 'callbacksuccess'
+  let srv = serve({name: name, favicon: binFavicon, port: port, host: host});
+  let url = host + '/' + name + '.html';
+  let favicon = host + '/' + name + '.ico';
+  let tab;
+
+  onFaviconChange(url, function (faviconUrl) {
+    getFavicon(url, function (url) {
+      assert.equal(favicon, url, 'Callback returns correct favicon url');
+      complete(tab, srv, done);
+    });
+  });
+
+  open({
+    url: url,
+    onOpen: function (newTab) tab = newTab,
+    inBackground: true
+  });
+};
+
+exports.testGetFaviconCallbackFailure = function (assert, done) {
+  let name = 'callbackfailure';
+  let srv = serve({name: name, favicon: binFavicon, port: port, host: host});
+  let url = host + '/' + name + '.html';
+  let tab;
+
+  onFaviconChange(url, function (faviconUrl) {
+    once('places-favicons-expired', function () {
+      getFavicon(url, function (url) {
+        assert.equal(url, null, 'Callback returns null');
+        complete(tab, srv, done);
+      });
+    });
+    faviconService.expireAllFavicons();
+  });
+
+  open({
+    url: url,
+    onOpen: function (newTab) tab = newTab,
+    inBackground: true
+  });
+};
+
+exports.testGetFaviconPromiseSuccess = function (assert, done) {
+  let name = 'promisesuccess'
+  let srv = serve({name: name, favicon: binFavicon, port: port, host: host});
+  let url = host + '/' + name + '.html';
+  let favicon = host + '/' + name + '.ico';
+  let tab;
+
+  onFaviconChange(url, function (faviconUrl) {
+    getFavicon(url).then(function (url) {
+      assert.equal(url, favicon, 'Callback returns null');
+    }, function (err) {
+      assert.fail('Reject should not be called');
+    }).then(complete.bind(null, tab, srv, done));
+  });
+
+  open({
+    url: url,
+    onOpen: function (newTab) tab = newTab,
+    inBackground: true
+  });
+};
+
+exports.testGetFaviconPromiseFailure = function (assert, done) {
+  let name = 'promisefailure'
+  let srv = serve({name: name, favicon: binFavicon, port: port, host: host});
+  let url = host + '/' + name + '.html';
+  let tab;
+
+  onFaviconChange(url, function (faviconUrl) {
+    once('places-favicons-expired', function () {
+      getFavicon(url).then(function (url) {
+        assert.fail('success should not be called');
+      }, function (err) {
+        assert.equal(err, null, 'should call reject');
+      }).then(complete.bind(null, tab, srv, done));
+    });
+    faviconService.expireAllFavicons();
+  });
+
+  open({
+    url: url,
+    onOpen: function (newTab) tab = newTab,
+    inBackground: true
+  });
+};
+
+function complete(tab, srv, done) {
+  tab.close(function () {
+    srv.stop(done);
+  })
+}
+
+require("test").run(exports);
--- a/addon-sdk/source/test/test-page-mod.js
+++ b/addon-sdk/source/test/test-page-mod.js
@@ -370,20 +370,21 @@ exports.testRelatedTabNoRequireTab = fun
   let loader = Loader(module);
   let tab;
   let url = "data:text/html;charset=utf-8," + encodeURI("Test related worker tab 2");
   let { PageMod } = loader.require("sdk/page-mod");
   let pageMod = new PageMod({
     include: url,
     onAttach: function(worker) {
       test.assertEqual(worker.tab.url, url, "Worker.tab.url is valid");
-      worker.tab.close();
-      pageMod.destroy();
-      loader.unload();
-      test.done();
+      worker.tab.close(function() {
+        pageMod.destroy();
+        loader.unload();
+        test.done();
+      });
     }
   });
 
   tabs.open(url);
 };
 
 exports.testRelatedTabNoOtherReqs = function(test) {
   test.waitUntilDone();
@@ -421,18 +422,17 @@ exports.testWorksWithExistingTabs = func
         attachTo: ["existing", "top", "frame"],
         onAttach: function(worker) {
           test.assert(!!worker.tab, "Worker.tab exists");
           test.assertEqual(tab, worker.tab, "A worker has been created on this existing tab");
 
           timer.setTimeout(function() {
             pageModOnExisting.destroy();
             pageModOffExisting.destroy();
-            tab.close();
-            test.done();
+            tab.close(test.done.bind(test));
           }, 0);
         }
       });
 
       let pageModOffExisting = new PageMod({
         include: url,
         onAttach: function(worker) {
           test.fail("pageModOffExisting page-mod should not have attached to anything");
@@ -466,21 +466,23 @@ exports.testTabWorkerOnMessage = functio
             test.assertEqual(this.tab.url, data.url, "location is correct");
             test.assertEqual(this.tab.title, data.title, "title is correct");
             if (this.tab.url === url1) {
               worker1 = this;
               tabs.open({ url: url2, inBackground: true });
             }
             else if (this.tab.url === url2) {
               mod.destroy();
-              worker1.tab.close();
-              worker1.destroy();
-              worker.tab.close();
-              worker.destroy();
-              test.done();
+              worker1.tab.close(function() {
+                worker1.destroy();
+                worker.tab.close(function() {
+                  worker.destroy();
+                  test.done();
+                });
+              });
             }
           }
         });
       });
     }
   });
 
   tabs.open(url1);
@@ -502,21 +504,19 @@ exports.testAutomaticDestroy = function(
   loader.unload();
 
   // Then create a second tab to ensure that it is correctly destroyed
   let tabs = require("sdk/tabs");
   tabs.open({
     url: "about:",
     onReady: function onReady(tab) {
       test.pass("check automatic destroy");
-      tab.close();
-      test.done();
+      tab.close(test.done.bind(test));
     }
   });
-
 }
 
 exports.testAttachToTabsOnly = function(test) {
   test.waitUntilDone();
 
   let { PageMod } = require('sdk/page-mod');
   let openedTab = null; // Tab opened in openTabWithIframe()
   let workerCount = 0;
@@ -851,18 +851,17 @@ exports.testPageModCssAutomaticDestroy =
       loader.unload();
 
       test.assertEqual(
         style.width,
         "200px",
         "PageMod contentStyle is removed after loader's unload"
       );
 
-      tab.close();
-      test.done();
+      tab.close(test.done.bind(test));
     }
   });
 };
 
 
 exports.testPageModTimeout = function(test) {
   test.waitUntilDone();
   let tab = null
@@ -877,20 +876,21 @@ exports.testPageModTimeout = function(te
       }, 10)
       self.port.emit("scheduled", id);
     }),
     onAttach: function(worker) {
       worker.port.on("scheduled", function(id) {
         test.pass("timer was scheduled")
         worker.port.on("fired", function(data) {
           test.assertEqual(id, data, "timer was fired")
-          tab.close()
-          worker.destroy()
-          loader.unload()
-          test.done()
+          tab.close(function() {
+            worker.destroy()
+            loader.unload()
+            test.done()
+          });
         })
       })
     }
   });
 
   tabs.open({
     url: "data:text/html;charset=utf-8,timeout",
     onReady: function($) { tab = $ }
@@ -916,21 +916,22 @@ exports.testPageModcancelTimeout = funct
       clearTimeout(id1)
     }),
     onAttach: function(worker) {
       worker.port.on("failed", function() {
         test.fail("cancelled timeout fired")
       })
       worker.port.on("timeout", function(id) {
         test.pass("timer was scheduled")
-        tab.close();
-        worker.destroy();
-        mod.destroy();
-        loader.unload();
-        test.done();
+        tab.close(function() {
+          worker.destroy();
+          mod.destroy();
+          loader.unload();
+          test.done();
+        });
       })
     }
   });
 
   tabs.open({
     url: "data:text/html;charset=utf-8,cancell timeout",
     onReady: function($) { tab = $ }
   })
--- a/addon-sdk/source/test/test-tab-browser.js
+++ b/addon-sdk/source/test/test-tab-browser.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/. */
+"use strict";
 
 var timer = require("sdk/timers");
-var {Cc,Ci} = require("chrome");
+var { Cc, Ci } = require("chrome");
 
 function onBrowserLoad(callback, event) {
   if (event.target && event.target.defaultView == this) {
     this.removeEventListener("load", onBrowserLoad, true);
     let browsers = this.document.getElementsByTagName("tabbrowser");
     try {
       timer.setTimeout(function (window) {
         callback(window, browsers[0]);
--- a/addon-sdk/source/test/test-tab-utils.js
+++ b/addon-sdk/source/test/test-tab-utils.js
@@ -1,73 +1,77 @@
 'use strict';
 
 const { getTabs } = require('sdk/tabs/utils');
 const { isGlobalPBSupported, isWindowPBSupported, isTabPBSupported } = require('sdk/private-browsing/utils');
 const { browserWindows } = require('sdk/windows');
 const tabs = require('sdk/tabs');
 const { pb } = require('./private-browsing/helper');
 const { isPrivate } = require('sdk/private-browsing');
-const { openTab } = require('sdk/tabs/utils');
+const { openTab, closeTab, getTabContentWindow } = require('sdk/tabs/utils');
 const { open, close } = require('sdk/window/helpers');
 const { windows } = require('sdk/window/utils');
 const { getMostRecentBrowserWindow } = require('sdk/window/utils');
 const { fromIterator } = require('sdk/util/array');
 
 if (isGlobalPBSupported) {
   exports.testGetTabs = function(assert, done) {
     pb.once('start', function() {
       tabs.open({
-      	url: 'about:blank',
-      	inNewWindow: true,
-      	onOpen: function(tab) {
+        url: 'about:blank',
+        inNewWindow: true,
+        onOpen: function(tab) {
           assert.equal(getTabs().length, 2, 'there are two tabs');
           assert.equal(browserWindows.length, 2, 'there are two windows');
           pb.once('stop', function() {
-          	done();
+            done();
           });
           pb.deactivate();
-      	}
+        }
       });
     });
     pb.activate();
   };
 }
 else if (isWindowPBSupported) {
   exports.testGetTabs = function(assert, done) {
     open(null, {
-      features: {
-      	private: true,
-      	toolbar: true,
-      	chrome: true
+        features: {
+        private: true,
+        toolbar: true,
+        chrome: true
       }
     }).then(function(window) {
       assert.ok(isPrivate(window), 'new tab is private');
       assert.equal(getTabs().length, 1, 'there is one tab found');
       assert.equal(browserWindows.length, 1, 'there is one window found');
       fromIterator(browserWindows).forEach(function(window) {
         assert.ok(!isPrivate(window), 'all found windows are not private');
       });
       assert.equal(windows(null, {includePrivate: true}).length, 2, 'there are really two windows');
       close(window).then(done);
     });
   };
 }
 else if (isTabPBSupported) {
   exports.testGetTabs = function(assert, done) {
-    tabs.once('open', function(tab) {
-      assert.ok(isPrivate(tab), 'new tab is private');
-      assert.equal(getTabs().length, 2, 'there are two tabs found');
-      assert.equal(browserWindows.length, 1, 'there is one window');
-      tab.close(function() {
-        done();
-      });
-	});
-    openTab(getMostRecentBrowserWindow(), 'about:blank', {
+    let startTabCount = getTabs().length;
+    let tab = openTab(getMostRecentBrowserWindow(), 'about:blank', {
       isPrivate: true
     });
+
+    assert.ok(isPrivate(getTabContentWindow(tab)), 'new tab is private');
+    let utils_tabs = getTabs();
+    assert.equal(utils_tabs.length, startTabCount + 1,
+                 'there are two tabs found');
+    assert.equal(utils_tabs[utils_tabs.length-1], tab,
+                 'the last tab is the opened tab');
+    assert.equal(browserWindows.length, 1, 'there is only one window');
+    closeTab(tab);
+
+    done();
   };
 }
 
 // Test disabled because of bug 855771
 module.exports = {};
 
 require('test').run(exports);
--- a/addon-sdk/source/test/test-tabs-common.js
+++ b/addon-sdk/source/test/test-tabs-common.js
@@ -7,16 +7,17 @@ const { Loader, LoaderWithHookedConsole 
 const { browserWindows } = require('sdk/windows');
 const tabs = require('sdk/tabs');
 const { isPrivate } = require('sdk/private-browsing');
 const { openDialog } = require('sdk/window/utils');
 const { isWindowPrivate } = require('sdk/window/utils');
 const { setTimeout } = require('sdk/timers');
 const { openWebpage } = require('./private-browsing/helper');
 const { isTabPBSupported, isWindowPBSupported } = require('sdk/private-browsing/utils');
+const app = require("sdk/system/xul-app");
 
 const URL = 'data:text/html;charset=utf-8,<html><head><title>#title#</title></head></html>';
 
 // TEST: tab count
 exports.testTabCounts = function(test) {
   test.waitUntilDone();
 
   tabs.open({
@@ -349,30 +350,42 @@ exports.testPrivateAreNotListed = functi
 }
 
 // If we close the tab while being in `onOpen` listener,
 // we end up synchronously consuming TabOpen, closing the tab and still
 // synchronously consuming the related TabClose event before the second
 // loader have a change to process the first TabOpen event!
 exports.testImmediateClosing = function (test) {
   test.waitUntilDone();
+
+  let tabURL = 'data:text/html,foo';
+
   let { loader, messages } = LoaderWithHookedConsole(module, onMessage);
   let concurrentTabs = loader.require("sdk/tabs");
-  concurrentTabs.on("open", function () {
-    test.fail("Concurrent loader manager receive a tabs `open` event");
-    // It shouldn't receive such event as the other loader will just open
-    // and destroy the tab without giving a change to other loader to even know
-    // about the existance of this tab.
+  concurrentTabs.on("open", function (tab) {
+    // On Firefox, It shouldn't receive such event as the other loader will just
+    // open and destroy the tab without giving a chance to other loader to even
+    // know about the existance of this tab.
+    if (app.is("Firefox")) {
+      test.fail("Concurrent loader received a tabs `open` event");
+    }
+    else {
+      // On mobile, we can still receive an open event,
+      // but not the related ready event
+      tab.on("ready", function () {
+        test.fail("Concurrent loader received a tabs `ready` event");
+      });
+    }
   });
   function onMessage(type, msg) {
     test.fail("Unexpected mesage on concurrent loader: " + msg);
   }
 
   tabs.open({
-    url: 'about:blank',
+    url: tabURL,
     onOpen: function(tab) {
       tab.close(function () {
         test.pass("Tab succesfully removed");
         // Let a chance to the concurrent loader to receive a TabOpen event
         // on the next event loop turn
         setTimeout(function () {
           loader.unload();
           test.done();
--- a/addon-sdk/source/test/test-window-observer.js
+++ b/addon-sdk/source/test/test-window-observer.js
@@ -1,55 +1,50 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 "use strict";
 
 const { Loader } = require("sdk/test/loader");
-const timer = require("sdk/timers");
+const { open, close } = require("sdk/window/helpers");
+const { browserWindows: windows } = require("sdk/windows");
+const { isBrowser } = require('sdk/window/utils');
 
 exports["test unload window observer"] = function(assert, done) {
   // Hacky way to be able to create unloadable modules via makeSandboxedLoader.
   let loader = Loader(module);
-
-  let utils = loader.require("sdk/deprecated/window-utils");
-  let { activeBrowserWindow: activeWindow } = utils;
-  let { isBrowser } = require('sdk/window/utils');
   let observer = loader.require("sdk/windows/observer").observer;
   let opened = 0;
   let closed = 0;
+  let windowsOpen = windows.length;
 
   observer.on("open", function onOpen(window) {
     // Ignoring non-browser windows
     if (isBrowser(window))
       opened++;
   });
   observer.on("close", function onClose(window) {
     // Ignore non-browser windows & already opened `activeWindow` (unload will
     // emit close on it even though it is not actually closed).
-    if (isBrowser(window) && window !== activeWindow)
+    if (isBrowser(window))
       closed++;
   });
 
   // Open window and close it to trigger observers.
-  activeWindow.open().close();
-
-  // Unload the module so that all listeners set by observer are removed.
-  loader.unload();
-
-  // Open and close window once again.
-  activeWindow.open().close();
-
-  // Enqueuing asserts to make sure that assertion is not performed early.
-  timer.setTimeout(function () {
-    assert.equal(1, opened, "observer open was called before unload only");
-    assert.equal(1, closed, "observer close was called before unload only");
-    done();
-  }, 0);
+  open().
+    then(close).
+    then(loader.unload).
+    then(open).
+    then(close).
+    then(function() {
+      // Enqueuing asserts to make sure that assertion is not performed early.
+      assert.equal(1, opened, "observer open was called before unload only");
+      assert.equal(windowsOpen + 1, closed, "observer close was called before unload only");
+    }).
+    then(done, assert.fail);
 };
 
 if (require("sdk/system/xul-app").is("Fennec")) {
   module.exports = {
     "test Unsupported Test": function UnsupportedTest (assert) {
         assert.pass(
           "Skipping this test until Fennec support is implemented." +
           "See bug 793071");
--- a/addon-sdk/source/test/test-xhr.js
+++ b/addon-sdk/source/test/test-xhr.js
@@ -1,38 +1,38 @@
 /* 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 xhr = require('sdk/net/xhr');
 const { Loader } = require('sdk/test/loader');
 const xulApp = require('sdk/system/xul-app');
+const { data } = require('sdk/self');
 
 // TODO: rewrite test below
 /* Test is intentionally disabled until platform bug 707256 is fixed.
 exports.testAbortedXhr = function(test) {
   var req = new xhr.XMLHttpRequest();
   test.assertEqual(xhr.getRequestCount(), 1);
   req.abort();
   test.assertEqual(xhr.getRequestCount(), 0);
 };
 */
 
 exports.testLocalXhr = function(assert, done) {
   var req = new xhr.XMLHttpRequest();
   let ready = false;
 
   req.overrideMimeType('text/plain');
-  req.open('GET', module.uri);
+  req.open('GET', data.url('testLocalXhr.json'));
   req.onreadystatechange = function() {
     if (req.readyState == 4 && (req.status == 0 || req.status == 200)) {
       ready = true;
-      assert.ok(req.responseText.match(/onreadystatechange/i),
-                'XMLHttpRequest should get local files');
+      assert.equal(req.responseText, '{}\n', 'XMLHttpRequest should get local files');
     }
   };
   req.addEventListener('load', function onload() {
     req.removeEventListener('load', onload);
     assert.pass('addEventListener for load event worked');
     assert.ok(ready, 'onreadystatechange listener worked');
     assert.equal(xhr.getRequestCount(), 0, 'request count is 0');
     done();
--- a/addon-sdk/source/test/windows/test-firefox-windows.js
+++ b/addon-sdk/source/test/windows/test-firefox-windows.js
@@ -305,24 +305,25 @@ exports.testTrackWindows = function(test
 
         test.assertEqual(actions.join(), expects.slice(0, index*4).join(), expects[index*4]);
         actions.push("activate " + index);
 
         if (windows.length < 3) {
           openWindow()
         }
         else {
-          let count = windows.length;
-          for each (let win in windows) {
-            win.close(function() {
-              if (--count == 0) {
-                test.done();
-              }
+          (function closeWindows(windows) {
+            if (!windows.length)
+              return test.done();
+
+            return windows.pop().close(function() {
+              test.pass('window was closed');
+              closeWindows(windows);
             });
-          }
+          })(windows)
         }
       },
 
       onDeactivate: function(window) {
         let index = windows.indexOf(window);
 
         test.assertEqual(actions.join(), expects.slice(0, index*4 + 2).join(), expects[index*4 + 2]);
         actions.push("deactivate " + index)
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -376,16 +376,17 @@ pref("dom.mozBrowserFramesEnabled", true
 // We'll run out of PIDs on UNIX-y systems before we hit this limit.
 pref("dom.ipc.processCount", 100000);
 
 pref("dom.ipc.browser_frames.oop_by_default", false);
 
 // Temporary permission hack for WebSMS
 pref("dom.sms.enabled", true);
 pref("dom.sms.strict7BitEncoding", false); // Disabled by default.
+pref("dom.sms.requestStatusReport", true); // Enabled by default.
 
 // Temporary permission hack for WebContacts
 pref("dom.mozContacts.enabled", true);
 
 // WebAlarms
 pref("dom.mozAlarms.enabled", true);
 
 // SimplePush
@@ -684,8 +685,15 @@ pref("b2g.version", @MOZ_B2G_VERSION@);
 
 // Disable console buffering to save memory.
 pref("consoleservice.buffered", false);
 
 #ifdef MOZ_WIDGET_GONK
 // Performance testing suggests 2k is a better page size for SQLite.
 pref("toolkit.storage.pageSize", 2048);
 #endif
+
+// Enable captive portal detection.
+pref("captivedetect.canonicalURL", "http://detectportal.firefox.com/success.txt");
+pref("captivedetect.canonicalContent", "success\n");
+
+// The url of the manifest we use for ADU pings.
+pref("ping.manifestURL", "https://marketplace.firefox.com/packaged.webapp");
--- a/b2g/chrome/content/forms.js
+++ b/b2g/chrome/content/forms.js
@@ -180,16 +180,17 @@ let FormVisibility = {
 
 let FormAssistant = {
   init: function fa_init() {
     addEventListener("focus", this, true, false);
     addEventListener("blur", this, true, false);
     addEventListener("resize", this, true, false);
     addEventListener("submit", this, true, false);
     addEventListener("pagehide", this, true, false);
+    addEventListener("beforeunload", this, true, false);
     addEventListener("input", this, true, false);
     addEventListener("keydown", this, true, false);
     addMessageListener("Forms:Select:Choice", this);
     addMessageListener("Forms:Input:Value", this);
     addMessageListener("Forms:Select:Blur", this);
     addMessageListener("Forms:SetSelectionRange", this);
   },
 
@@ -287,17 +288,19 @@ let FormAssistant = {
 
         if (this.isFocusableElement(target)) {
           this.showKeyboard(target);
           this.updateSelection();
         }
         break;
 
       case "pagehide":
-        // We are only interested to the pagehide event from the root document.
+      case "beforeunload":
+        // We are only interested to the pagehide and beforeunload events from
+        // the root document.
         if (target && target != content.document) {
           break;
         }
         // fall through
       case "blur":
       case "submit":
         if (this.focusedElement) {
           this.hideKeyboard();
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -159,16 +159,21 @@ SettingsListener.observe('language.curre
     function(value) {
       Services.prefs.setCharPref('dom.mms.retrieval_mode', value);
   });
 
   SettingsListener.observe('ril.sms.strict7BitEncoding.enabled', false,
     function(value) {
       Services.prefs.setBoolPref('dom.sms.strict7BitEncoding', value);
   });
+
+  SettingsListener.observe('ril.sms.requestStatusReport.enabled', true,
+    function(value) {
+      Services.prefs.setBoolPref('dom.sms.requestStatusReport', value);
+  });
 })();
 
 //=================== DeviceInfo ====================
 Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
 Components.utils.import('resource://gre/modules/ctypes.jsm');
 (function DeviceInfoToSettings() {
   XPCOMUtils.defineLazyServiceGetter(this, 'gSettingsService',
                                      '@mozilla.org/settingsService;1',
new file mode 100644
--- /dev/null
+++ b/b2g/config/emulator/config.json
@@ -0,0 +1,22 @@
+{
+    "config_version": 2,
+    "tooltool_manifest": "releng-emulator.tt",
+    "mock_target": "mozilla-centos6-x86_64",
+    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel", "git"],
+    "mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
+    "build_targets": ["droid", "package-emulator"],
+    "upload_files": [
+        "{workdir}/out/emulator.tar.gz",
+        "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
+        "{workdir}/sources.xml"
+    ],
+    "gecko_l10n_root": "http://hg.mozilla.org/l10n-central",
+    "gaia": {
+        "l10n": {
+            "vcs": "hgtool",
+            "root": "http://hg.mozilla.org/gaia-l10n"
+        }
+    },
+    "b2g_manifest": "emulator.xml",
+    "b2g_manifest_branch": "master"
+}
new file mode 100644
--- /dev/null
+++ b/b2g/config/emulator/releng-emulator.tt
@@ -0,0 +1,2 @@
+[
+]
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -87,16 +87,19 @@ include $(topsrcdir)/config/config.mk
 ifdef _MSC_VER
 # Always enter a Windows program through wmain, whether or not we're
 # a console application.
 WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
 endif
 
 ifeq ($(OS_ARCH),WINNT)
 RCINCLUDE = splash.rc
+# Rebuild firefox.exe if the manifest changes - it's included by splash.rc.
+# (this dependency should really be just for firefox.exe, not other targets)
+EXTRA_DEPS += $(PROGRAM).manifest
 ifndef GNU_CC
 RCFLAGS += -DMOZ_PHOENIX -I$(srcdir)
 else
 RCFLAGS += -DMOZ_PHOENIX --include-dir $(srcdir)
 endif
 endif
 
 ifeq ($(OS_ARCH),OS2)
--- a/browser/app/firefox.exe.manifest
+++ b/browser/app/firefox.exe.manifest
@@ -21,14 +21,19 @@
 </dependency>
 <ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
   <ms_asmv3:security>
     <ms_asmv3:requestedPrivileges>
       <ms_asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" />
     </ms_asmv3:requestedPrivileges>
   </ms_asmv3:security>
 </ms_asmv3:trustInfo>
+  <ms_asmv3:application xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
+    <ms_asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+      <dpiAware>true</dpiAware>
+    </ms_asmv3:windowsSettings>
+  </ms_asmv3:application>
   <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
     <application>
       <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
     </application>
   </compatibility>
 </assembly>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -598,18 +598,18 @@ pref("network.protocol-handler.expose.nn
 pref("accessibility.typeaheadfind", false);
 pref("accessibility.typeaheadfind.timeout", 5000);
 pref("accessibility.typeaheadfind.linksonly", false);
 pref("accessibility.typeaheadfind.flashBar", 1);
 
 // plugin finder service url
 pref("pfs.datasource.url", "https://pfs.mozilla.org/plugins/PluginFinderService.php?mimetype=%PLUGIN_MIMETYPE%&appID=%APP_ID%&appVersion=%APP_VERSION%&clientOS=%CLIENT_OS%&chromeLocale=%CHROME_LOCALE%&appRelease=%APP_RELEASE%");
 
-// by default we show an infobar message when pages require plugins the user has not installed, or are outdated
-pref("plugins.hide_infobar_for_missing_plugin", false);
+// by default we show an infobar message when pages require plugins that are blocked, or are outdated
+pref("plugins.hide_infobar_for_blocked_plugin", false);
 pref("plugins.hide_infobar_for_outdated_plugin", false);
 
 pref("plugins.update.url", "https://www.mozilla.org/%LOCALE%/plugincheck/");
 pref("plugins.update.notifyUser", false);
 
 pref("plugins.click_to_play", false);
 
 // display door hanger if flash not installed
@@ -1104,19 +1104,16 @@ pref("devtools.chrome.enabled", false);
 pref("devtools.theme", "light");
 
 // Display the introductory text
 pref("devtools.gcli.hideIntro", false);
 
 // How eager are we to show help: never=1, sometimes=2, always=3
 pref("devtools.gcli.eagerHelper", 2);
 
-// Do we allow the 'pref set' command
-pref("devtools.gcli.allowSet", false);
-
 // Remember the Web Console filters
 pref("devtools.webconsole.filter.network", true);
 pref("devtools.webconsole.filter.networkinfo", true);
 pref("devtools.webconsole.filter.csserror", true);
 pref("devtools.webconsole.filter.cssparser", true);
 pref("devtools.webconsole.filter.exception", true);
 pref("devtools.webconsole.filter.jswarn", true);
 pref("devtools.webconsole.filter.error", true);
@@ -1202,17 +1199,17 @@ pref("pdfjs.previousHandler.preferredAct
 pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
 
 // The maximum amount of decoded image data we'll willingly keep around (we
 // might keep around more than this, but we'll try to get down to this value).
 // (This is intentionally on the high side; see bug 746055.)
 pref("image.mem.max_decoded_image_kb", 256000);
 
 // Default social providers
-pref("social.manifest.facebook", "{\"origin\":\"https://www.facebook.com\",\"name\":\"Facebook Messenger\",\"workerURL\":\"https://www.facebook.com/desktop/fbdesktop2/socialfox/fbworker.js.php\",\"iconURL\":\"data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAX0lEQVQ4jWP4%2F%2F8%2FAyUYTFhHzjgDxP9JxGeQDSBVMxgTbUBCxer%2Fr999%2BQ8DJBuArJksA9A10s8AXIBoA0B%2BR%2FY%2FjD%2BEwoBoA1yT5v3PbdmCE8MAshhID%2FUMoDgzUYIBj0Cgi7ar4coAAAAASUVORK5CYII%3D\",\"sidebarURL\":\"https://www.facebook.com/desktop/fbdesktop2/?socialfox=true\",\"icon32URL\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAADbklEQVRYCc1Xv08UQRj99tctexAuCEFjRE0kGBEtLDSGqIWNxkYKbTAxNlY2JhaGWltNtNFeKgsKKxITK43/gCYW+IsoRhA4D47bH7fn9+bcvdm5JR7sefolC3Ozu9978+bNN7PayUv3HN3umdY0Y6IWBtSJ0HSTarXqTOiuTep6Lj+tdxAcA8RAgSmwdd2aCDs0clldYALb/FvgYVhjmfliVA2XpjEgWo0Attn42Z6WH1RFor5ehwo9XQIUZMoVn4qlCoVMSo62EvD8Kh0b3U2Xz43R2PBO6mUCGDlAf65V6MadZzT/rUimoccc2kYA4BfPHqJb105RzjJigKhRq9kEJUBIjgYVuXeL7SAI6eD+Abp5dTwVHOmEHxT50d8WBYJqSOdPj5BjW8gZR8UNqFR2xagx/65XFYaMH+BGWwiYpi4UkBPPLxTp9v1Z+lHc4DWvCQXWmIy6EjITgKowVd5Jjv7N3Hd6y5esigoOwpkJIAmMpZpLJGdiaaC4F0UmAj6bD84GCEwmB/qxMmRilmnwb/mpjAocHh4UEoNAt5NLZB7oy9OJo0PxqkAtePdhiSqunyC1LQUwWMPQaOr6GRre258Ajn4cP7KHcEXhsxpXbj+lT19X2TMNGTLVAcjcalS8gDwsQ2UOMhH4k8FkcrEn5E5ub2sKohxLK2VR77Hl9RUcsrgeRIEiVOT6z+tDbIeLy+vk+kGTCbXxycet6xhl//3f6bJEkdHYhA+mLtDIvoH4ieev5+juoxdk5+pjhALYEdXIpEB5w+NlSKSzqVQ/+H7IO6BLtl3fngGMiqhGJgIwlM6qpyUGFjySdk8m0Zg0ubeD7X9OIDEFajltRQgUJaUKx69tdgaQa0FMADuahZPMFtcEwNPm2hA7ZI5sK4aoE2NvYI+o8hkCIe7CwTv68zS0q9Dk5vpbm/8FXxitSzmMFHpsGj0wyLUheTwD2Y9fVgh1Ae0EPUgD9241ZEnld+v5kgnVZ/8fE0brVh5BK+1oCqKKF72Dk7HwBsssB/pklU1dfChy3S659H5+uelgIb+8WRv1/uGTV9Sdb5wJFlfW6fPCalMhwhSU1j2xKwKbP838GcOwJja4TqO0bjdmXxYTy1EYjFdCWoCEYZhseH/GDL3yJPHnuW6YmT7P1SlIA4768Hke4vOcsX8BE346lLHhDUQAAAAASUVORK5CYII=\", \"icon64URL\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAACNNJREFUeNrtm3tw1NUVxz/399hHHkgCaCBGEFEEREVFYFQcSoOKdkZay4z+4dDpYIsjHWx1WoTMhFi1gzBSpVgVGbU4U1sHfPESKODwEEnRYDFAICEIeZIQshs2u/v73ds/drMsyW7YLEkl2Z6Z32yy+9v7u+fc7znne8+5KzgvAjDunzlv0M13PjDZ6c4cARj0WhEoaZ1tOn3yq9XLf/tNU0O1D5Ad7wq/OpxpaXOL1j5uZAwuaGlVgwNBhULRm0XXBG6HZrlNa9uRrzfM+3DlgjIgGMsA7rl/XDdHOnNf9vosTfVuvTsaQhdkZ4iykh2rHtqydvkxwI58BhjTfv7MmP55E9/1nLNdfU15ACkVvoAaMCRvRPa+re9+DgTaPjMAx+DrJv3M67Mz+6LybWLb4NfTHhxzx31DDhZvOtqGAgNwWbjGICV9XQJB0e/KobcOP1i8qTzaAEYgaDtNU/V5A9hSaUFLuQEt2gVQSgml+j4CUAIppYgK/m0GkCjZ9xGAUNAu0LUhgJRAAAIVzwBSqVRQH4hlAClRKZAFhOgEASoFECBR8QwgUyQGdJT/B8HzCEiBNKhUJzEgBYIgQsTJAkohe9oFZHgHKvQoHtZ9K3tewfiixXABLdoFeuSSEmkF+PH4QTz7+M3o+ENptzvGtS36uSwmjMpAYF10XCllHCYoe84FlLS555Zs5jx6J6ahY+iCl98pJiDNS1hwSZop+cm91zJmxEBefGsPlu1AxKC67V3gf5oGlZSMuz6Dp2fdhWnoAEwaN5T5hsYLb+4hKB1dcgelFDpB8ifk8thDt3DO5+fZxRvxBV0IjQR0EB3KfD1GhJS0GZnnYuGcKTgdF9ZWx4/No/BJjUUrdtJqm4iL+K5SCmSAiWMHMevhcQzNzaa6ron5SzfQ7HeiaSKx+au4m6HupcJKSYZdZVI4dypuV2yo3zoql0VP3cOiFV/Q4jdiGkGhQFqMGpbJL346kbE3DEYIQWNTC39Ysp4Gr4HQtZDyiRhA0NlmSHZbRM7pr1H0m6lckeHqdGXG3jCYoqfupeC17bT49fNRXIFSNrkDTGbNGM9dtw1D10M1DI/Xx3NLP6OqETRdDy1eglPT4rqA7K56gCIrXfHCvHwGZqUnBMtR113FS/N+xHPLtuJpDa1mVobg0emjmX7vqEjsUErhaw1Q8Mo6yk4F0A1HeOW7kIlFx/u7jworRabLpmhuPjmD+iG7YNDrrhnIS09P5cW/buOeO67lkftvJt3tDE06PE7Qsnh++QYOHPOim86wcVUS0+whJug0ghTMmcK1V2eH8m2UHP++nrwhAyIwjiXDcrN5vXAGhqGhFBeMYUvJ0re2sPfgGTTDGUZrEogVopMgmGQWUCgMEWTBE5MZPSLngnGqas/w9j92s31fJfmThvPM7HyMMKRj+qgmOiBHSsnr73/B5r1V6A53KD4k3bFS8dNgckFQoWPxu1kTGDc6N7JqzR4ff/+smE+2H8FSLkx3FluLawhaG3n2iXwcppGoV/Hemt18tK0c3UwLIfUS2nVafBeQJNUXkAF+/dht3H37cKSUBC2bTTv+w98++YazPg1dT0NoIUhruoMd+2sJrtjI7381rQM3iCVrN33N++tL0c30xFNdp0GQeFRYQhcRIO0gv5xxE/fdfSO2bfNVSTmrPtxLZW0A3XSh6VporaLG1XQHu0pOU/TaOhY8+QAuZ3w6vHnnQd74536EkZ50wOsSE0zcugolbWZOG8GM/LGUVdSw6sM97D/UgGa60QxXzMJDZAq6yb7SJgr//CkLn5pOmsvR4Z5dxUdZ9t6XoKfFjNyXkqZjuoBUCpGgCyhp8eDdQ5k++UaWrdrMlr2VSFxoZlpE8YtNWGgGXx9ppnDZpxTMfTCS8gAOlJ5g8ds7kCItTIi6j6FqMVxAC2sV2RB1ekmLCTcNpH+myeyFH7BxT1Voopoe4RKJXQqhmxw45mXh0o/xeH0opThcXs2iv2wmoFyhAnbC4yX+3PgISMDShrA5XHGa3d9UITRniIeTfHASmsGhEz7mL/mI2TPv4sU3t+KzHAnu7JKpCosOkcSIICAB5hZE0OiRCM0Iwb0b6LPQdI5W+Zn/yucoYYayRk+16eK1xqRMDAHtA0r3lep0lNAjO8kfpCpMqpTF4xZEUqA7rIlOCiKpgADVWXc4FQwgEfHPB5AiByTixIDUCYJx+wJoqdIcJV5VOAWygEZcF7BToT2upFDKtuz2BrAtf8v3mju972cBJX2exso6ok6N64BhOtM11xXXPBz6v6340PcuO+DZfaJkzWqgqY3L64Bqaaz0ZV45Mkc308dG2kd97FLSaq4v317gazr5HeCLRoACFTxbfeBw+oDhWYYj4/rw+30H+rb/VMPxXQsbKnbuABqJOi4vogyRiRB5/XNvvz3zytFTDEf61eF9b0dCKTS36c4afymTsgLeQ9Ly13X/aYnzE1Uy6PV7679trNy1xe+tKwPqAH/0Vla0qw65gH7AFeG/Y3Uy9P45o0bm3PTIaplM6lTK9jWf/OBUyQcrpdXaTIyfsXQb9QcLaAn7vJd2vxY5XxBpo8pwDmgFGsLKx1oeh8OVmUUSLXUlrWZPzbdLag9v+BjUqfDzepKAyDDcZbznGHG+1NmqSKHpVlfbadJqLW+o2LHobNX+PUB1WPkfnHwYyTmX6lI7Lehr3F576NM/+T3V3wH17f2w1xkg2ggXuSvga6p8p+bgmpVKWpXAmVh+2AsNEKogdYYAJa0GT03J4obyf60HTgKe6PTTqw0QOpcQ3wXs4LlDZyq2FXrrS4uBmjDxuCw3G5eIgA46yeC5ho11pWsWW35PWTibBC4Xf+9eBLRPg0q2+s5UvHG6bMNqJYPHw7nXutxZYvIIiMoCSgbrPVX/fv7syS+3AKfC5MOmF4iRpP6RjrId8O5vrNhS1NpUWQLUholUr6muXEoatP3emrWNR9e/avk9R8P+HuxNypPkrk93pGdnK0VtXemaN6UdOHo55vdE5b/0NKx+K4AxtAAAAABJRU5ErkJggg==\", \"description\":\"Keep up with friends wherever you go on the web.\",\"author\":\"Facebook\",\"homepageURL\":\"https://www.facebook.com/about/messenger-for-firefox\",\"builtin\":\"true\"}");
+pref("social.manifest.facebook", "{\"origin\":\"https://www.facebook.com\",\"name\":\"Facebook Messenger\",\"workerURL\":\"https://www.facebook.com/desktop/fbdesktop2/socialfox/fbworker.js.php\",\"shareURL\":\"https://www.facebook.com/sharer/sharer.php?u=%{url}\",\"iconURL\":\"data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAX0lEQVQ4jWP4%2F%2F8%2FAyUYTFhHzjgDxP9JxGeQDSBVMxgTbUBCxer%2Fr999%2BQ8DJBuArJksA9A10s8AXIBoA0B%2BR%2FY%2FjD%2BEwoBoA1yT5v3PbdmCE8MAshhID%2FUMoDgzUYIBj0Cgi7ar4coAAAAASUVORK5CYII%3D\",\"sidebarURL\":\"https://www.facebook.com/desktop/fbdesktop2/?socialfox=true\",\"icon32URL\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAADbklEQVRYCc1Xv08UQRj99tctexAuCEFjRE0kGBEtLDSGqIWNxkYKbTAxNlY2JhaGWltNtNFeKgsKKxITK43/gCYW+IsoRhA4D47bH7fn9+bcvdm5JR7sefolC3Ozu9978+bNN7PayUv3HN3umdY0Y6IWBtSJ0HSTarXqTOiuTep6Lj+tdxAcA8RAgSmwdd2aCDs0clldYALb/FvgYVhjmfliVA2XpjEgWo0Attn42Z6WH1RFor5ehwo9XQIUZMoVn4qlCoVMSo62EvD8Kh0b3U2Xz43R2PBO6mUCGDlAf65V6MadZzT/rUimoccc2kYA4BfPHqJb105RzjJigKhRq9kEJUBIjgYVuXeL7SAI6eD+Abp5dTwVHOmEHxT50d8WBYJqSOdPj5BjW8gZR8UNqFR2xagx/65XFYaMH+BGWwiYpi4UkBPPLxTp9v1Z+lHc4DWvCQXWmIy6EjITgKowVd5Jjv7N3Hd6y5esigoOwpkJIAmMpZpLJGdiaaC4F0UmAj6bD84GCEwmB/qxMmRilmnwb/mpjAocHh4UEoNAt5NLZB7oy9OJo0PxqkAtePdhiSqunyC1LQUwWMPQaOr6GRre258Ajn4cP7KHcEXhsxpXbj+lT19X2TMNGTLVAcjcalS8gDwsQ2UOMhH4k8FkcrEn5E5ub2sKohxLK2VR77Hl9RUcsrgeRIEiVOT6z+tDbIeLy+vk+kGTCbXxycet6xhl//3f6bJEkdHYhA+mLtDIvoH4ieev5+juoxdk5+pjhALYEdXIpEB5w+NlSKSzqVQ/+H7IO6BLtl3fngGMiqhGJgIwlM6qpyUGFjySdk8m0Zg0ubeD7X9OIDEFajltRQgUJaUKx69tdgaQa0FMADuahZPMFtcEwNPm2hA7ZI5sK4aoE2NvYI+o8hkCIe7CwTv68zS0q9Dk5vpbm/8FXxitSzmMFHpsGj0wyLUheTwD2Y9fVgh1Ae0EPUgD9241ZEnld+v5kgnVZ/8fE0brVh5BK+1oCqKKF72Dk7HwBsssB/pklU1dfChy3S659H5+uelgIb+8WRv1/uGTV9Sdb5wJFlfW6fPCalMhwhSU1j2xKwKbP838GcOwJja4TqO0bjdmXxYTy1EYjFdCWoCEYZhseH/GDL3yJPHnuW6YmT7P1SlIA4768Hke4vOcsX8BE346lLHhDUQAAAAASUVORK5CYII=\", \"icon64URL\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAACNNJREFUeNrtm3tw1NUVxz/399hHHkgCaCBGEFEEREVFYFQcSoOKdkZay4z+4dDpYIsjHWx1WoTMhFi1gzBSpVgVGbU4U1sHfPESKODwEEnRYDFAICEIeZIQshs2u/v73ds/drMsyW7YLEkl2Z6Z32yy+9v7u+fc7znne8+5KzgvAjDunzlv0M13PjDZ6c4cARj0WhEoaZ1tOn3yq9XLf/tNU0O1D5Ad7wq/OpxpaXOL1j5uZAwuaGlVgwNBhULRm0XXBG6HZrlNa9uRrzfM+3DlgjIgGMsA7rl/XDdHOnNf9vosTfVuvTsaQhdkZ4iykh2rHtqydvkxwI58BhjTfv7MmP55E9/1nLNdfU15ACkVvoAaMCRvRPa+re9+DgTaPjMAx+DrJv3M67Mz+6LybWLb4NfTHhxzx31DDhZvOtqGAgNwWbjGICV9XQJB0e/KobcOP1i8qTzaAEYgaDtNU/V5A9hSaUFLuQEt2gVQSgml+j4CUAIppYgK/m0GkCjZ9xGAUNAu0LUhgJRAAAIVzwBSqVRQH4hlAClRKZAFhOgEASoFECBR8QwgUyQGdJT/B8HzCEiBNKhUJzEgBYIgQsTJAkohe9oFZHgHKvQoHtZ9K3tewfiixXABLdoFeuSSEmkF+PH4QTz7+M3o+ENptzvGtS36uSwmjMpAYF10XCllHCYoe84FlLS555Zs5jx6J6ahY+iCl98pJiDNS1hwSZop+cm91zJmxEBefGsPlu1AxKC67V3gf5oGlZSMuz6Dp2fdhWnoAEwaN5T5hsYLb+4hKB1dcgelFDpB8ifk8thDt3DO5+fZxRvxBV0IjQR0EB3KfD1GhJS0GZnnYuGcKTgdF9ZWx4/No/BJjUUrdtJqm4iL+K5SCmSAiWMHMevhcQzNzaa6ron5SzfQ7HeiaSKx+au4m6HupcJKSYZdZVI4dypuV2yo3zoql0VP3cOiFV/Q4jdiGkGhQFqMGpbJL346kbE3DEYIQWNTC39Ysp4Gr4HQtZDyiRhA0NlmSHZbRM7pr1H0m6lckeHqdGXG3jCYoqfupeC17bT49fNRXIFSNrkDTGbNGM9dtw1D10M1DI/Xx3NLP6OqETRdDy1eglPT4rqA7K56gCIrXfHCvHwGZqUnBMtR113FS/N+xHPLtuJpDa1mVobg0emjmX7vqEjsUErhaw1Q8Mo6yk4F0A1HeOW7kIlFx/u7jworRabLpmhuPjmD+iG7YNDrrhnIS09P5cW/buOeO67lkftvJt3tDE06PE7Qsnh++QYOHPOim86wcVUS0+whJug0ghTMmcK1V2eH8m2UHP++nrwhAyIwjiXDcrN5vXAGhqGhFBeMYUvJ0re2sPfgGTTDGUZrEogVopMgmGQWUCgMEWTBE5MZPSLngnGqas/w9j92s31fJfmThvPM7HyMMKRj+qgmOiBHSsnr73/B5r1V6A53KD4k3bFS8dNgckFQoWPxu1kTGDc6N7JqzR4ff/+smE+2H8FSLkx3FluLawhaG3n2iXwcppGoV/Hemt18tK0c3UwLIfUS2nVafBeQJNUXkAF+/dht3H37cKSUBC2bTTv+w98++YazPg1dT0NoIUhruoMd+2sJrtjI7381rQM3iCVrN33N++tL0c30xFNdp0GQeFRYQhcRIO0gv5xxE/fdfSO2bfNVSTmrPtxLZW0A3XSh6VporaLG1XQHu0pOU/TaOhY8+QAuZ3w6vHnnQd74536EkZ50wOsSE0zcugolbWZOG8GM/LGUVdSw6sM97D/UgGa60QxXzMJDZAq6yb7SJgr//CkLn5pOmsvR4Z5dxUdZ9t6XoKfFjNyXkqZjuoBUCpGgCyhp8eDdQ5k++UaWrdrMlr2VSFxoZlpE8YtNWGgGXx9ppnDZpxTMfTCS8gAOlJ5g8ds7kCItTIi6j6FqMVxAC2sV2RB1ekmLCTcNpH+myeyFH7BxT1Voopoe4RKJXQqhmxw45mXh0o/xeH0opThcXs2iv2wmoFyhAnbC4yX+3PgISMDShrA5XHGa3d9UITRniIeTfHASmsGhEz7mL/mI2TPv4sU3t+KzHAnu7JKpCosOkcSIICAB5hZE0OiRCM0Iwb0b6LPQdI5W+Zn/yucoYYayRk+16eK1xqRMDAHtA0r3lep0lNAjO8kfpCpMqpTF4xZEUqA7rIlOCiKpgADVWXc4FQwgEfHPB5AiByTixIDUCYJx+wJoqdIcJV5VOAWygEZcF7BToT2upFDKtuz2BrAtf8v3mju972cBJX2exso6ok6N64BhOtM11xXXPBz6v6340PcuO+DZfaJkzWqgqY3L64Bqaaz0ZV45Mkc308dG2kd97FLSaq4v317gazr5HeCLRoACFTxbfeBw+oDhWYYj4/rw+30H+rb/VMPxXQsbKnbuABqJOi4vogyRiRB5/XNvvz3zytFTDEf61eF9b0dCKTS36c4afymTsgLeQ9Ly13X/aYnzE1Uy6PV7679trNy1xe+tKwPqAH/0Vla0qw65gH7AFeG/Y3Uy9P45o0bm3PTIaplM6lTK9jWf/OBUyQcrpdXaTIyfsXQb9QcLaAn7vJd2vxY5XxBpo8pwDmgFGsLKx1oeh8OVmUUSLXUlrWZPzbdLag9v+BjUqfDzepKAyDDcZbznGHG+1NmqSKHpVlfbadJqLW+o2LHobNX+PUB1WPkfnHwYyTmX6lI7Lehr3F576NM/+T3V3wH17f2w1xkg2ggXuSvga6p8p+bgmpVKWpXAmVh+2AsNEKogdYYAJa0GT03J4obyf60HTgKe6PTTqw0QOpcQ3wXs4LlDZyq2FXrrS4uBmjDxuCw3G5eIgA46yeC5ho11pWsWW35PWTibBC4Xf+9eBLRPg0q2+s5UvHG6bMNqJYPHw7nXutxZYvIIiMoCSgbrPVX/fv7syS+3AKfC5MOmF4iRpP6RjrId8O5vrNhS1NpUWQLUholUr6muXEoatP3emrWNR9e/avk9R8P+HuxNypPkrk93pGdnK0VtXemaN6UdOHo55vdE5b/0NKx+K4AxtAAAAABJRU5ErkJggg==\", \"description\":\"Keep up with friends wherever you go on the web.\",\"author\":\"Facebook\",\"homepageURL\":\"https://www.facebook.com/about/messenger-for-firefox\",\"builtin\":\"true\"}");
 
 // comma separated list of domain origins (e.g. https://domain.com) for
 // providers that can install from their own website without user warnings.
 // entries are
 pref("social.whitelist", "https://mozsocial.cliqz.com,https://now.msn.com,https://mixi.jp");
 // omma separated list of domain origins (e.g. https://domain.com) for directory
 // websites (e.g. AMO) that can install providers for other sites
 pref("social.directories", "https://addons.mozilla.org");
--- a/browser/base/content/aboutSocialError.xhtml
+++ b/browser/base/content/aboutSocialError.xhtml
@@ -42,16 +42,18 @@
     }
 
     function parseQueryString() {
       let url = document.documentURI;
       let queryString = url.replace(/^about:socialerror\??/, "");
 
       let modeMatch = queryString.match(/mode=([^&]+)/);
       let mode = modeMatch && modeMatch[1] ? modeMatch[1] : "";
+      let originMatch = queryString.match(/origin=([^&]+)/);
+      config.origin = originMatch && originMatch[1] ? decodeURIComponent(originMatch[1]) : "";
 
       switch (mode) {
         case "compactInfo":
           document.getElementById("btnTryAgain").style.display = 'none';
           document.getElementById("btnCloseSidebar").style.display = 'none';
           break;
         case "tryAgainOnly":
           document.getElementById("btnCloseSidebar").style.display = 'none';
@@ -72,17 +74,21 @@
       }
     }
 
     function setUpStrings() {
       let brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
       let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
 
       let productName = brandBundle.GetStringFromName("brandShortName");
-      let providerName = Social && Social.provider && Social.provider.name;
+      let provider = Social && Social.provider;
+      if (config.origin) {
+        provider = Social && Social._getProviderFromOrigin(config.origin);
+      }
+      let providerName = provider && provider.name;
 
       // Sets up the error message
       let msg = browserBundle.formatStringFromName("social.error.message", [productName, providerName], 2);
       document.getElementById("main-error-msg").textContent = msg;
 
       // Sets up the buttons' labels and accesskeys
       let btnTryAgain = document.getElementById("btnTryAgain");
       btnTryAgain.textContent = browserBundle.GetStringFromName("social.error.tryAgain.label");
--- a/browser/base/content/abouthealthreport/abouthealth.xhtml
+++ b/browser/base/content/abouthealthreport/abouthealth.xhtml
@@ -11,16 +11,18 @@
   %securityPrefsDTD;
   <!ENTITY % aboutHealthReportDTD SYSTEM "chrome://browser/locale/aboutHealthReport.dtd">
   %aboutHealthReportDTD;
 ]>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
    <title>&abouthealth.pagetitle;</title>
+   <link rel="icon" type="image/png" id="favicon"
+         href="chrome://branding/content/icon32.png"/>
    <link rel="stylesheet"
      href="chrome://browser/content/abouthealthreport/abouthealth.css"
      type="text/css" />
    <script type="text/javascript;version=1.8"
      src="chrome://browser/content/abouthealthreport/abouthealth.js" />
   </head>
   <body onload="healthReportWrapper.init();"
         onunload="healthReportWrapper.uninit();">
--- a/browser/base/content/browser-context.inc
+++ b/browser/base/content/browser-context.inc
@@ -35,16 +35,20 @@
       <menuseparator id="context-sep-open"/>
       <menuitem id="context-bookmarklink"
                 label="&bookmarkThisLinkCmd.label;"
                 accesskey="&bookmarkThisLinkCmd.accesskey;"
                 oncommand="gContextMenu.bookmarkLink();"/>
       <menuitem id="context-marklink"
                 accesskey="&social.marklink.accesskey;"
                 oncommand="gContextMenu.markLink();"/>
+      <menuitem id="context-sharelink"
+                label="&shareLinkCmd.label;"
+                accesskey="&shareLinkCmd.accesskey;"
+                oncommand="gContextMenu.shareLink();"/>
       <menuitem id="context-savelink"
                 label="&saveLinkCmd.label;"
                 accesskey="&saveLinkCmd.accesskey;"
                 oncommand="gContextMenu.saveLink();"/>
       <menuitem id="context-copyemail"
                 label="&copyEmailCmd.label;"
                 accesskey="&copyEmailCmd.accesskey;"
                 oncommand="gContextMenu.copyEmail();"/>
@@ -155,32 +159,40 @@
                 label="&copyAudioURLCmd.label;"
                 accesskey="&copyAudioURLCmd.accesskey;"
                 oncommand="gContextMenu.copyMediaLocation();"/>
       <menuseparator id="context-sep-copyimage"/>
       <menuitem id="context-saveimage"
                 label="&saveImageCmd.label;"
                 accesskey="&saveImageCmd.accesskey;"
                 oncommand="gContextMenu.saveMedia();"/>
+      <menuitem id="context-shareimage"
+                label="&shareImageCmd.label;"
+                accesskey="&shareImageCmd.accesskey;"
+                oncommand="gContextMenu.shareImage();"/>
       <menuitem id="context-sendimage"
                 label="&emailImageCmd.label;"
                 accesskey="&emailImageCmd.accesskey;"
                 oncommand="gContextMenu.sendMedia();"/>
       <menuitem id="context-setDesktopBackground"
                 label="&setDesktopBackgroundCmd.label;"
                 accesskey="&setDesktopBackgroundCmd.accesskey;"
                 oncommand="gContextMenu.setDesktopBackground();"/>
       <menuitem id="context-viewimageinfo"
                 label="&viewImageInfoCmd.label;"
                 accesskey="&viewImageInfoCmd.accesskey;"
                 oncommand="gContextMenu.viewImageInfo();"/>
       <menuitem id="context-savevideo"
                 label="&saveVideoCmd.label;"
                 accesskey="&saveVideoCmd.accesskey;"
                 oncommand="gContextMenu.saveMedia();"/>
+      <menuitem id="context-sharevideo"
+                label="&shareVideoCmd.label;"
+                accesskey="&shareVideoCmd.accesskey;"
+                oncommand="gContextMenu.shareVideo();"/>
       <menuitem id="context-saveaudio"
                 label="&saveAudioCmd.label;"
                 accesskey="&saveAudioCmd.accesskey;"
                 oncommand="gContextMenu.saveMedia();"/>
       <menuitem id="context-video-saveimage"
                 accesskey="&videoSaveImage.accesskey;"
                 label="&videoSaveImage.label;"
                 oncommand="gContextMenu.saveVideoFrameAsImage();"/>
@@ -223,16 +235,20 @@
       <menuseparator id="context-sep-stop"/>
       <menuitem id="context-bookmarkpage"
                 label="&bookmarkPageCmd2.label;"
                 accesskey="&bookmarkPageCmd2.accesskey;"
                 oncommand="gContextMenu.bookmarkThisPage();"/>
       <menuitem id="context-markpage"
                 accesskey="&social.markpage.accesskey;"
                 command="Social:TogglePageMark"/>
+      <menuitem id="context-sharepage"
+                label="&sharePageCmd.label;"
+                accesskey="&sharePageCmd.accesskey;"
+                oncommand="SocialShare.sharePage();"/>
       <menuitem id="context-savepage"
                 label="&savePageCmd.label;"
                 accesskey="&savePageCmd.accesskey2;"
                 oncommand="gContextMenu.savePageAs();"/>
       <menuseparator id="context-sep-viewbgimage"/>
       <menuitem id="context-viewbgimage"
                 label="&viewBGImageCmd.label;"
                 accesskey="&viewBGImageCmd.accesskey;"
@@ -266,16 +282,20 @@
                 command="cmd_selectAll"/>
       <menuseparator id="context-sep-selectall"/>
       <menuitem id="context-keywordfield"
                 label="&keywordfield.label;"
                 accesskey="&keywordfield.accesskey;"
                 oncommand="AddKeywordForSearchField();"/>
       <menuitem id="context-searchselect"
                 oncommand="BrowserSearch.loadSearchFromContext(getBrowserSelection());"/>
+      <menuitem id="context-shareselect"
+                label="&shareSelectCmd.label;"
+                accesskey="&shareSelectCmd.accesskey;"
+                oncommand="gContextMenu.shareSelect(getBrowserSelection());"/>
       <menuseparator id="frame-sep"/>
       <menu id="frame" label="&thisFrameMenu.label;" accesskey="&thisFrameMenu.accesskey;">
         <menupopup>
           <menuitem id="context-showonlythisframe"
                     label="&showOnlyThisFrameCmd.label;"
                     accesskey="&showOnlyThisFrameCmd.accesskey;"
                     oncommand="gContextMenu.showOnlyThisFrame();"/>
           <menuitem id="context-openframeintab"
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -930,17 +930,17 @@ var gPluginHandler = {
                           },
     };
 
     // If there is already an outdated plugin notification then do nothing
     if (outdatedNotification)
       return;
 
     if (eventType == "PluginBlocklisted") {
-      if (gPrefService.getBoolPref("plugins.hide_infobar_for_missing_plugin")) // XXX add a new pref?
+      if (gPrefService.getBoolPref("plugins.hide_infobar_for_blocked_plugin"))
         return;
 
       if (blockedNotification)
         return;
     }
     else if (eventType == "PluginOutdated") {
       if (gPrefService.getBoolPref("plugins.hide_infobar_for_outdated_plugin"))
         return;
--- a/browser/base/content/browser-safebrowsing.js
+++ b/browser/base/content/browser-safebrowsing.js
@@ -34,15 +34,20 @@ var gSafeBrowsing = {
   /**
    * Used to report a phishing page or a false positive
    * @param name String One of "Phish", "Error", "Malware" or "MalwareError"
    * @return String the report phishing URL.
    */
   getReportURL: function(name) {
     var reportUrl = SafeBrowsing.getReportURL(name);
 
-    var pageUrl = gBrowser.currentURI.asciiSpec;
-    reportUrl += "&url=" + encodeURIComponent(pageUrl);
+    var pageUri = gBrowser.currentURI.clone();
+
+    // Remove the query to avoid including potentially sensitive data
+    if (pageUri instanceof Ci.nsIURL)
+      pageUri.query = '';
+
+    reportUrl += "&url=" + encodeURIComponent(pageUri.asciiSpec);
 
     return reportUrl;
   }
 }
 #endif
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -105,16 +105,17 @@
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing"
       oncommand="OpenBrowserWindow({private: true});"/>
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
     <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
     <command id="Social:TogglePageMark" oncommand="SocialMark.togglePageMark();" disabled="true"/>
+    <command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/>
     <command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();"/>
     <command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/>
     <command id="Social:FocusChat" oncommand="SocialChatBar.focus();" hidden="true" disabled="true"/>
     <command id="Social:Toggle" oncommand="Social.toggle();" hidden="true"/>
     <command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/>
   </commandset>
 
   <commandset id="placesCommands">
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -2,29 +2,36 @@
 // 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/.
 
 // the "exported" symbols
 let SocialUI,
     SocialChatBar,
     SocialFlyout,
     SocialMark,
+    SocialShare,
     SocialMenu,
     SocialToolbar,
     SocialSidebar;
 
 (function() {
 
 // The minimum sizes for the auto-resize panel code.
 const PANEL_MIN_HEIGHT = 100;
 const PANEL_MIN_WIDTH = 330;
 
 XPCOMUtils.defineLazyModuleGetter(this, "SharedFrame",
   "resource:///modules/SharedFrame.jsm");
 
+XPCOMUtils.defineLazyGetter(this, "OpenGraphBuilder", function() {
+  let tmp = {};
+  Cu.import("resource:///modules/Social.jsm", tmp);
+  return tmp.OpenGraphBuilder;
+});
+
 SocialUI = {
   // Called on delayed startup to initialize the UI
   init: function SocialUI_init() {
     Services.obs.addObserver(this, "social:ambient-notification-changed", false);
     Services.obs.addObserver(this, "social:profile-changed", false);
     Services.obs.addObserver(this, "social:page-mark-config", false);
     Services.obs.addObserver(this, "social:frameworker-error", false);
     Services.obs.addObserver(this, "social:provider-set", false);
@@ -38,16 +45,17 @@ SocialUI = {
     // Called when we enter DOM full-screen mode.
     window.addEventListener("mozfullscreenchange", function () {
       SocialSidebar.update();
       SocialChatBar.update();
     });
 
     SocialChatBar.init();
     SocialMark.init();
+    SocialShare.init();
     SocialMenu.init();
     SocialToolbar.init();
     SocialSidebar.init();
 
     if (!Social.initialized) {
       Social.init();
     } else {
       // social was previously initialized, so it's not going to notify us of
@@ -82,26 +90,28 @@ SocialUI = {
         case "social:provider-set":
           // Social.provider has changed (possibly to null), update any state
           // which depends on it.
           this._updateActiveUI();
           this._updateMenuItems();
 
           SocialFlyout.unload();
           SocialChatBar.update();
+          SocialShare.update();
           SocialSidebar.update();
           SocialMark.update();
           SocialToolbar.update();
           SocialMenu.populate();
           break;
         case "social:providers-changed":
           // the list of providers changed - this may impact the "active" UI.
           this._updateActiveUI();
           // and the multi-provider menu
           SocialToolbar.populateProviderMenus();
+          SocialShare.populateProviderMenu();
           break;
 
         // Provider-specific notifications
         case "social:ambient-notification-changed":
           if (this._matchesCurrentProvider(data)) {
             SocialToolbar.updateButton();
             SocialMenu.populate();
           }
@@ -379,17 +389,23 @@ SocialChatBar = {
 }
 
 function sizeSocialPanelToContent(panel, iframe) {
   // FIXME: bug 764787: Maybe we can use nsIDOMWindowUtils.getRootBounds() here?
   let doc = iframe.contentDocument;
   if (!doc || !doc.body) {
     return;
   }
+  // We need an element to use for sizing our panel.  See if the body defines
+  // an id for that element, otherwise use the body itself.
   let body = doc.body;
+  let bodyId = body.getAttribute("contentid");
+  if (bodyId) {
+    body = doc.getElementById(bodyId) || doc.body;
+  }
   // offsetHeight/Width don't include margins, so account for that.
   let cs = doc.defaultView.getComputedStyle(body);
   let computedHeight = parseInt(cs.marginTop) + body.offsetHeight + parseInt(cs.marginBottom);
   let height = Math.max(computedHeight, PANEL_MIN_HEIGHT);
   let computedWidth = parseInt(cs.marginLeft) + body.offsetWidth + parseInt(cs.marginRight);
   let width = Math.max(computedWidth, PANEL_MIN_WIDTH);
   let wDiff = width - iframe.getBoundingClientRect().width;
   // A panel resize will move the right margin - if that is where the anchor
@@ -561,16 +577,311 @@ SocialFlyout = {
       // that the docShell of this frame is created
       panel.firstChild.clientTop;
       Social.setErrorListener(iframe, this.setFlyoutErrorMessage.bind(this))
     }
     this.yOffset = yOffset;
   }
 }
 
+SocialShare = {
+  // Called once, after window load, when the Social.provider object is initialized
+  init: function() {},
+
+  get panel() {
+    return document.getElementById("social-share-panel");
+  },
+
+  get iframe() {
+    // first element is our menu vbox.
+    if (this.panel.childElementCount == 1)
+      return null;
+    else
+      return this.panel.lastChild;
+  },
+
+  _createFrame: function() {
+    let panel = this.panel;
+    if (!SocialUI.enabled || this.iframe)
+      return;
+    this.panel.hidden = false;
+    // create and initialize the panel for this window
+    let iframe = document.createElement("iframe");
+    iframe.setAttribute("type", "content");
+    iframe.setAttribute("class", "social-share-frame");
+    iframe.setAttribute("flex", "1");
+    panel.appendChild(iframe);
+    this.populateProviderMenu();
+  },
+  
+  getSelectedProvider: function() {
+    let provider;
+    let lastProviderOrigin = this.iframe && this.iframe.getAttribute("origin");
+    if (lastProviderOrigin) {
+      provider = Social._getProviderFromOrigin(lastProviderOrigin);
+    }
+    if (!provider)
+      provider = Social.provider || Social.defaultProvider;
+    // if our provider has no shareURL, select the first one that does
+    if (provider && !provider.shareURL) {
+      let providers = [p for (p of Social.providers) if (p.shareURL)];
+      provider = providers.length > 0  && providers[0];
+    }
+    return provider;
+  },
+
+  populateProviderMenu: function() {
+    if (!this.iframe)
+      return;
+    let providers = [p for (p of Social.providers) if (p.shareURL)];
+    let hbox = document.getElementById("social-share-provider-buttons");
+    // selectable providers are inserted before the provider-menu seperator,
+    // remove any menuitems in that area
+    while (hbox.firstChild) {
+      hbox.removeChild(hbox.firstChild);
+    }
+    // reset our share toolbar
+    // only show a selection if there is more than one
+    if (!SocialUI.enabled || providers.length < 2) {
+      this.panel.firstChild.hidden = true;
+      return;
+    }
+    let selectedProvider = this.getSelectedProvider();
+    for (let provider of providers) {
+      let button = document.createElement("toolbarbutton");
+      button.setAttribute("class", "toolbarbutton share-provider-button");
+      button.setAttribute("type", "radio");
+      button.setAttribute("group", "share-providers");
+      button.setAttribute("image", provider.iconURL);
+      button.setAttribute("tooltiptext", provider.name);
+      button.setAttribute("origin", provider.origin);
+      button.setAttribute("oncommand", "SocialShare.sharePage(this.getAttribute('origin')); this.checked=true;");
+      if (provider == selectedProvider) {
+        this.defaultButton = button;
+      }
+      hbox.appendChild(button);
+    }
+    if (!this.defaultButton) {
+      this.defaultButton = hbox.firstChild
+    }
+    this.defaultButton.setAttribute("checked", "true");
+    this.panel.firstChild.hidden = false;
+  },
+
+  get shareButton() {
+    return document.getElementById("social-share-button");
+  },
+
+  canSharePage: function(aURI) {
+    // we do not enable sharing from private sessions
+    if (PrivateBrowsingUtils.isWindowPrivate(window))
+      return false;
+
+    if (!aURI || !(aURI.schemeIs('http') || aURI.schemeIs('https')))
+      return false;
+
+    // The share button and context menus are disabled if the current tab has
+    // defined no-store. However, a share from other content is still possible
+    // (eg. via mozSocial or future use of web activities).  If the URI is not
+    // the current tab URI, we cannot validate the no-store header on the URI.
+    if (aURI != gBrowser.currentURI)
+      return true;
+
+    // we want to ensure this is a successful load and that the page is locally
+    // cacheable since that is a common mechanism for sensitive pages to avoid
+    // storing sensitive data in cache.
+    let channel = gBrowser.docShell.currentDocumentChannel;
+    let httpChannel;
+    try {
+      httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
+    } catch (e) {
+      /* Not an HTTP channel. */
+      Cu.reportError("cannot share without httpChannel");
+      return false;
+    }
+
+    // Continue only if we have a 2xx status code.
+    try {
+      if (!httpChannel.requestSucceeded)
+        return false;
+    } catch (e) {
+      // Can't get response information from the httpChannel
+      // because mResponseHead is not available.
+      return false;
+    }
+
+    // Cache-Control: no-store.
+    if (httpChannel.isNoStoreResponse()) {
+      Cu.reportError("cannot share cache-control: no-share");
+      return false;
+    }
+
+    return true;
+  },
+
+  update: function() {
+    let shareButton = this.shareButton;
+    shareButton.hidden = !SocialUI.enabled ||
+                         [p for (p of Social.providers) if (p.shareURL)].length == 0;
+    shareButton.disabled = shareButton.hidden || !this.canSharePage(gBrowser.currentURI);
+
+    // also update the relevent command's disabled state so the keyboard
+    // shortcut only works when available.
+    let cmd = document.getElementById("Social:SharePage");
+    cmd.setAttribute("disabled", shareButton.disabled ? "true" : "false");
+  },
+
+  onShowing: function() {
+    this.shareButton.setAttribute("open", "true");
+  },
+
+  onHidden: function() {
+    this.shareButton.removeAttribute("open");
+    this.iframe.setAttribute("src", "data:text/plain;charset=utf8,")
+    this.currentShare = null;
+  },
+
+  setErrorMessage: function() {
+    let iframe = this.iframe;
+    if (!iframe)
+      return;
+
+    iframe.removeAttribute("src");
+    iframe.webNavigation.loadURI("about:socialerror?mode=compactInfo&origin=" +
+                                 encodeURIComponent(iframe.getAttribute("origin")),
+                                 null, null, null, null);
+    sizeSocialPanelToContent(this.panel, iframe);
+  },
+
+  sharePage: function(providerOrigin, graphData) {
+    // if providerOrigin is undefined, we use the last-used provider, or the
+    // current/default provider.  The provider selection in the share panel
+    // will call sharePage with an origin for us to switch to.
+    this._createFrame();
+    let iframe = this.iframe;
+    let provider;
+    if (providerOrigin)
+      provider = Social._getProviderFromOrigin(providerOrigin);
+    else
+      provider = this.getSelectedProvider();
+    if (!provider || !provider.shareURL)
+      return;
+
+    // graphData is an optional param that either defines the full set of data
+    // to be shared, or partial data about the current page. It is set by a call
+    // in mozSocial API, or via nsContentMenu calls. If it is present, it MUST
+    // define at least url. If it is undefined, we're sharing the current url in
+    // the browser tab.
+    let sharedURI = graphData ? Services.io.newURI(graphData.url, null, null) :
+                                gBrowser.currentURI;
+    if (!this.canSharePage(sharedURI))
+      return;
+
+    // the point of this action type is that we can use existing share
+    // endpoints (e.g. oexchange) that do not support additional
+    // socialapi functionality.  One tweak is that we shoot an event
+    // containing the open graph data.
+    let pageData = graphData ? graphData : this.currentShare;
+    if (!pageData || sharedURI == gBrowser.currentURI) {
+      pageData = OpenGraphBuilder.getData(gBrowser);
+      if (graphData) {
+        // overwrite data retreived from page with data given to us as a param
+        for (let p in graphData) {
+          pageData[p] = graphData[p];
+        }
+      }
+    }
+    this.currentShare = pageData;
+
+    let shareEndpoint = this._generateShareEndpointURL(provider.shareURL, pageData);
+
+    this._dynamicResizer = new DynamicResizeWatcher();
+    // if we've already loaded this provider/page share endpoint, we don't want
+    // to add another load event listener.
+    let reload = true;
+    let endpointMatch = shareEndpoint == iframe.getAttribute("src");
+    let docLoaded = iframe.contentDocument && iframe.contentDocument.readyState == "complete";
+    if (endpointMatch && docLoaded) {
+      reload = shareEndpoint != iframe.contentDocument.location.spec;
+    }
+    if (!reload) {
+      this._dynamicResizer.start(this.panel, iframe);
+      iframe.docShell.isActive = true;
+      iframe.docShell.isAppTab = true;
+      let evt = iframe.contentDocument.createEvent("CustomEvent");
+      evt.initCustomEvent("OpenGraphData", true, true, JSON.stringify(pageData));
+      iframe.contentDocument.documentElement.dispatchEvent(evt);
+    } else {
+      // first time load, wait for load and dispatch after load
+      iframe.addEventListener("load", function panelBrowserOnload(e) {
+        iframe.removeEventListener("load", panelBrowserOnload, true);
+        iframe.docShell.isActive = true;
+        iframe.docShell.isAppTab = true;
+        setTimeout(function() {
+          if (SocialShare._dynamicResizer) { // may go null if hidden quickly
+            SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
+          }
+        }, 0);
+        let evt = iframe.contentDocument.createEvent("CustomEvent");
+        evt.initCustomEvent("OpenGraphData", true, true, JSON.stringify(pageData));
+        iframe.contentDocument.documentElement.dispatchEvent(evt);
+      }, true);
+    }
+    // always ensure that origin belongs to the endpoint
+    let uri = Services.io.newURI(shareEndpoint, null, null);
+    iframe.setAttribute("origin", provider.origin);
+    iframe.setAttribute("src", shareEndpoint);
+
+    let navBar = document.getElementById("nav-bar");
+    let anchor = navBar.getAttribute("mode") == "text" ?
+                   document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-text") :
+                   document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-icon");
+    this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
+    Social.setErrorListener(iframe, this.setErrorMessage.bind(this));
+  },
+
+  _generateShareEndpointURL: function(shareURL, pageData) {
+    // support for existing share endpoints by supporting their querystring
+    // arguments. parse the query string template and do replacements where
+    // necessary the query names may be different than ours, so we could see
+    // u=%{url} or url=%{url}
+    let [shareEndpoint, queryString] = shareURL.split("?");
+    let query = {};
+    if (queryString) {
+      queryString.split('&').forEach(function (val) {
+        let [name, value] = val.split('=');
+        let p = /%\{(.+)\}/.exec(value);
+        if (!p) {
+          // preserve non-template query vars
+          query[name] = value;
+        } else if (pageData[p[1]]) {
+          query[name] = pageData[p[1]];
+        } else if (p[1] == "body") {
+          // build a body for emailers
+          let body = "";
+          if (pageData.title)
+            body += pageData.title + "\n\n";
+          if (pageData.description)
+            body += pageData.description + "\n\n";
+          if (pageData.text)
+            body += pageData.text + "\n\n";
+          body += pageData.url;
+          query["body"] = body;
+        }
+      });
+    }
+    var str = [];
+    for (let p in query)
+       str.push(p + "=" + encodeURIComponent(query[p]));
+    if (str.length)
+      shareEndpoint = shareEndpoint + "?" + str.join("&");
+    return shareEndpoint;
+  }
+};
+
 SocialMark = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SSB_init() {
   },
 
   get button() {
     return document.getElementById("social-mark-button");
   },
@@ -593,17 +904,17 @@ SocialMark = {
     cmd.setAttribute("disabled", markButton.disabled ? "true" : "false");
   },
 
   togglePageMark: function(aCallback) {
     if (this.button.disabled)
       return;
     this.toggleURIMark(gBrowser.currentURI, aCallback)
   },
-  
+
   toggleURIMark: function(aURI, aCallback) {
     let update = function(marked) {
       this._updateMarkState(marked);
       if (aCallback)
         aCallback(marked);
     }.bind(this);
     Social.isURIMarked(aURI, function(marked) {
       if (marked) {
@@ -993,21 +1304,22 @@ SocialToolbar = {
   _populateProviderMenu: function SocialToolbar_renderProviderMenu(providerMenuSep) {
     let menu = providerMenuSep.parentNode;
     // selectable providers are inserted before the provider-menu seperator,
     // remove any menuitems in that area
     while (providerMenuSep.previousSibling.nodeName == "menuitem") {
       menu.removeChild(providerMenuSep.previousSibling);
     }
     // only show a selection if enabled and there is more than one
-    if (Social.providers.length < 2) {
+    let providers = [p for (p of Social.providers) if (p.workerURL || p.sidebarURL)];
+    if (providers.length < 2) {
       providerMenuSep.hidden = true;
       return;
     }
-    for (let provider of Social.providers) {
+    for (let provider of providers) {
       let menuitem = document.createElement("menuitem");
       menuitem.className = "menuitem-iconic social-provider-menuitem";
       menuitem.setAttribute("image", provider.iconURL);
       menuitem.setAttribute("label", provider.name);
       menuitem.setAttribute("origin", provider.origin);
       if (provider == Social.provider) {
         menuitem.setAttribute("checked", "true");
       } else {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3401,16 +3401,17 @@ function BrowserToolboxCustomizeDone(aTo
   setUrlAndSearchBarWidthForConditionalForwardButton();
 
   // Update the urlbar
   if (gURLBar) {
     URLBarSetURI();
     XULBrowserWindow.asyncUpdateUI();
     BookmarksMenuButton.updateStarState();
     SocialMark.updateMarkState();
+    SocialShare.update();
   }
 
   TabsInTitlebar.allowedBy("customizing-toolbars", true);
 
   // Re-enable parts of the UI we disabled during the dialog
   var menubar = document.getElementById("main-menubar");
   for (let childNode of menubar.childNodes)
     childNode.setAttribute("disabled", false);
@@ -3875,16 +3876,17 @@ var XULBrowserWindow = {
       }
 
       if (gURLBar) {
         URLBarSetURI(aLocationURI);
 
         // Update starring UI
         BookmarksMenuButton.updateStarState();
         SocialMark.updateMarkState();
+        SocialShare.update();
       }
 
       // Show or hide browser chrome based on the whitelist
       if (this.hideChromeForLocation(location)) {
         document.documentElement.setAttribute("disablechrome", "true");
       } else {
         let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
         if (ss.getTabValue(gBrowser.selectedTab, "appOrigin"))
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -200,16 +200,29 @@
                   autofocus="autofocus"
                   label="&social.ok.label;"
                   accesskey="&social.ok.accesskey;"
                   oncommand="SocialUI.activationPanel.hidePopup();"/>
         </hbox>
       </vbox>
     </panel>
 
+    <panel id="social-share-panel"
+           class="social-panel"
+           type="arrow"
+           orient="horizontal"
+           onpopupshowing="SocialShare.onShowing()"
+           onpopuphidden="SocialShare.onHidden()"
+           consumeoutsideclicks="true"
+           hidden="true">
+      <vbox class="social-share-toolbar">
+        <vbox id="social-share-provider-buttons" flex="1"/>
+      </vbox>
+    </panel>
+
     <panel id="social-notification-panel"
            class="social-panel"
            type="arrow"
            hidden="true"
            noautofocus="true"/>
     <panel id="social-flyout-panel"
            class="social-panel"
            onpopupshown="SocialFlyout.onShown()"
@@ -699,16 +712,23 @@
                      label="&homeButton.label;"
                      ondragover="homeButtonObserver.onDragOver(event)"
                      ondragenter="homeButtonObserver.onDragOver(event)"
                      ondrop="homeButtonObserver.onDrop(event)"
                      ondragexit="homeButtonObserver.onDragExit(event)"
                      onclick="BrowserGoHome(event);"
                      aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
 
+      <toolbarbutton id="social-share-button"
+                     class="toolbarbutton-1 chromeclass-toolbar-additional"
+                     hidden="true"
+                     label="&sharePageCmd.label;"
+                     tooltiptext="&sharePageCmd.label;"
+                     command="Social:SharePage"/>
+
       <toolbaritem id="social-toolbar-item"
                    class="chromeclass-toolbar-additional"
                    removable="false"
                    title="&socialToolbar.title;"
                    hidden="true"
                    skipintoolbarset="true"
                    observes="socialActiveBroadcaster">
         <toolbarbutton id="social-provider-button"
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -313,16 +313,29 @@ nsContextMenu.prototype = {
       Social.isURIMarked(this.linkURI, function(marked) {
         let label = marked ? "social.unmarklink.label" : "social.marklink.label";
         let provider = Social.provider || Social.defaultProvider;
         let menuLabel = gNavigatorBundle.getFormattedString(label, [provider.name]);
         this.setItemAttr("context-marklink", "label", menuLabel);
       }.bind(this));
     }
     this.showItem("context-marklink", enableLinkMark);
+
+    // SocialShare
+    let shareButton = SocialShare.shareButton;
+    let shareEnabled = shareButton && !shareButton.disabled && !this.onSocial;
+    let pageShare = shareEnabled && !(this.isContentSelected ||
+                            this.onTextInput || this.onLink || this.onImage ||
+                            this.onVideo || this.onAudio);
+    this.showItem("context-sharepage", pageShare);
+    this.showItem("context-shareselect", shareEnabled && this.isContentSelected);
+    this.showItem("context-sharelink", shareEnabled && (this.onLink || this.onPlainTextLink) && !this.onMailtoLink);
+    this.showItem("context-shareimage", shareEnabled && this.onImage);
+    this.showItem("context-sharevideo", shareEnabled && this.onVideo);
+    this.setItemAttr("context-sharevideo", "disabled", !this.mediaURL);
   },
 
   initSpellingItems: function() {
     var canSpell = InlineSpellCheckerUI.canSpellCheck;
     var onMisspelling = InlineSpellCheckerUI.overMisspelling;
     var showUndo = canSpell && InlineSpellCheckerUI.canUndo();
     this.showItem("spell-check-enabled", canSpell);
     this.showItem("spell-separator", canSpell || this.onEditableArea);
@@ -1493,16 +1506,32 @@ nsContextMenu.prototype = {
     }
   },
 
   markLink: function CM_markLink() {
     // send link to social
     SocialMark.toggleURIMark(this.linkURI);
   },
 
+  shareLink: function CM_shareLink() {
+    SocialShare.sharePage(null, { url: this.linkURI.spec });
+  },
+
+  shareImage: function CM_shareImage() {
+    SocialShare.sharePage(null, { url: this.imageURL, previews: [ this.mediaURL ] });
+  },
+
+  shareVideo: function CM_shareVideo() {
+    SocialShare.sharePage(null, { url: this.mediaURL, source: this.mediaURL });
+  },
+
+  shareSelect: function CM_shareSelect(selection) {
+    SocialShare.sharePage(null, { url: this.browser.currentURI.spec, text: selection });
+  },
+
   savePageAs: function CM_savePageAs() {
     saveDocument(this.browser.contentDocument);
   },
 
   printFrame: function CM_printFrame() {
     PrintUtils.print(this.target.ownerDocument.defaultView);
   },
 
--- a/browser/base/content/socialchat.xml
+++ b/browser/base/content/socialchat.xml
@@ -115,17 +115,17 @@
       <method name="toggle">
         <body><![CDATA[
           this.minimized = !this.minimized;
         ]]></body>
       </method>
     </implementation>
 
     <handlers>
-      <handler event="focus">
+      <handler event="focus" phase="capturing">
         this.parentNode.selectedChat = this;
       </handler>
       <handler event="DOMTitleChanged"><![CDATA[
         this.setAttribute('label', this.iframe.contentDocument.title);
         this.parentNode.updateTitlebar(this);
       ]]></handler>
       <handler event="DOMLinkAdded"><![CDATA[
         // much of this logic is from DOMLinkHandler in browser.js
@@ -150,20 +150,20 @@
           this.isActive = !this.minimized;
       </handler>
     </handlers>
   </binding>
 
   <binding id="chatbar">
     <content>
       <xul:hbox align="end" pack="end" anonid="innerbox" class="chatbar-innerbox" mousethrough="always" flex="1">
+        <xul:spacer flex="1" anonid="spacer" class="chatbar-overflow-spacer"/>
         <xul:toolbarbutton anonid="nub" class="chatbar-button" type="menu" collapsed="true" mousethrough="never">
           <xul:menupopup anonid="nubMenu" oncommand="document.getBindingParent(this).showChat(event.target.chat)"/>
         </xul:toolbarbutton>
-        <xul:spacer flex="1" anonid="spacer" class="chatbar-overflow-spacer"/>
         <children/>
       </xul:hbox>
     </content>
 
     <implementation implements="nsIDOMEventListener">
       <constructor>
         // to avoid reflows we cache the width of the nub.
         this.cachedWidthNub = 0;
--- a/browser/base/content/test/social/Makefile.in
+++ b/browser/base/content/test/social/Makefile.in
@@ -27,21 +27,23 @@ include $(DEPTH)/config/autoconf.mk
                  browser_social_isVisible.js \
                  browser_social_chatwindow.js \
                  browser_social_chatwindowfocus.js \
                  browser_social_multiprovider.js \
                  browser_social_errorPage.js \
                  browser_social_window.js \
                  social_activate.html \
                  social_activate_iframe.html \
+                 browser_share.js \
                  social_panel.html \
                  social_mark_image.png \
                  social_sidebar.html \
                  social_chat.html \
                  social_flyout.html \
                  social_window.html \
                  social_worker.js \
+                 share.html \
                  $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/browser_share.js
@@ -0,0 +1,140 @@
+
+let baseURL = "https://example.com/browser/browser/base/content/test/social/";
+
+function test() {
+  waitForExplicitFinish();
+
+  let manifest = { // normal provider
+    name: "provider 1",
+    origin: "https://example.com",
+    sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
+    workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
+    iconURL: "https://example.com/browser/browser/base/content/test/moz.png",
+    shareURL: "https://example.com/browser/browser/base/content/test/social/share.html"
+  };
+  runSocialTestWithProvider(manifest, function (finishcb) {
+    runSocialTests(tests, undefined, undefined, finishcb);
+  });
+}
+
+let corpus = [
+  {
+    url: baseURL+"opengraph/opengraph.html",
+    options: {
+      // og:title
+      title: ">This is my title<",
+      // og:description
+      description: "A test corpus file for open graph tags we care about",
+      //medium: this.getPageMedium(),
+      //source: this.getSourceURL(),
+      // og:url
+      url: "https://www.mozilla.org/",
+      //shortUrl: this.getShortURL(),
+      // og:image
+      previews:["https://www.mozilla.org/favicon.png"],
+      // og:site_name
+      siteName: ">My simple test page<"
+    }
+  },
+  {
+    // tests that og:url doesn't override the page url if it is bad
+    url: baseURL+"opengraph/og_invalid_url.html",
+    options: {
+      description: "A test corpus file for open graph tags passing a bad url",
+      url: baseURL+"opengraph/og_invalid_url.html",
+      previews: [],
+      siteName: "Evil chrome delivering website"
+    }
+  },
+  {
+    url: baseURL+"opengraph/shorturl_link.html",
+    options: {
+      previews: ["http://example.com/1234/56789.jpg"],
+      url: "http://www.example.com/photos/56789/",
+      shortUrl: "http://imshort/p/abcde"
+    }
+  },
+  {
+    url: baseURL+"opengraph/shorturl_linkrel.html",
+    options: {
+      previews: ["http://example.com/1234/56789.jpg"],
+      url: "http://www.example.com/photos/56789/",
+      shortUrl: "http://imshort/p/abcde"
+    }
+  },
+  {
+    url: baseURL+"opengraph/shortlink_linkrel.html",
+    options: {
+      previews: ["http://example.com/1234/56789.jpg"],
+      url: "http://www.example.com/photos/56789/",
+      shortUrl: "http://imshort/p/abcde"
+    }
+  }
+];
+
+function loadURLInTab(url, callback) {
+  info("Loading tab with "+url);
+  let tab = gBrowser.selectedTab = gBrowser.addTab(url);
+  tab.linkedBrowser.addEventListener("load", function listener() {
+    is(tab.linkedBrowser.currentURI.spec, url, "tab loaded")
+    tab.linkedBrowser.removeEventListener("load", listener, true);
+    callback(tab);
+  }, true);
+}
+
+function hasoptions(testOptions, options) {
+  let msg;
+  for (let option in testOptions) {
+    let data = testOptions[option];
+    info("data: "+JSON.stringify(data));
+    let message_data = options[option];
+    info("message_data: "+JSON.stringify(message_data));
+    if (Array.isArray(data)) {
+      // the message may have more array elements than we are testing for, this
+      // is ok since some of those are hard to test. So we just test that
+      // anything in our test data IS in the message.
+      ok(Array.every(data, function(item) { return message_data.indexOf(item) >= 0 }), "option "+option);
+    } else {
+      is(message_data, data, "option "+option);
+    }
+  }
+}
+
+var tests = {
+  testSharePage: function(next) {
+    let panel = document.getElementById("social-flyout-panel");
+    let port = Social.provider.getWorkerPort();
+    ok(port, "provider has a port");
+    let testTab;
+    let testIndex = 0;
+    let testData = corpus[testIndex++];
+    
+    function runOneTest() {
+      loadURLInTab(testData.url, function(tab) {
+        testTab = tab;
+        SocialShare.sharePage();
+      });
+    }
+
+    port.onmessage = function (e) {
+      let topic = e.data.topic;
+      switch (topic) {
+        case "got-sidebar-message":
+          // open a tab with share data, then open the share panel
+          runOneTest();
+          break;
+        case "got-share-data-message":
+          gBrowser.removeTab(testTab);
+          hasoptions(testData.options, e.data.result);
+          testData = corpus[testIndex++];
+          if (testData) {
+            runOneTest();
+          } else {
+            next();
+          }
+          break;
+      }
+    }
+    port.postMessage({topic: "test-init"});
+  }
+}
--- a/browser/base/content/test/social/browser_social_chatwindowfocus.js
+++ b/browser/base/content/test/social/browser_social_chatwindowfocus.js
@@ -60,22 +60,26 @@ function startTestAndWaitForSidebar(call
     if (!doneCallback)
       callback(port);
     doneCallback = true;
   }
   port.onmessage = function(e) {
     let topic = e.data.topic;
     switch (topic) {
       case "got-sidebar-message":
+        // if sidebar loaded too fast, we need a backup ping
+      case "got-isVisible-response":
         isSidebarLoaded = true;
         maybeCallback();
         break;
       case "test-init-done":
         if (isSidebarLoaded)
           maybeCallback();
+        else
+          port.postMessage({topic: "test-isVisible"});
         break;
     }
   }
   port.postMessage({topic: "test-init"});
 }
 
 let manifest = { // normal provider
   name: "provider 1",
@@ -97,17 +101,17 @@ function test() {
   tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
     tab.linkedBrowser.removeEventListener("load", tabLoad, true);
     // before every test we focus the input field.
     let preSubTest = function(cb) {
       // XXX - when bug 604289 is fixed it should be possible to just do:
       // tab.linkedBrowser.contentWindow.focus()
       // but instead we must do:
       tab.linkedBrowser.contentDocument.getElementById("theinput").focus();
-      cb();
+      waitForCondition(function() isTabFocused(), cb, "tab should have focus");
     }
     let postSubTest = function(cb) {
       window.SocialChatBar.chatbar.removeAll();
       cb();
     }
     // and run the tests.
     runSocialTestWithProvider(manifest, function (finishcb) {
       runSocialTests(tests, preSubTest, postSubTest, function () {
@@ -133,50 +137,59 @@ var tests = {
         is(SocialChatBar.chatbar.childElementCount, 1, "exactly 1 chat open");
         ok(isTabFocused(), "tab should still be focused");
         // re-request the same chat via a message.
         openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
           is(SocialChatBar.chatbar.childElementCount, 1, "still exactly 1 chat open");
           ok(isTabFocused(), "tab should still be focused");
           // re-request the same chat via user event.
           openChatViaUser();
-          is(SocialChatBar.chatbar.childElementCount, 1, "still exactly 1 chat open");
-          // should now be focused
-          ok(isChatFocused(SocialChatBar.chatbar.firstElementChild), "chat should be focused");
-          next();
+          waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat),
+                           function() {
+            is(SocialChatBar.chatbar.childElementCount, 1, "still exactly 1 chat open");
+            is(SocialChatBar.chatbar.selectedChat, SocialChatBar.chatbar.firstElementChild, "chat should be selected");
+            next();
+          }, "chat should be focused");
         });
       });
     });
   },
 
   // In this test we arrange for the sidebar to open the chat via a simulated
   // click.  This should cause the new chat to be opened and focused.
   testFocusWhenViaUser: function(next) {
     startTestAndWaitForSidebar(function(port) {
       openChatViaUser();
       ok(SocialChatBar.chatbar.firstElementChild, "chat opened");
-      ok(isChatFocused(SocialChatBar.chatbar.firstElementChild), "chat should be focused");
-      next();
+      waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat),
+                       function() {
+        is(SocialChatBar.chatbar.selectedChat, SocialChatBar.chatbar.firstElementChild, "chat is selected");
+        next();
+      }, "chat should be focused");
     });
   },
 
   // Open a chat via the worker - it will open minimized and not have focus.
   // Then open the same chat via a sidebar message - it will be restored but
   // should still not have grabbed focus.
   testNoFocusOnAutoRestore: function(next) {
     const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html?id=1";
     let chatbar = SocialChatBar.chatbar;
     startTestAndWaitForSidebar(function(port) {
       openChatViaWorkerMessage(port, chatUrl, function() {
         is(chatbar.childElementCount, 1, "exactly 1 chat open");
         ok(chatbar.firstElementChild.minimized, "chat is minimized");
+        // bug 865086 opening minimized still sets the window as selected
+        todo(chatbar.selectedChat != chatbar.firstElementChild, "chat is not selected");
         ok(isTabFocused(), "tab should be focused");
         openChatViaSidebarMessage(port, {stealFocus: 1, id: 1}, function() {
           is(chatbar.childElementCount, 1, "still 1 chat open");
           ok(!chatbar.firstElementChild.minimized, "chat no longer minimized");
+          // bug 865086 because we marked it selected on open, it still is
+          todo(chatbar.selectedChat != chatbar.firstElementChild, "chat is not selected");
           ok(isTabFocused(), "tab should still be focused");
           next();
         });
       });
     });
   },
 
   // Here we open a chat, which will not be focused.  Then we minimize it and
@@ -187,40 +200,52 @@ var tests = {
         ok(true, "got chatbox message");
         ok(isTabFocused(), "tab should still be focused");
         let chatbox = SocialChatBar.chatbar.firstElementChild;
         ok(chatbox, "chat opened");
         chatbox.minimized = true;
         ok(isTabFocused(), "tab should still be focused");
         // pretend we clicked on the titlebar
         chatbox.onTitlebarClick({button: 0});
-        ok(!chatbox.minimized, "chat should have been restored");
-        ok(isChatFocused(chatbox), "chat should be focused");
-        next();
+        waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat),
+                         function() {
+          ok(!chatbox.minimized, "chat should have been restored");
+          ok(isChatFocused(chatbox), "chat should be focused");
+          is(chatbox, SocialChatBar.chatbar.selectedChat, "chat is marked selected");
+          next();
+        }, "chat should have focus");
       });
     });
   },
 
   // Open 2 chats and give 1 focus.  Minimize the focused one - the second
   // should get focus.
   testMinimizeFocused: function(next) {
     let chatbar = SocialChatBar.chatbar;
     startTestAndWaitForSidebar(function(port) {
       openChatViaSidebarMessage(port, {stealFocus: 1, id: 1}, function() {
         let chat1 = chatbar.firstElementChild;
         openChatViaSidebarMessage(port, {stealFocus: 1, id: 2}, function() {
           is(chatbar.childElementCount, 2, "exactly 2 chats open");
           let chat2 = chat1.nextElementSibling || chat1.previousElementSibling;
           chatbar.selectedChat = chat1;
           chatbar.focus();
-          ok(isChatFocused(chat1), "first chat should be focused");
-          chat1.minimized = true;
-          // minimizing the chat with focus should give it to another.
-          ok(isChatFocused(chat2), "second chat should be focused");
-          next();
+          waitForCondition(function() isChatFocused(chat1),
+                           function() {
+            is(chat1, SocialChatBar.chatbar.selectedChat, "chat1 is marked selected");
+            isnot(chat2, SocialChatBar.chatbar.selectedChat, "chat2 is not marked selected");
+            chat1.minimized = true;
+            waitForCondition(function() isChatFocused(chat2),
+                             function() {
+              // minimizing the chat with focus should give it to another.
+              isnot(chat1, SocialChatBar.chatbar.selectedChat, "chat1 is not marked selected");
+              is(chat2, SocialChatBar.chatbar.selectedChat, "chat2 is marked selected");
+              next();
+            }, "chat2 should have focus");
+          }, "chat1 should have focus");
         });
       });
     });
   },
 
   // Open 2 chats, select (but not focus) one, then re-request it be
   // opened via a message.  Focus should not move.
   testReopenNonFocused: function(next) {
@@ -264,40 +289,42 @@ var tests = {
     let chatbar = SocialChatBar.chatbar;
     startTestAndWaitForSidebar(function(port) {
       openChatViaSidebarMessage(port, {id: 1}, function() {
         let chat1 = chatbar.firstElementChild;
         openChatViaSidebarMessage(port, {id: 2}, function() {
           let chat2 = chat1.nextElementSibling || chat1.previousElementSibling;
           chatbar.selectedChat = chat2;
           chatbar.focus();
-          ok(isChatFocused(chat2), "new chat is focused");
-          // Our chats have 3 focusable elements, so it takes 4 TABs to move
-          // to the new chat.
-          sendTabAndWaitForFocus(chat2, "input1", function() {
-            is(chat2.iframe.contentDocument.activeElement.getAttribute("id"), "input1",
-               "first input field has focus");
-            ok(isChatFocused(chat2), "new chat still focused after first tab");
-            sendTabAndWaitForFocus(chat2, "input2", function() {
-              ok(isChatFocused(chat2), "new chat still focused after tab");
-              is(chat2.iframe.contentDocument.activeElement.getAttribute("id"), "input2",
-                 "second input field has focus");
-              sendTabAndWaitForFocus(chat2, "iframe", function() {
+          waitForCondition(function() isChatFocused(chatbar.selectedChat),
+                           function() {
+            // Our chats have 3 focusable elements, so it takes 4 TABs to move
+            // to the new chat.
+            sendTabAndWaitForFocus(chat2, "input1", function() {
+              is(chat2.iframe.contentDocument.activeElement.getAttribute("id"), "input1",
+                 "first input field has focus");
+              ok(isChatFocused(chat2), "new chat still focused after first tab");
+              sendTabAndWaitForFocus(chat2, "input2", function() {
                 ok(isChatFocused(chat2), "new chat still focused after tab");
-                is(chat2.iframe.contentDocument.activeElement.getAttribute("id"), "iframe",
-                   "iframe has focus");
-                // this tab now should move to the next chat, but focus the
-                // document element itself (hence the null eltid)
-                sendTabAndWaitForFocus(chat1, null, function() {
-                  ok(isChatFocused(chat1), "first chat is focused");
-                  next();
+                is(chat2.iframe.contentDocument.activeElement.getAttribute("id"), "input2",
+                   "second input field has focus");
+                sendTabAndWaitForFocus(chat2, "iframe", function() {
+                  ok(isChatFocused(chat2), "new chat still focused after tab");
+                  is(chat2.iframe.contentDocument.activeElement.getAttribute("id"), "iframe",
+                     "iframe has focus");
+                  // this tab now should move to the next chat, but focus the
+                  // document element itself (hence the null eltid)
+                  sendTabAndWaitForFocus(chat1, null, function() {
+                    ok(isChatFocused(chat1), "first chat is focused");
+                    next();
+                  });
                 });
               });
             });
-          });
+          }, "chat should have focus");
         });
       });
     });
   },
 
   // Open a chat and focus an element other than the first. Move focus to some
   // other item (the tab itself in this case), then focus the chatbar - the
   // same element that was previously focused should still have focus.
@@ -305,23 +332,30 @@ var tests = {
     let chatbar = SocialChatBar.chatbar;
     startTestAndWaitForSidebar(function(port) {
       openChatViaUser();
       let chat = chatbar.firstElementChild;
       // need to wait for the content to load before we can focus it.
       chat.addEventListener("DOMContentLoaded", function DOMContentLoaded() {
         chat.removeEventListener("DOMContentLoaded", DOMContentLoaded);
         chat.iframe.contentDocument.getElementById("input2").focus();
-        is(chat.iframe.contentDocument.activeElement.getAttribute("id"), "input2",
-           "correct input field has focus");
-        // set focus to the tab.
-        let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
-        Services.focus.moveFocus(tabb.contentWindow, null, Services.focus.MOVEFOCUS_ROOT, 0);
-        ok(isTabFocused(), "tab took focus");
-        chatbar.focus();
-        ok(isChatFocused(chat), "chat took focus");
-        is(chat.iframe.contentDocument.activeElement.getAttribute("id"), "input2",
-           "correct input field still has focus");
-        next();
+        waitForCondition(function() isChatFocused(chat),
+                         function() {
+          is(chat.iframe.contentDocument.activeElement.getAttribute("id"), "input2",
+             "correct input field has focus");
+          // set focus to the tab.
+          let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
+          Services.focus.moveFocus(tabb.contentWindow, null, Services.focus.MOVEFOCUS_ROOT, 0);
+          waitForCondition(function() isTabFocused(),
+                           function() {
+            chatbar.focus();
+            waitForCondition(function() isChatFocused(chat),
+                             function() {
+              is(chat.iframe.contentDocument.activeElement.getAttribute("id"), "input2",
+                 "correct input field still has focus");
+              next();
+            }, "chat took focus");
+          }, "tab has focus");
+        }, "chat took focus");
       });
     });
   },
 };
--- a/browser/base/content/test/social/browser_social_markButton.js
+++ b/browser/base/content/test/social/browser_social_markButton.js
@@ -4,17 +4,17 @@
 
 let prefName = "social.enabled",
     gFinishCB;
 
 function test() {
   waitForExplicitFinish();
 
   // Need to load a http/https/ftp/ftps page for the social mark button to appear
-  let tab = gBrowser.selectedTab = gBrowser.addTab("https://example.com", {skipAnimation: true});
+  let tab = gBrowser.selectedTab = gBrowser.addTab("https://test1.example.com", {skipAnimation: true});
   tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
     tab.linkedBrowser.removeEventListener("load", tabLoad, true);
     executeSoon(tabLoaded);
   }, true);
 
   registerCleanupFunction(function() {
     Services.prefs.clearUserPref(prefName);
     gBrowser.removeTab(tab);
@@ -69,20 +69,21 @@ function testInitial(finishcb) {
         });
       });
     });
     markButton.click();
   }, "provider didn't provide page-mark-config");
 }
 
 function testStillMarkedIn2Tabs() {
-  let toMark = "http://example.com";
+  let toMark = "http://test2.example.com";
   let markUri = Services.io.newURI(toMark, null, null);
   let markButton = SocialMark.button;
   let initialTab = gBrowser.selectedTab;
+  info("initialTab has loaded " + gBrowser.currentURI.spec);
   is(markButton.hasAttribute("marked"), false, "SocialMark button should not have 'marked' for the initial tab");
   let tab1 = gBrowser.selectedTab = gBrowser.addTab(toMark);
   let tab1b = gBrowser.getBrowserForTab(tab1);
 
   tab1b.addEventListener("load", function tabLoad(event) {
     tab1b.removeEventListener("load", tabLoad, true);
     let tab2 = gBrowser.selectedTab = gBrowser.addTab(toMark);
     let tab2b = gBrowser.getBrowserForTab(tab2);
@@ -94,41 +95,45 @@ function testStillMarkedIn2Tabs() {
         ok(!marked, "page is unmarked in annotations");
         markButton.click();
         waitForCondition(function() markButton.hasAttribute("marked"), function() {
           Social.isURIMarked(markUri, function(marked) {
             ok(marked, "page is marked in annotations");
             // and switching to the first tab (with the same URL) should still reflect marked.
             gBrowser.selectedTab = tab1;
             is(markButton.hasAttribute("marked"), true, "SocialMark button should reflect the marked state");
+            // wait for tabselect
+            gBrowser.tabContainer.addEventListener("TabSelect", function onTabSelect() {
+              gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect, false);
+              waitForCondition(function() !markButton.hasAttribute("marked"), function() {
+                gBrowser.selectedTab = tab1;
+      
+                SocialMark.togglePageMark(function() {
+                  Social.isURIMarked(gBrowser.currentURI, function(marked) {
+                    ok(!marked, "page is unmarked in annotations");
+                    is(markButton.hasAttribute("marked"), false, "mark button should not be marked");
+                    gBrowser.removeTab(tab1);
+                    gBrowser.removeTab(tab2);
+                    executeSoon(testStillMarkedAfterReopen);
+                  });
+                });
+              }, "button has been unmarked");
+            }, false);
             // but switching back the initial one should reflect not marked.
             gBrowser.selectedTab = initialTab;
-            waitForCondition(function() !markButton.hasAttribute("marked"), function() {
-              gBrowser.selectedTab = tab1;
-    
-              SocialMark.togglePageMark(function() {
-                Social.isURIMarked(gBrowser.currentURI, function(marked) {
-                  ok(!marked, "page is unmarked in annotations");
-                  is(markButton.hasAttribute("marked"), false, "mark button should not be marked");
-                  gBrowser.removeTab(tab1);
-                  gBrowser.removeTab(tab2);
-                  executeSoon(testStillMarkedAfterReopen);
-                });
-              });
-            }, "button has been unmarked");
           });
         }, "button has been marked");
       });
 
     }, true);
   }, true);
 }
 
 function testStillMarkedAfterReopen() {
-  let toMark = "http://example.com";
+  let toMark = "http://test2.example.com";
   let markButton = SocialMark.button;
 
   is(markButton.hasAttribute("marked"), false, "Reopen: SocialMark button should not have 'marked' for the initial tab");
   let tab = gBrowser.selectedTab = gBrowser.addTab(toMark);
   let tabb = gBrowser.getBrowserForTab(tab);
   tabb.addEventListener("load", function tabLoad(event) {
     tabb.removeEventListener("load", tabLoad, true);
     SocialMark.togglePageMark(function() {
@@ -149,17 +154,17 @@ function testStillMarkedAfterReopen() {
           });
         }, true);
       }, "button is now unmarked");
     });
   }, true);
 }
 
 function testOnlyMarkCertainUrlsTabSwitch() {
-  let toMark = "http://example.com";
+  let toMark = "http://test2.example.com";
   let notSharable = "about:blank";
   let markButton = SocialMark.button;
   let tab = gBrowser.selectedTab = gBrowser.addTab(toMark);
   let tabb = gBrowser.getBrowserForTab(tab);
   tabb.addEventListener("load", function tabLoad(event) {
     tabb.removeEventListener("load", tabLoad, true);
     ok(!markButton.hidden, "SocialMark button not hidden for http url");
     let tab2 = gBrowser.selectedTab = gBrowser.addTab(notSharable);
@@ -174,17 +179,17 @@ function testOnlyMarkCertainUrlsTabSwitc
       gBrowser.removeTab(tab);
       gBrowser.removeTab(tab2);
       executeSoon(testOnlyMarkCertainUrlsSameTab);
     }, true);
   }, true);
 }
 
 function testOnlyMarkCertainUrlsSameTab() {
-  let toMark = "http://example.com";
+  let toMark = "http://test2.example.com";
   let notSharable = "about:blank";
   let markButton = SocialMark.button;
   let tab = gBrowser.selectedTab = gBrowser.addTab(toMark);
   let tabb = gBrowser.getBrowserForTab(tab);
   tabb.addEventListener("load", function tabLoad(event) {
     tabb.removeEventListener("load", tabLoad, true);
     ok(!markButton.disabled, "SocialMark button not disabled for http url");
     tabb.addEventListener("load", function tabLoad(event) {
--- a/browser/base/content/test/social/moz.build
+++ b/browser/base/content/test/social/moz.build
@@ -1,6 +1,7 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+DIRS += ['opengraph']
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/opengraph/Makefile.in
@@ -0,0 +1,24 @@
+# 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/.
+
+DEPTH		= @DEPTH@
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+relativesrcdir  = @relativesrcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+_BROWSER_FILES = \
+                 opengraph.html \
+                 og_invalid_url.html \
+                 shortlink_linkrel.html \
+                 shorturl_link.html \
+                 shorturl_linkrel.html \
+                 $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
+libs::	$(_BROWSER_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/opengraph/moz.build
@@ -0,0 +1,4 @@
+# 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/.
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/opengraph/og_invalid_url.html
@@ -0,0 +1,11 @@
+<html xmlns:og="http://ogp.me/ns#">
+<head>
+  <meta property="og:url" content="chrome://browser/content/aboutDialog.xul"/>
+  <meta property="og:site_name" content="Evil chrome delivering website"/>
+  <meta property="og:description"
+        content="A test corpus file for open graph tags passing a bad url"/>
+</head>
+<body>
+    Open Graph Test Page
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/opengraph/opengraph.html
@@ -0,0 +1,13 @@
+<html xmlns:og="http://ogp.me/ns#">
+<head>
+  <meta property="og:title" content="&gt;This is my title&lt;"/>
+  <meta property="og:url" content="https://www.mozilla.org"/>
+  <meta property="og:image" content="https://www.mozilla.org/favicon.png"/>
+  <meta property="og:site_name" content="&#62;My simple test page&#60;"/>
+  <meta property="og:description"
+        content="A test corpus file for open graph tags we care about"/>
+</head>
+<body>
+    Open Graph Test Page
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/opengraph/shortlink_linkrel.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+    <link rel="image_src" href="http://example.com/1234/56789.jpg" id="image-src" />
+    <link id="canonicalurl" rel="canonical" href="http://www.example.com/photos/56789/" />
+    <link rel="shortlink" href="http://imshort/p/abcde" />
+</head>
+<body>
+    link[rel='shortlink']
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/opengraph/shorturl_link.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+    <link rel="image_src" href="http://example.com/1234/56789.jpg" id="image-src" />
+    <link id="canonicalurl" rel="canonical" href="http://www.example.com/photos/56789/" />
+    <link id="shorturl" rev="canonical" type="text/html" href="http://imshort/p/abcde" />
+</head>
+<body>
+    link id="shorturl"
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/opengraph/shorturl_linkrel.html
@@ -0,0 +1,25 @@
+<html>
+<head>
+	<title>Test Image</title>
+
+        <meta name="description" content="Iron  man in a tutu" />
+	<meta name="title" content="Test Image" />
+
+	<meta name="medium" content="image" />
+	<link rel="image_src" href="http://example.com/1234/56789.jpg" id="image-src" />
+	<link id="canonicalurl" rel="canonical" href="http://www.example.com/photos/56789/" />
+	<link id="shorturl" href="http://imshort/p/abcde" />
+
+        <meta property="og:title" content="TestImage" />
+        <meta property="og:type" content="photos:photo" />
+        <meta property="og:url" content="http://www.example.com/photos/56789/" />
+        <meta property="og:site_name" content="My Photo Site" />
+        <meta property="og:description" content="Iron man in a tutu" />
+        <meta property="og:image" content="http://example.com/1234/56789.jpg" />
+        <meta property="og:image:width" content="480" />
+        <meta property="og:image:height" content="640" />
+</head>
+<body>
+    link[rel='shorturl']
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/share.html
@@ -0,0 +1,18 @@
+<html>
+  <head>
+    <meta charset="utf-8">
+    <script>
+      var shareData;
+      addEventListener("OpenGraphData", function(e) {
+        shareData = JSON.parse(e.detail);
+        var port = navigator.mozSocial.getWorker().port;
+        port.postMessage({topic: "share-data-message", result: shareData});
+        // share windows self-close
+        window.close();
+      })
+    </script>
+  </head>
+  <body>
+    <p>This is a test social share window.</p>
+  </body>
+</html>
--- a/browser/base/content/test/social/social_worker.js
+++ b/browser/base/content/test/social/social_worker.js
@@ -128,11 +128,15 @@ onconnect = function(e) {
         apiPort.postMessage({topic: "social.ambient-notification", data: icon});
         break;
       case "test-isVisible":
         sidebarPort.postMessage({topic: "test-isVisible"});
         break;
       case "test-isVisible-response":
         testPort.postMessage({topic: "got-isVisible-response", result: event.data.result});
         break;
+      case "share-data-message":
+        if (testPort)
+          testPort.postMessage({topic:"got-share-data-message", result: event.data.result});
+        break;
     }
   }
 }
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1165,17 +1165,17 @@ BrowserGlue.prototype = {
     var notifyBox = win.gBrowser.getNotificationBox();
     var notification = notifyBox.appendNotification(text, title, null,
                                                     notifyBox.PRIORITY_CRITICAL_MEDIUM,
                                                     buttons);
     notification.persistence = -1; // Until user closes it
   },
 
   _migrateUI: function BG__migrateUI() {
-    const UI_VERSION = 12;
+    const UI_VERSION = 13;
     const BROWSER_DOCURL = "chrome://browser/content/browser.xul#";
     let currentUIVersion = 0;
     try {
       currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
     } catch(ex) {}
     if (currentUIVersion >= UI_VERSION)
       return;
 
@@ -1358,16 +1358,24 @@ BrowserGlue.prototype = {
           // Just append.
           currentset = currentset.replace(/(^|,)window-controls($|,)/,
                                           "$1bookmarks-menu-button,window-controls$2")
         }
         this._setPersist(toolbarResource, currentsetResource, currentset);
       }
     }
 
+    if (currentUIVersion < 13) {
+      try {
+        if (Services.prefs.getBoolPref("plugins.hide_infobar_for_missing_plugin"))
+          Services.prefs.setBoolPref("plugins.notifyMissingFlash", false);
+      }
+      catch (ex) {}
+    }
+
     if (this._dirty)
       this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();
 
     delete this._rdf;
     delete this._dataSource;
 
     // Update the migration version.
     Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -141,16 +141,25 @@ var gAdvancedPane = {
     var toPref = document.getElementById("gfx.direct2d.disabled");
     toPref.value = fromPref.value;
 #endif
   },
 
   // DATA CHOICES TAB
 
   /**
+   * opening links behind a modal dialog is poor form. Work around flawed text-link handling here.
+   */
+  openTextLink: function (evt) {
+    let where = Services.prefs.getBoolPref("browser.preferences.instantApply") ? "tab" : "window";
+    openUILinkIn(evt.target.getAttribute("href"), where);
+    evt.preventDefault();
+  },
+
+  /**
    * Set up or hide the Learn More links for various data collection options
    */
   _setupLearnMoreLink: function (pref, element) {
     // set up the Learn More link with the correct URL
     let url = Services.prefs.getCharPref(pref);
     let el = document.getElementById(element);
 
     if (url) {
--- a/browser/components/preferences/advanced.xul
+++ b/browser/components/preferences/advanced.xul
@@ -202,50 +202,53 @@
             <hbox>
               <checkbox id="submitTelemetryBox"
                         preference="toolkit.telemetry.enabled"
                         label="&enableTelemetry.label;"
                         accesskey="&enableTelemetry.accesskey;"/>
               <spacer flex="1"/>
               <label id="telemetryLearnMore"
                      class="text-link"
-                     value="&telemetryLearnMore.label;"/>
+                     value="&telemetryLearnMore.label;"
+                     onclick="gAdvancedPane.openTextLink(event)"/>
             </hbox>
           </groupbox>
 #endif
 #ifdef MOZ_SERVICES_HEALTHREPORT
           <groupbox>
             <caption label="&healthReportSection.label;"/>
             <description>&healthReportDesc.label;</description>
             <hbox>
               <checkbox id="submitHealthReportBox"
                         oncommand="gAdvancedPane.updateSubmitHealthReport();"
                         label="&enableHealthReport.label;"
                         accesskey="&enableHealthReport.accesskey;"/>
               <spacer flex="1"/>
               <label id="FHRLearnMore"
                      class="text-link"
-                     value="&healthReportLearnMore.label;"/>
+                     value="&healthReportLearnMore.label;"
+                     onclick="gAdvancedPane.openTextLink(event)"/>
             </hbox>
           </groupbox>
 #endif
 #ifdef MOZ_CRASHREPORTER
           <groupbox>
             <caption label="&crashReporterSection.label;"/>
             <description>&crashReporterDesc.label;</description>
             <hbox>
               <checkbox id="submitCrashesBox"
                         oncommand="gAdvancedPane.updateSubmitCrashes();"
                         label="&enableCrashReporter.label;"
                         accesskey="&enableCrashReporter.accesskey;"/>
 
               <spacer flex="1"/>
               <label id="crashReporterLearnMore"
                      class="text-link"
-                     value="&crashReporterLearnMore.label;"/>
+                     value="&crashReporterLearnMore.label;"
+                     onclick="gAdvancedPane.openTextLink(event)"/>
             </hbox>
           </groupbox>
 #endif
         </tabpanel>
 #endif
         <!-- Network -->
         <tabpanel id="networkPanel" orient="vertical">
 
--- a/browser/components/privatebrowsing/test/browser/Makefile.in
+++ b/browser/components/privatebrowsing/test/browser/Makefile.in
@@ -7,16 +7,18 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_FILES =  \
 		head.js \
+                browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js \
+                browser_privatebrowsing_aboutSessionRestore.js \
 		browser_privatebrowsing_certexceptionsui.js \
 		browser_privatebrowsing_concurrent.js \
 		browser_privatebrowsing_concurrent_page.html \
 		browser_privatebrowsing_cookieacceptdialog.js \
 		browser_privatebrowsing_cookieacceptdialog.html \
 		browser_privatebrowsing_crh.js \
 		browser_privatebrowsing_downloadLastDir.js \
 		browser_privatebrowsing_downloadLastDir_c.js \
@@ -27,16 +29,17 @@ MOCHITEST_BROWSER_FILES =  \
 		browser_privatebrowsing_lastpbcontextexited.js \
 		browser_privatebrowsing_localStorage.js \
 		browser_privatebrowsing_localStorage_before_after.js \
 		browser_privatebrowsing_localStorage_before_after_page.html \
 		browser_privatebrowsing_localStorage_before_after_page2.html \
 		browser_privatebrowsing_localStorage_page1.html \
 		browser_privatebrowsing_localStorage_page2.html \
 		browser_privatebrowsing_nonbrowser.js \
+                browser_privatebrowsing_noSessionRestoreMenuOption.js \
 		browser_privatebrowsing_opendir.js \
 		browser_privatebrowsing_openlocation.js \
 		browser_privatebrowsing_openLocationLastURL.js \
 		browser_privatebrowsing_placestitle.js \
 		browser_privatebrowsing_placesTitleNoUpdate.js \
 		browser_privatebrowsing_placesTitleNoUpdate.html \
 		browser_privatebrowsing_popupblocker.js \
 		browser_privatebrowsing_protocolhandler.js \
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js
@@ -0,0 +1,46 @@
+/* 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/. */
+
+// This test checks that the Session Restore about:home button
+// is disabled in private mode
+
+function test() {
+  waitForExplicitFinish();
+
+  function testNoSessionRestoreButton() {
+    let win = OpenBrowserWindow({private: true});
+    win.addEventListener("load", function onLoad() {
+      win.removeEventListener("load", onLoad, false);
+      executeSoon(function() {
+        info("The second private window got loaded");
+        let newTab = win.gBrowser.addTab("about:home");
+        win.gBrowser.selectedTab = newTab;
+        let tabBrowser = win.gBrowser.getBrowserForTab(newTab);
+        tabBrowser.addEventListener("load", function tabLoadListener() {
+          tabBrowser.removeEventListener("load", tabLoadListener, true);
+          executeSoon(function() {
+            info("about:home got loaded");
+            let sessionRestoreButton = win.gBrowser
+                                          .contentDocument
+                                          .getElementById("restorePreviousSession");
+            is(win.getComputedStyle(sessionRestoreButton).display, 
+               "none", "The Session Restore about:home button should be disabled");
+            win.close();
+            finish();
+          });
+        }, true);
+      });
+    }, false);
+  }
+
+  let win = OpenBrowserWindow({private: true});
+  win.addEventListener("load", function onload() {
+    win.removeEventListener("load", onload, false);
+    executeSoon(function() {
+      info("The first private window got loaded");
+      win.close();
+      testNoSessionRestoreButton();
+    });
+  }, false);
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutSessionRestore.js
@@ -0,0 +1,45 @@
+/* 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/. */
+
+// This test checks that the session restore button from about:sessionrestore
+// is disabled in private mode
+
+function test() {
+  waitForExplicitFinish();
+
+  function testNoSessionRestoreButton() {
+    let win = OpenBrowserWindow({private: true});
+    win.addEventListener("load", function onLoad() {
+      win.removeEventListener("load", onLoad, false);
+      executeSoon(function() {
+        info("The second private window got loaded");
+        let newTab = win.gBrowser.addTab("about:sessionrestore");
+        win.gBrowser.selectedTab = newTab;
+        let tabBrowser = win.gBrowser.getBrowserForTab(newTab);
+        tabBrowser.addEventListener("load", function tabLoadListener() {
+          tabBrowser.removeEventListener("load", tabLoadListener, true);
+          executeSoon(function() {
+            info("about:sessionrestore got loaded");
+            let restoreButton = win.gBrowser.contentDocument
+                                            .getElementById("errorTryAgain");
+            ok(restoreButton.disabled,
+               "The Restore about:sessionrestore button should be disabled");
+            win.close();
+            finish();
+          });
+        }, true);
+      });
+    }, false);
+  }
+
+  let win = OpenBrowserWindow({private: true});
+  win.addEventListener("load", function onload() {
+    win.removeEventListener("load", onload, false);
+    executeSoon(function() {
+      info("The first private window got loaded");
+      win.close();
+      testNoSessionRestoreButton();
+    });
+  }, false);
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_noSessionRestoreMenuOption.js
@@ -0,0 +1,34 @@
+/* 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/. */
+
+// This test checks that the Session Restore menu option is not enabled in private mode
+
+function test() {
+  waitForExplicitFinish();
+
+  function testNoSessionRestoreMenuItem() { 
+    let win = OpenBrowserWindow({private: true});
+    win.addEventListener("load", function onLoad() {
+      win.removeEventListener("load", onLoad, false);
+      ok(true, "The second private window got loaded");
+      let srCommand = win.document.getElementById("Browser:RestoreLastSession");
+      ok(srCommand, "The Session Restore command should exist");
+      is(PrivateBrowsingUtils.isWindowPrivate(win), true,
+         "PrivateBrowsingUtils should report the correct per-window private browsing status");
+      is(srCommand.hasAttribute("disabled"), true,
+         "The Session Restore command should be disabled in private browsing mode");
+      win.close();
+      finish();
+    }, false);
+  }
+
+  let win = OpenBrowserWindow({private: true});
+  win.addEventListener("load", function onload() {
+    win.removeEventListener("load", onload, false);
+    ok(true, "The first private window got loaded");
+    win.gBrowser.addTab("about:mozilla");
+    win.close();
+    testNoSessionRestoreMenuItem();
+  }, false);
+}
copy from browser/config/mozconfigs/linux32/release
copy to browser/config/mozconfigs/linux32/beta
--- a/browser/config/mozconfigs/linux32/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux32/l10n-mozconfig
@@ -1,9 +1,9 @@
-ac_add_options --with-l10n-base=../../l10n-central
+ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
 
 . $topsrcdir/build/unix/mozconfig.linux32
 
--- a/browser/config/mozconfigs/linux32/release
+++ b/browser/config/mozconfigs/linux32/release
@@ -1,25 +1,7 @@
-ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
-ac_add_options --enable-official-branding
-
-. $topsrcdir/build/unix/mozconfig.linux32
-
-# Avoid dependency on libstdc++ 4.5
-ac_add_options --enable-stdcxx-compat
-
-# PGO
-mk_add_options MOZ_PGO=1
-mk_add_options PROFILE_GEN_SCRIPT='EXTRA_TEST_ARGS=10 $(MAKE) -C $(MOZ_OBJDIR) pgo-profile-run'
+# This make file should be identical to the beta mozconfig, apart from the
+# safeguard below
+. "$topsrcdir/browser/config/mozconfigs/linux32/beta"
 
-# Needed to enable breakpad in application.ini
-export MOZILLA_OFFICIAL=1
-
-export MOZ_TELEMETRY_REPORTING=1
-
-# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
-ac_add_options --enable-warnings-as-errors
-
-# Package js shell.
-export MOZ_PACKAGE_JSSHELL=1
-
-. "$topsrcdir/build/mozconfig.common.override"
+# safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
+# defines.sh during the beta cycle
+export BUILDING_RELEASE=1
copy from browser/config/mozconfigs/linux64/release
copy to browser/config/mozconfigs/linux64/beta
--- a/browser/config/mozconfigs/linux64/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux64/l10n-mozconfig
@@ -1,9 +1,9 @@
-ac_add_options --with-l10n-base=../../l10n-central
+ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
 
 . $topsrcdir/build/unix/mozconfig.linux
 
--- a/browser/config/mozconfigs/linux64/release
+++ b/browser/config/mozconfigs/linux64/release
@@ -1,25 +1,7 @@
-ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
-ac_add_options --enable-official-branding
-
-. $topsrcdir/build/unix/mozconfig.linux
-
-# Avoid dependency on libstdc++ 4.5
-ac_add_options --enable-stdcxx-compat
-
-# PGO
-mk_add_options MOZ_PGO=1
-mk_add_options PROFILE_GEN_SCRIPT='EXTRA_TEST_ARGS=10 $(MAKE) -C $(MOZ_OBJDIR) pgo-profile-run'
+# This make file should be identical to the beta mozconfig, apart from the
+# safeguard below
+. "$topsrcdir/browser/config/mozconfigs/linux64/beta"
 
-# Needed to enable breakpad in application.ini
-export MOZILLA_OFFICIAL=1
-
-export MOZ_TELEMETRY_REPORTING=1
-
-# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
-ac_add_options --enable-warnings-as-errors
-
-# Package js shell.
-export MOZ_PACKAGE_JSSHELL=1
-
-. "$topsrcdir/build/mozconfig.common.override"
+# safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
+# defines.sh during the beta cycle
+export BUILDING_RELEASE=1
copy from browser/config/mozconfigs/macosx-universal/release
copy to browser/config/mozconfigs/macosx-universal/beta
--- a/browser/config/mozconfigs/macosx-universal/l10n-mozconfig
+++ b/browser/config/mozconfigs/macosx-universal/l10n-mozconfig
@@ -1,11 +1,11 @@
 . "$topsrcdir/browser/config/mozconfigs/common"
 
-ac_add_options --with-l10n-base=../../../l10n-central
+ac_add_options --with-l10n-base=../../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --with-macbundlename-prefix=Firefox
 ac_add_options --with-ccache
 
 export MOZILLA_OFFICIAL=1
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/macosx-universal/release
+++ b/browser/config/mozconfigs/macosx-universal/release
@@ -1,21 +1,7 @@
-. $topsrcdir/build/macosx/universal/mozconfig
-
-# Universal builds override the default of browser (bug 575283 comment 29)
-ac_add_options --enable-application=browser
-
-ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
-ac_add_options --enable-official-branding
+# This make file should be identical to the beta mozconfig, apart from the
+# safeguard below
+. "$topsrcdir/browser/config/mozconfigs/macosx-universal/beta"
 
-# Needed to enable breakpad in application.ini
-export MOZILLA_OFFICIAL=1
-
-export MOZ_TELEMETRY_REPORTING=1
-
-# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
-ac_add_options --enable-warnings-as-errors
-
-# Package js shell.
-export MOZ_PACKAGE_JSSHELL=1
-
-. "$topsrcdir/build/mozconfig.common.override"
+# safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
+# defines.sh during the beta cycle
+export BUILDING_RELEASE=1
--- a/browser/config/mozconfigs/macosx64/l10n-mozconfig
+++ b/browser/config/mozconfigs/macosx64/l10n-mozconfig
@@ -1,8 +1,8 @@
 . "$topsrcdir/browser/config/mozconfigs/common"
 
-ac_add_options --with-l10n-base=../../l10n-central
+ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --with-ccache
 
 . "$topsrcdir/build/mozconfig.common.override"
copy from browser/config/mozconfigs/win32/release
copy to browser/config/mozconfigs/win32/beta
--- a/browser/config/mozconfigs/win32/l10n-mozconfig
+++ b/browser/config/mozconfigs/win32/l10n-mozconfig
@@ -1,13 +1,13 @@
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
-ac_add_options --with-l10n-base=../../l10n-central
+ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-metro
 ac_add_options --with-windows-version=601
 
 export MOZILLA_OFFICIAL=1
 
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
--- a/browser/config/mozconfigs/win32/release
+++ b/browser/config/mozconfigs/win32/release
@@ -1,33 +1,7 @@
-. "$topsrcdir/browser/config/mozconfigs/common"
-
-# for pgo
-mk_add_options MOZ_PGO=1
-mk_add_options PROFILE_GEN_SCRIPT='$(MAKE) -C $(MOZ_OBJDIR) pgo-profile-run'
-
-ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-ac_add_options --enable-update-packaging
-ac_add_options --enable-jemalloc
-ac_add_options --enable-official-branding
-
-# Needed to enable breakpad in application.ini
-export MOZILLA_OFFICIAL=1
-
-export MOZ_TELEMETRY_REPORTING=1
+# This make file should be identical to the beta mozconfig, apart from the
+# safeguard below
+. "$topsrcdir/browser/config/mozconfigs/win32/beta"
 
-if test -z "${_PYMAKE}"; then
-  mk_add_options MOZ_MAKE_FLAGS=-j1
-fi
-
-if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
-  . $topsrcdir/build/win32/mozconfig.vs2010-win64
-else
-  . $topsrcdir/build/win32/mozconfig.vs2010
-fi
-
-# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
-ac_add_options --enable-warnings-as-errors
-
-# Package js shell.
-export MOZ_PACKAGE_JSSHELL=1
-
-. "$topsrcdir/build/mozconfig.common.override"
+# safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
+# defines.sh during the beta cycle
+export BUILDING_RELEASE=1
--- a/browser/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^
+++ b/browser/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^
@@ -1,1 +1,2 @@
 Content-Type: text/cache-manifest; charset=ISO-8859-1
+Last-Modified: Tue, 23 Apr 9998 11:41:13 GMT
--- a/browser/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^
+++ b/browser/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^
@@ -1,1 +1,2 @@
 Content-Type: text/cache-manifest
+Last-Modified: Tue, 23 Apr 9998 11:41:13 GMT
--- a/browser/devtools/debugger/DebuggerUI.jsm
+++ b/browser/devtools/debugger/DebuggerUI.jsm
@@ -4,17 +4,17 @@
  * 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 = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
-const DBG_XUL = "chrome://browser/content/debugger.xul";
+const DBG_XUL = "chrome://browser/content/devtools/debugger.xul";
 const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
 const CHROME_DEBUGGER_PROFILE_NAME = "-chrome-debugger";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this,
   "DebuggerServer", "resource://gre/modules/devtools/dbg-server.jsm");
 
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -1,24 +1,24 @@
 <?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/. -->
 <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/devtools/widgets.css" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/content/debugger.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/debugger.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/widgets.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/debugger.css" type="text/css"?>
 <!DOCTYPE window [
   <!ENTITY % debuggerDTD SYSTEM "chrome://browser/locale/devtools/debugger.dtd">
   %debuggerDTD;
 ]>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
-<?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
+<?xul-overlay href="chrome://browser/content/devtools/source-editor-overlay.xul"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
   <script type="text/javascript" src="debugger-controller.js"/>
   <script type="text/javascript" src="debugger-view.js"/>
   <script type="text/javascript" src="debugger-toolbar.js"/>
   <script type="text/javascript" src="debugger-panes.js"/>
 
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -10,17 +10,16 @@ relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_aaa_run_first_leaktest.js \
 	browser_dbg_clean-exit.js \
 	browser_dbg_cmd.js \
 	$(browser_dbg_cmd_break.js disabled until bug 722727 is fixed) \
-	browser_dbg_createChrome.js \
 	$(browser_dbg_createRemote.js disabled for intermittent failures, bug 753225) \
 	browser_dbg_debuggerstatement.js \
 	browser_dbg_listtabs.js \
 	browser_dbg_tabactor-01.js \
 	browser_dbg_tabactor-02.js \
 	browser_dbg_globalactor-01.js \
 	browser_dbg_nav-01.js \
 	browser_dbg_propertyview-01.js \
@@ -56,16 +55,17 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_stack-01.js \
 	browser_dbg_stack-02.js \
 	browser_dbg_stack-03.js \
 	browser_dbg_stack-04.js \
 	browser_dbg_stack-05.js \
 	browser_dbg_location-changes.js \
 	browser_dbg_location-changes-new.js \
 	browser_dbg_location-changes-blank.js \
+	browser_dbg_location-changes-bp.js \
 	browser_dbg_sources-cache.js \
 	browser_dbg_scripts-switching.js \
 	browser_dbg_scripts-sorting.js \
 	browser_dbg_scripts-searching-01.js \
 	browser_dbg_scripts-searching-02.js \
 	browser_dbg_scripts-searching-03.js \
 	browser_dbg_scripts-searching-04.js \
 	browser_dbg_scripts-searching-05.js \
@@ -128,13 +128,23 @@ MOCHITEST_BROWSER_PAGES = \
 	browser_dbg_function-search-02.html \
 	test-function-search-01.js \
 	test-function-search-02.js \
 	test-function-search-03.js \
 	binary_search.html \
 	binary_search.coffee \
 	binary_search.js \
 	binary_search.map \
+	test-location-changes-bp.js \
+	test-location-changes-bp.html \
 	$(NULL)
 
+ifneq (Linux,$(OS_ARCH))
+MOCHITEST_BROWSER_TESTS += \
+	browser_dbg_createChrome.js \
+	$(NULL)
+else
+$(browser_dbg_createChrome.js disabled to fix for ubuntu hangs, bug 847558)
+endif
+
 MOCHITEST_BROWSER_FILES_PARTS = MOCHITEST_BROWSER_TESTS MOCHITEST_BROWSER_PAGES
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes-bp.js
@@ -0,0 +1,163 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that reloading a page with a breakpoint set does not cause it to
+ * fire more than once.
+ */
+
+const TAB_URL = EXAMPLE_URL + "test-location-changes-bp.html";
+const SCRIPT_URL = EXAMPLE_URL + "test-location-changes-bp.js";
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+var sourcesShown = false;
+var tabNavigated = false;
+
+function test()
+{
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.panelWin;
+
+    testAddBreakpoint();
+  });
+}
+
+function testAddBreakpoint()
+{
+  let controller = gDebugger.DebuggerController;
+  controller.activeThread.addOneTimeListener("framesadded", function() {
+    Services.tm.currentThread.dispatch({ run: function() {
+
+      var frames = gDebugger.DebuggerView.StackFrames._container._list;
+
+      is(controller.activeThread.state, "paused",
+         "The debugger statement was reached.");
+
+      is(frames.querySelectorAll(".dbg-stackframe").length, 1,
+         "Should have one frame.");
+
+      gPane.addBreakpoint({ url: SCRIPT_URL, line: 5 }, testResume);
+    }}, 0);
+  });
+
+  gDebuggee.runDebuggerStatement();
+}
+
+function testResume()
+{
+  is(gDebugger.DebuggerController.activeThread.state, "paused",
+    "The breakpoint wasn't hit yet.");
+
+  let thread = gDebugger.DebuggerController.activeThread;
+  thread.addOneTimeListener("resumed", function() {
+    thread.addOneTimeListener("paused", function() {
+      executeSoon(testBreakpointHit);
+    });
+
+    EventUtils.sendMouseEvent({ type: "click" },
+      content.document.querySelector("button"));
+  });
+
+  thread.resume();
+}
+
+function testBreakpointHit()
+{
+  is(gDebugger.DebuggerController.activeThread.state, "paused",
+    "The breakpoint was hit.");
+
+  let thread = gDebugger.DebuggerController.activeThread;
+  thread.addOneTimeListener("paused", function test(aEvent, aPacket) {
+    thread.addOneTimeListener("resumed", function() {
+      executeSoon(testReloadPage);
+    });
+
+    is(aPacket.why.type, "debuggerStatement", "Execution has advanced to the next line.");
+    isnot(aPacket.why.type, "breakpoint", "No ghost breakpoint was hit.");
+    thread.resume();
+  });
+
+  thread.resume();
+}
+
+function testReloadPage()
+{
+  let controller = gDebugger.DebuggerController;
+  controller._target.once("navigate", function onTabNavigated(aEvent, aPacket) {
+    tabNavigated = true;
+    ok(true, "tabNavigated event was fired.");
+    info("Still attached to the tab.");
+    clickAgain();
+  });
+
+  gDebugger.addEventListener("Debugger:SourceShown", function onSourcesShown() {
+    sourcesShown = true;
+    gDebugger.removeEventListener("Debugger:SourceShown", onSourcesShown);
+    clickAgain();
+  });
+
+  content.location.reload();
+}
+
+function clickAgain()
+{
+  if (!sourcesShown || !tabNavigated) {
+    return;
+  }
+
+  let controller = gDebugger.DebuggerController;
+  controller.activeThread.addOneTimeListener("framesadded", function() {
+    is(gDebugger.DebuggerController.activeThread.state, "paused",
+      "The breakpoint was hit.");
+
+    let thread = gDebugger.DebuggerController.activeThread;
+    thread.addOneTimeListener("paused", function test(aEvent, aPacket) {
+      thread.addOneTimeListener("resumed", function() {
+        executeSoon(closeDebuggerAndFinish);
+      });
+
+      is(aPacket.why.type, "debuggerStatement", "Execution has advanced to the next line.");
+      isnot(aPacket.why.type, "breakpoint", "No ghost breakpoint was hit.");
+      thread.resume();
+    });
+
+    thread.resume();
+  });
+
+  EventUtils.sendMouseEvent({ type: "click" },
+    content.document.querySelector("button"));
+}
+
+function testBreakpointHitAfterReload()
+{
+  is(gDebugger.DebuggerController.activeThread.state, "paused",
+    "The breakpoint was hit.");
+
+  let thread = gDebugger.DebuggerController.activeThread;
+  thread.addOneTimeListener("paused", function test(aEvent, aPacket) {
+    thread.addOneTimeListener("resumed", function() {
+      executeSoon(closeDebuggerAndFinish);
+    });
+
+    is(aPacket.why.type, "debuggerStatement", "Execution has advanced to the next line.");
+    isnot(aPacket.why.type, "breakpoint", "No ghost breakpoint was hit.");
+    thread.resume();
+  });
+
+  thread.resume();
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebuggee = null;
+  gDebugger = null;
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/test-location-changes-bp.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'/>
+<script type="text/javascript" src="test-location-changes-bp.js"></script>
+<script type="text/javascript">
+function runDebuggerStatement() {
+  debugger;
+}
+</script>
+</head>
+<body>
+
+<button type="button" onclick="myFunction()">Run</button>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/test-location-changes-bp.js
@@ -0,0 +1,7 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function myFunction() {
+  var a = 1;
+  debugger;
+}
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -187,16 +187,17 @@ this.devtools = {
     this._provider.unload("reload");
     delete this._provider;
     gDevTools._teardown();
     this._chooseProvider();
   },
 };
 
 const FORBIDDEN_IDS = new Set(["toolbox", ""]);
+const MAX_ORDINAL = 99;
 
 /**
  * DevTools is a class that represents a set of developer tools, it holds a
  * set of tools and keeps track of open toolboxes in the browser.
  */
 this.DevTools = function DevTools() {
   this._tools = new Map();     // Map<toolId, tool>
   this._toolboxes = new Map(); // Map<target, toolbox>
@@ -269,28 +270,37 @@ DevTools.prototype = {
     }
     this._tools.delete(toolId);
 
     if (!isQuitApplication) {
       this.emit("tool-unregistered", tool);
     }
   },
 
+  /**
+   * Sorting function used for sorting tools based on their ordinals.
+   */
+  ordinalSort: function DT_ordinalSort(d1, d2) {
+    let o1 = (typeof d1.ordinal == "number") ? d1.ordinal : MAX_ORDINAL;
+    let o2 = (typeof d2.ordinal == "number") ? d2.ordinal : MAX_ORDINAL;
+    return o1 - o2;
+  },
+
   getDefaultTools: function DT_getDefaultTools() {
-    return devtools.defaultTools;
+    return devtools.defaultTools.sort(this.ordinalSort);
   },
 
   getAdditionalTools: function DT_getAdditionalTools() {
     let tools = [];
     for (let [key, value] of this._tools) {
       if (devtools.defaultTools.indexOf(value) == -1) {
         tools.push(value);
       }
     }
-    return tools;
+    return tools.sort(this.ordinalSort);
   },
 
   /**
    * Allow ToolBoxes to get at the list of tools that they should populate
    * themselves with.
    *
    * @return {Map} tools
    *         A map of the the tool definitions registered in this instance
@@ -322,30 +332,22 @@ DevTools.prototype = {
    * Tools have an inherent ordering that can't be represented in a Map so
    * getToolDefinitionArray provides an alternative representation of the
    * definitions sorted by ordinal value.
    *
    * @return {Array} tools
    *         A sorted array of the tool definitions registered in this instance
    */
   getToolDefinitionArray: function DT_getToolDefinitionArray() {
-    const MAX_ORDINAL = 99;
-
     let definitions = [];
     for (let [id, definition] of this.getToolDefinitionMap()) {
       definitions.push(definition);
     }
 
-    definitions.sort(function(d1, d2) {
-      let o1 = (typeof d1.ordinal == "number") ? d1.ordinal : MAX_ORDINAL;
-      let o2 = (typeof d2.ordinal == "number") ? d2.ordinal : MAX_ORDINAL;
-      return o1 - o2;
-    });
-
-    return definitions;
+    return definitions.sort(this.ordinalSort);
   },
 
   /**
    * Show a Toolbox for a target (either by creating a new one, or if a toolbox
    * already exists for the target, by bring to the front the existing one)
    * If |toolId| is specified then the displayed toolbox will have the
    * specified tool selected.
    * If |hostType| is specified then the toolbox will be displayed using the
--- a/browser/devtools/framework/test/browser_toolbox_options.js
+++ b/browser/devtools/framework/test/browser_toolbox_options.js
@@ -81,16 +81,20 @@ function prefChanged(event, data) {
 
 function checkTools() {
   let toolsPref = panelWin.document.querySelectorAll("#default-tools-box > checkbox");
   prefNodes = [];
   index = 0;
   for (let tool of toolsPref) {
     prefNodes.push(tool);
   }
+  // Randomize the order in which we remove the tool and then add them back so
+  // that we get to know if the tabs are correctly placed as per their ordinals.
+  prefNodes = prefNodes.sort(() => Math.random() > 0.5 ? 1: -1);
+
   // Wait for the next turn of the event loop to avoid stack overflow errors.
   executeSoon(toggleTools);
 }
 
 function toggleTools() {
   if (index < prefNodes.length) {
     gDevTools.once("tool-unregistered", checkUnregistered);
     EventUtils.synthesizeMouse(prefNodes[index], 10, 10, {}, panelWin);
@@ -119,17 +123,32 @@ function checkUnregistered(event, data) 
   ok(false, "Something went wrong, " + data.id + " was not unregistered");
   cleanup();
 }
 
 function checkRegistered(event, data) {
   if (data == prefNodes[index - prefNodes.length].getAttribute("id")) {
     ok(true, "Correct tool added back");
     // checking tab on the toolbox
-    ok(doc.getElementById("toolbox-tab-" + data), "Tab added back for " + data);
+    let radio = doc.getElementById("toolbox-tab-" + data);
+    ok(radio, "Tab added back for " + data);
+    if (radio.previousSibling) {
+      ok(+radio.getAttribute("ordinal") >=
+         +radio.previousSibling.getAttribute("ordinal"),
+         "Inserted tab's ordinal is greater than equal to its previous tab." +
+         "Expected " + radio.getAttribute("ordinal") + " >= " +
+         radio.previousSibling.getAttribute("ordinal"));
+    }
+    if (radio.nextSibling) {
+      ok(+radio.getAttribute("ordinal") <
+         +radio.nextSibling.getAttribute("ordinal"),
+         "Inserted tab's ordinal is less than its next tab. Expected " +
+         radio.getAttribute("ordinal") + " < " +
+         radio.nextSibling.getAttribute("ordinal"));
+    }
     index++;
     // Wait for the next turn of the event loop to avoid stack overflow errors.
     executeSoon(toggleTools);
     return;
   }
   ok(false, "Something went wrong, " + data + " was not registered back");
   cleanup();
 }
--- a/browser/devtools/framework/toolbox-options.js
+++ b/browser/devtools/framework/toolbox-options.js
@@ -1,8 +1,13 @@
+/* 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 { utils: Cu } = Components;
 const DISABLED_TOOLS = "devtools.toolbox.disabledTools";
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
 window.addEventListener("load", function onLoad() {
   window.removeEventListener("load", onLoad);
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
-
+const MAX_ORDINAL = 99;
 let Promise = require("sdk/core/promise");
 let EventEmitter = require("devtools/shared/event-emitter");
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
 loader.lazyGetter(this, "Hosts", () => require("devtools/framework/toolbox-hosts").Hosts);
@@ -355,16 +355,20 @@ Toolbox.prototype = {
 
     let id = toolDefinition.id;
 
     let radio = this.doc.createElement("radio");
     radio.className = "toolbox-tab devtools-tab";
     radio.id = "toolbox-tab-" + id;
     radio.setAttribute("flex", "1");
     radio.setAttribute("toolid", id);
+    if (toolDefinition.ordinal == undefined || toolDefinition.ordinal < 0) {
+      toolDefinition.ordinal = MAX_ORDINAL;
+    }
+    radio.setAttribute("ordinal", toolDefinition.ordinal);
     radio.setAttribute("tooltiptext", toolDefinition.tooltip);
 
     radio.addEventListener("command", function(id) {
       this.selectTool(id);
     }.bind(this, id));
 
     if (toolDefinition.icon) {
       let image = this.doc.createElement("image");
@@ -377,18 +381,34 @@ Toolbox.prototype = {
     label.setAttribute("crop", "end");
     label.setAttribute("flex", "1");
 
     let vbox = this.doc.createElement("vbox");
     vbox.className = "toolbox-panel";
     vbox.id = "toolbox-panel-" + id;
 
     radio.appendChild(label);
-    tabs.appendChild(radio);
-    deck.appendChild(vbox);
+
+    // If there is no tab yet, or the ordinal to be added is the largest one.
+    if (tabs.childNodes.length == 0 ||
+        +tabs.lastChild.getAttribute("ordinal") <= toolDefinition.ordinal) {
+      tabs.appendChild(radio);
+      deck.appendChild(vbox);
+    }
+    // else, iterate over all the tabs to get the correct location.
+    else {
+      Array.some(tabs.childNodes, (node, i) => {
+        if (+node.getAttribute("ordinal") > toolDefinition.ordinal) {
+          tabs.insertBefore(radio, node);
+          deck.insertBefore(vbox, deck.childNodes[i + 1]);
+          // + 1 because of options panel.
+          return true;
+        }
+      });
+    }
 
     this._addKeysToWindow();
   },
 
   /**
    * Switch to the tool with the given id
    *
    * @param {string} id
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -1,68 +1,68 @@
 # 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/.
 
 browser.jar:
-    content/browser/devtools/widgets.css          (shared/widgets/widgets.css)
-    content/browser/devtools/widgets/VariablesView.xul (shared/widgets/VariablesView.xul)
-    content/browser/devtools/markup-view.xhtml    (markupview/markup-view.xhtml)
-    content/browser/devtools/markup-view.css      (markupview/markup-view.css)
-    content/browser/devtools/netmonitor.xul           (netmonitor/netmonitor.xul)
-    content/browser/devtools/netmonitor.css           (netmonitor/netmonitor.css)
-    content/browser/devtools/netmonitor-controller.js (netmonitor/netmonitor-controller.js)
-    content/browser/devtools/netmonitor-view.js       (netmonitor/netmonitor-view.js)
-    content/browser/NetworkPanel.xhtml            (webconsole/NetworkPanel.xhtml)
-    content/browser/devtools/webconsole.js        (webconsole/webconsole.js)
-    content/browser/devtools/webconsole.xul       (webconsole/webconsole.xul)
-*   content/browser/scratchpad.xul                (scratchpad/scratchpad.xul)
-    content/browser/scratchpad.js                 (scratchpad/scratchpad.js)
-    content/browser/splitview.css                 (shared/splitview.css)
-    content/browser/devtools/theme-switching.js   (shared/theme-switching.js)
-    content/browser/styleeditor.xul               (styleeditor/styleeditor.xul)
-    content/browser/styleeditor.css               (styleeditor/styleeditor.css)
-    content/browser/devtools/computedview.xhtml   (styleinspector/computedview.xhtml)
-    content/browser/devtools/cssruleview.xhtml    (styleinspector/cssruleview.xhtml)
-    content/browser/devtools/ruleview.css         (styleinspector/ruleview.css)
-    content/browser/devtools/layoutview/view.js   (layoutview/view.js)
-    content/browser/devtools/layoutview/view.xhtml  (layoutview/view.xhtml)
-    content/browser/devtools/layoutview/view.css  (layoutview/view.css)
-    content/browser/devtools/fontinspector/font-inspector.js    (fontinspector/font-inspector.js)
-    content/browser/devtools/fontinspector/font-inspector.xhtml (fontinspector/font-inspector.xhtml)
-    content/browser/devtools/fontinspector/font-inspector.css   (fontinspector/font-inspector.css)
-    content/browser/orion.js                      (sourceeditor/orion/orion.js)
-*   content/browser/source-editor-overlay.xul     (sourceeditor/source-editor-overlay.xul)
-    content/browser/debugger.xul                  (debugger/debugger.xul)
-    content/browser/debugger.css                  (debugger/debugger.css)
-    content/browser/debugger-controller.js        (debugger/debugger-controller.js)
-    content/browser/debugger-view.js              (debugger/debugger-view.js)
-    content/browser/debugger-toolbar.js           (debugger/debugger-toolbar.js)
-    content/browser/debugger-panes.js             (debugger/debugger-panes.js)
-    content/browser/profiler.xul                  (profiler/profiler.xul)
-    content/browser/devtools/cleopatra.html       (profiler/cleopatra/cleopatra.html)
-    content/browser/devtools/profiler/cleopatra/css/ui.css              (profiler/cleopatra/css/ui.css)
-    content/browser/devtools/profiler/cleopatra/css/tree.css            (profiler/cleopatra/css/tree.css)
-    content/browser/devtools/profiler/cleopatra/css/devtools.css        (profiler/cleopatra/css/devtools.css)
-    content/browser/devtools/profiler/cleopatra/js/strings.js           (profiler/cleopatra/js/strings.js)
-    content/browser/devtools/profiler/cleopatra/js/parser.js            (profiler/cleopatra/js/parser.js)
-    content/browser/devtools/profiler/cleopatra/js/parserWorker.js      (profiler/cleopatra/js/parserWorker.js)
-    content/browser/devtools/profiler/cleopatra/js/tree.js              (profiler/cleopatra/js/tree.js)
-    content/browser/devtools/profiler/cleopatra/js/ui.js                (profiler/cleopatra/js/ui.js)
-    content/browser/devtools/profiler/cleopatra/js/ProgressReporter.js  (profiler/cleopatra/js/ProgressReporter.js)
-    content/browser/devtools/profiler/cleopatra/js/devtools.js          (profiler/cleopatra/js/devtools.js)
-    content/browser/devtools/profiler/cleopatra/images/circlearrow.svg  (profiler/cleopatra/images/circlearrow.svg)
-    content/browser/devtools/profiler/cleopatra/images/noise.png        (profiler/cleopatra/images/noise.png)
-    content/browser/devtools/profiler/cleopatra/images/throbber.svg     (profiler/cleopatra/images/throbber.svg)
-    content/browser/devtools/profiler/cleopatra/images/treetwisty.svg   (profiler/cleopatra/images/treetwisty.svg)
-    content/browser/devtools/commandline.css      (commandline/commandline.css)
-    content/browser/devtools/commandlineoutput.xhtml  (commandline/commandlineoutput.xhtml)
-    content/browser/devtools/commandlinetooltip.xhtml  (commandline/commandlinetooltip.xhtml)
-    content/browser/devtools/framework/toolbox-window.xul    (framework/toolbox-window.xul)
-    content/browser/devtools/framework/toolbox-options.xul   (framework/toolbox-options.xul)
-    content/browser/devtools/framework/toolbox-options.js    (framework/toolbox-options.js)
-*   content/browser/devtools/framework/toolbox.xul           (framework/toolbox.xul)
-    content/browser/devtools/framework/toolbox.css           (framework/toolbox.css)
-    content/browser/devtools/inspector/inspector.xul         (inspector/inspector.xul)
-    content/browser/devtools/inspector/inspector.css         (inspector/inspector.css)
-    content/browser/devtools/connect.xhtml  (framework/connect/connect.xhtml)
-    content/browser/devtools/connect.css    (framework/connect/connect.css)
-    content/browser/devtools/connect.js     (framework/connect/connect.js)
+    content/browser/devtools/widgets.css                               (shared/widgets/widgets.css)
+    content/browser/devtools/widgets/VariablesView.xul                 (shared/widgets/VariablesView.xul)
+    content/browser/devtools/markup-view.xhtml                         (markupview/markup-view.xhtml)
+    content/browser/devtools/markup-view.css                           (markupview/markup-view.css)
+    content/browser/devtools/netmonitor.xul                            (netmonitor/netmonitor.xul)
+    content/browser/devtools/netmonitor.css                            (netmonitor/netmonitor.css)
+    content/browser/devtools/netmonitor-controller.js                  (netmonitor/netmonitor-controller.js)
+    content/browser/devtools/netmonitor-view.js                        (netmonitor/netmonitor-view.js)
+    content/browser/devtools/NetworkPanel.xhtml                        (webconsole/NetworkPanel.xhtml)
+    content/browser/devtools/webconsole.js                             (webconsole/webconsole.js)
+    content/browser/devtools/webconsole.xul                            (webconsole/webconsole.xul)
+*   content/browser/devtools/scratchpad.xul                            (scratchpad/scratchpad.xul)
+    content/browser/devtools/scratchpad.js                             (scratchpad/scratchpad.js)
+    content/browser/devtools/splitview.css                             (shared/splitview.css)
+    content/browser/devtools/theme-switching.js                        (shared/theme-switching.js)
+    content/browser/devtools/styleeditor.xul                           (styleeditor/styleeditor.xul)
+    content/browser/devtools/styleeditor.css                           (styleeditor/styleeditor.css)
+    content/browser/devtools/computedview.xhtml                        (styleinspector/computedview.xhtml)
+    content/browser/devtools/cssruleview.xhtml                         (styleinspector/cssruleview.xhtml)
+    content/browser/devtools/ruleview.css                              (styleinspector/ruleview.css)
+    content/browser/devtools/layoutview/view.js                        (layoutview/view.js)
+    content/browser/devtools/layoutview/view.xhtml                     (layoutview/view.xhtml)
+    content/browser/devtools/layoutview/view.css                       (layoutview/view.css)
+    content/browser/devtools/fontinspector/font-inspector.js           (fontinspector/font-inspector.js)
+    content/browser/devtools/fontinspector/font-inspector.xhtml        (fontinspector/font-inspector.xhtml)
+    content/browser/devtools/fontinspector/font-inspector.css          (fontinspector/font-inspector.css)
+    content/browser/devtools/orion.js                                  (sourceeditor/orion/orion.js)
+*   content/browser/devtools/source-editor-overlay.xul                 (sourceeditor/source-editor-overlay.xul)
+    content/browser/devtools/debugger.xul                              (debugger/debugger.xul)
+    content/browser/devtools/debugger.css                              (debugger/debugger.css)
+    content/browser/devtools/debugger-controller.js                    (debugger/debugger-controller.js)
+    content/browser/devtools/debugger-view.js                          (debugger/debugger-view.js)
+    content/browser/devtools/debugger-toolbar.js                       (debugger/debugger-toolbar.js)
+    content/browser/devtools/debugger-panes.js                         (debugger/debugger-panes.js)
+    content/browser/devtools/profiler.xul                              (profiler/profiler.xul)
+    content/browser/devtools/cleopatra.html                            (profiler/cleopatra/cleopatra.html)
+    content/browser/devtools/profiler/cleopatra/css/ui.css             (profiler/cleopatra/css/ui.css)
+    content/browser/devtools/profiler/cleopatra/css/tree.css           (profiler/cleopatra/css/tree.css)
+    content/browser/devtools/profiler/cleopatra/css/devtools.css       (profiler/cleopatra/css/devtools.css)
+    content/browser/devtools/profiler/cleopatra/js/strings.js          (profiler/cleopatra/js/strings.js)
+    content/browser/devtools/profiler/cleopatra/js/parser.js           (profiler/cleopatra/js/parser.js)
+    content/browser/devtools/profiler/cleopatra/js/parserWorker.js     (profiler/cleopatra/js/parserWorker.js)
+    content/browser/devtools/profiler/cleopatra/js/tree.js             (profiler/cleopatra/js/tree.js)
+    content/browser/devtools/profiler/cleopatra/js/ui.js               (profiler/cleopatra/js/ui.js)
+    content/browser/devtools/profiler/cleopatra/js/ProgressReporter.js (profiler/cleopatra/js/ProgressReporter.js)
+    content/browser/devtools/profiler/cleopatra/js/devtools.js         (profiler/cleopatra/js/devtools.js)
+    content/browser/devtools/profiler/cleopatra/images/circlearrow.svg (profiler/cleopatra/images/circlearrow.svg)
+    content/browser/devtools/profiler/cleopatra/images/noise.png       (profiler/cleopatra/images/noise.png)
+    content/browser/devtools/profiler/cleopatra/images/throbber.svg    (profiler/cleopatra/images/throbber.svg)
+    content/browser/devtools/profiler/cleopatra/images/treetwisty.svg  (profiler/cleopatra/images/treetwisty.svg)
+    content/browser/devtools/commandline.css                           (commandline/commandline.css)
+    content/browser/devtools/commandlineoutput.xhtml                   (commandline/commandlineoutput.xhtml)
+    content/browser/devtools/commandlinetooltip.xhtml                  (commandline/commandlinetooltip.xhtml)
+    content/browser/devtools/framework/toolbox-window.xul              (framework/toolbox-window.xul)
+    content/browser/devtools/framework/toolbox-options.xul             (framework/toolbox-options.xul)
+    content/browser/devtools/framework/toolbox-options.js              (framework/toolbox-options.js)
+*   content/browser/devtools/framework/toolbox.xul                     (framework/toolbox.xul)
+    content/browser/devtools/framework/toolbox.css                     (framework/toolbox.css)
+    content/browser/devtools/inspector/inspector.xul                   (inspector/inspector.xul)
+    content/browser/devtools/inspector/inspector.css                   (inspector/inspector.css)
+    content/browser/devtools/connect.xhtml                             (framework/connect/connect.xhtml)
+    content/browser/devtools/connect.css                               (framework/connect/connect.css)
+    content/browser/devtools/connect.js                                (framework/connect/connect.js)
--- a/browser/devtools/main.js
+++ b/browser/devtools/main.js
@@ -77,17 +77,17 @@ Tools.webConsole = {
 Tools.jsdebugger = {
   id: "jsdebugger",
   key: l10n("open.commandkey", debuggerStrings),
   accesskey: l10n("debuggerMenu.accesskey", debuggerStrings),
   modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
   ordinal: 2,
   killswitch: "devtools.debugger.enabled",
   icon: "chrome://browser/skin/devtools/tool-debugger.png",
-  url: "chrome://browser/content/debugger.xul",
+  url: "chrome://browser/content/devtools/debugger.xul",
   label: l10n("ToolboxDebugger.label", debuggerStrings),
   tooltip: l10n("ToolboxDebugger.tooltip", debuggerStrings),
 
   isTargetSupported: function(target) {
     return true;
   },
 
   build: function(iframeWindow, toolbox) {
@@ -119,17 +119,17 @@ Tools.inspector = {
 
 Tools.styleEditor = {
   id: "styleeditor",
   key: l10n("open.commandkey", styleEditorStrings),
   ordinal: 3,
   accesskey: l10n("open.accesskey", styleEditorStrings),
   modifiers: "shift",
   icon: "chrome://browser/skin/devtools/tool-styleeditor.png",
-  url: "chrome://browser/content/styleeditor.xul",
+  url: "chrome://browser/content/devtools/styleeditor.xul",
   label: l10n("ToolboxStyleEditor.label", styleEditorStrings),
   tooltip: l10n("ToolboxStyleEditor.tooltip", styleEditorStrings),
 
   isTargetSupported: function(target) {
     return true;
   },
 
   build: function(iframeWindow, toolbox) {
@@ -141,17 +141,17 @@ Tools.styleEditor = {
 Tools.jsprofiler = {
   id: "jsprofiler",
   accesskey: l10n("profiler.accesskey", profilerStrings),
   key: l10n("profiler2.commandkey", profilerStrings),
   ordinal: 4,
   modifiers: "shift",
   killswitch: "devtools.profiler.enabled",
   icon: "chrome://browser/skin/devtools/tool-profiler.png",
-  url: "chrome://browser/content/profiler.xul",
+  url: "chrome://browser/content/devtools/profiler.xul",
   label: l10n("profiler.label", profilerStrings),
   tooltip: l10n("profiler.tooltip", profilerStrings),
 
   isTargetSupported: function (target) {
     return true;
   },
 
   build: function (frame, target) {
--- a/browser/devtools/profiler/ProfilerPanel.jsm
+++ b/browser/devtools/profiler/ProfilerPanel.jsm
@@ -56,17 +56,17 @@ function ProfileUI(uid, name, panel) {
 
   this.panel = panel;
   this.uid = uid;
   this.name = name;
 
   this.iframe = doc.createElement("iframe");
   this.iframe.setAttribute("flex", "1");
   this.iframe.setAttribute("id", "profiler-cleo-" + uid);
-  this.iframe.setAttribute("src", "devtools/cleopatra.html?" + uid);
+  this.iframe.setAttribute("src", "cleopatra.html?" + uid);
   this.iframe.setAttribute("hidden", "true");
 
   // Append our iframe and subscribe to postMessage events.
   // They'll tell us when the underlying page is done loading
   // or when user clicks on start/stop buttons.
 
   doc.getElementById("profiler-report").appendChild(this.iframe);
   win.addEventListener("message", function (event) {
--- a/browser/devtools/profiler/profiler.xul
+++ b/browser/devtools/profiler/profiler.xul
@@ -3,17 +3,17 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <?xml-stylesheet href="chrome://global/skin/global.css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/common.css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/splitview.css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/profiler.css"?>
-<?xml-stylesheet href="chrome://browser/content/splitview.css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/splitview.css"?>
 
 <!DOCTYPE window [
 <!ENTITY % profilerDTD SYSTEM "chrome://browser/locale/devtools/profiler.dtd">
   %profilerDTD;
 ]>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <box flex="1" id="profiler-chrome" class="splitview-root">
--- a/browser/devtools/scratchpad/scratchpad-manager.jsm
+++ b/browser/devtools/scratchpad/scratchpad-manager.jsm
@@ -6,17 +6,17 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["ScratchpadManager"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
-const SCRATCHPAD_WINDOW_URL = "chrome://browser/content/scratchpad.xul";
+const SCRATCHPAD_WINDOW_URL = "chrome://browser/content/devtools/scratchpad.xul";
 const SCRATCHPAD_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 /**
  * The ScratchpadManager object opens new Scratchpad windows and manages the state
  * of open scratchpads for session restore. There's only one ScratchpadManager in
  * the life of the browser.
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -25,25 +25,33 @@ Cu.import("resource:///modules/PropertyP
 Cu.import("resource:///modules/source-editor.jsm");
 Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
 Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
 Cu.import("resource://gre/modules/jsdebugger.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
 
+XPCOMUtils.defineLazyModuleGetter(this, "VariablesView",
+                                  "resource:///modules/devtools/VariablesView.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "devtools",
+                                  "resource:///modules/devtools/gDevTools.jsm");
+
 const SCRATCHPAD_CONTEXT_CONTENT = 1;
 const SCRATCHPAD_CONTEXT_BROWSER = 2;
 const SCRATCHPAD_L10N = "chrome://browser/locale/devtools/scratchpad.properties";
 const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
 const PREF_RECENT_FILES_MAX = "devtools.scratchpad.recentFilesMax";
 const BUTTON_POSITION_SAVE = 0;
 const BUTTON_POSITION_CANCEL = 1;
 const BUTTON_POSITION_DONT_SAVE = 2;
-const BUTTON_POSITION_REVERT=0;
+const BUTTON_POSITION_REVERT = 0;
+const VARIABLES_VIEW_URL = "chrome://browser/content/devtools/widgets/VariablesView.xul";
+
 
 /**
  * The scratchpad object handles the Scratchpad window functionality.
  */
 var Scratchpad = {
   _instanceId: null,
   _initialWindowTitle: document.title,
 
@@ -248,16 +256,28 @@ var Scratchpad = {
    * Unique name for the current Scratchpad instance. Used to distinguish
    * Scratchpad windows between each other. See bug 661762.
    */
   get uniqueName()
   {
     return "Scratchpad/" + this._instanceId;
   },
 
+
+  /**
+   * Sidebar that contains the VariablesView for object inspection.
+   */
+  get sidebar()
+  {
+    if (!this._sidebar) {
+      this._sidebar = new ScratchpadSidebar();
+    }
+    return this._sidebar;
+  },
+
   /**
    * Get the Cu.Sandbox object for the active tab content window object. Note
    * that the returned object is cached for later reuse. The cached object is
    * kept only for the current location in the current tab of the current
    * browser window and it is reset for each context switch,
    * navigator:browser window switch, tab switch or navigation.
    */
   get contentSandbox()
@@ -418,35 +438,45 @@ var Scratchpad = {
         this.deselect();
       }
     });
     return promise;
   },
 
   /**
    * Execute the selected text (if any) or the entire editor content in the
-   * current context. The resulting object is opened up in the Property Panel
-   * for inspection.
+   * current context. If the result is primitive then it is written as a
+   * comment. Otherwise, the resulting object is inspected up in the sidebar.
    *
    * @return Promise
    *         The promise for the script evaluation result.
    */
   inspect: function SP_inspect()
   {
-    let promise = this.execute();
-    promise.then(([aString, aError, aResult]) => {
+    let deferred = Promise.defer();
+    let reject = aReason => deferred.reject(aReason);
+
+    this.execute().then(([aString, aError, aResult]) => {
+      let resolve = () => deferred.resolve([aString, aError, aResult]);
+
       if (aError) {
         this.writeAsErrorComment(aError);
+        resolve();
+      }
+      else if (!isObject(aResult)) {
+        this.writeAsComment(aResult);
+        resolve();
       }
       else {
         this.deselect();
-        this.openPropertyPanel(aString, aResult);
+        this.sidebar.open(aString, aResult).then(resolve, reject);
       }
-    });
-    return promise;
+    }, reject);
+    
+    return deferred.promise;
   },
 
   /**
    * Reload the current page and execute the entire editor content when
    * the page finishes loading. Note that this operation should be available
    * only in the content context.
    *
    * @return Promise
@@ -547,68 +577,16 @@ var Scratchpad = {
       stack = "@" + aError.lineNumber;
     }
 
     let newComment = "Exception: " + ( aError.message || aError) + ( stack == "" ? stack : "\n" + stack.replace(/\n$/, "") );
 
     this.writeAsComment(newComment);
   },
 
-  /**
-   * Open the Property Panel to inspect the given object.
-   *
-   * @param string aEvalString
-   *        The string that was evaluated. This is re-used when the user updates
-   *        the properties list, by clicking the Update button.
-   * @param object aOutputObject
-   *        The object to inspect, which is the aEvalString evaluation result.
-   * @return object
-   *         The PropertyPanel object instance.
-   */
-  openPropertyPanel: function SP_openPropertyPanel(aEvalString, aOutputObject)
-  {
-    let propPanel;
-    // The property panel has a button:
-    // `Update`: reexecutes the string executed on the command line. The
-    // result will be inspected by this panel.
-    let buttons = [];
-
-    // If there is a evalString passed to this function, then add a `Update`
-    // button to the panel so that the evalString can be reexecuted to update
-    // the content of the panel.
-    if (aEvalString !== null) {
-      buttons.push({
-        label: this.strings.
-               GetStringFromName("propertyPanel.updateButton.label"),
-        accesskey: this.strings.
-                   GetStringFromName("propertyPanel.updateButton.accesskey"),
-        oncommand: () => {
-          this.evalForContext(aEvalString).then(([, aError, aResult]) => {
-            if (!aError) {
-              propPanel.treeView.data = { object: aResult };
-            }
-          });
-        }
-      });
-    }
-
-    let doc = this.browserWindow.document;
-    let parent = doc.getElementById("mainPopupSet");
-    let title = String(aOutputObject);
-    propPanel = new PropertyPanel(parent, title, { object: aOutputObject },
-                                  buttons);
-
-    let panel = propPanel.panel;
-    panel.setAttribute("class", "scratchpad_propertyPanel");
-    panel.openPopup(null, "after_pointer", 0, 0, false, false);
-    panel.sizeTo(200, 400);
-
-    return propPanel;
-  },
-
   // Menu Operations
 
   /**
    * Open a new Scratchpad window.
    *
    * @return nsIWindow
    */
   openScratchpad: function SP_openScratchpad()
@@ -1490,16 +1468,142 @@ var Scratchpad = {
   {
     let url = this.strings.GetStringFromName("help.openDocumentationPage");
     let newTab = this.gBrowser.addTab(url);
     this.browserWindow.focus();
     this.gBrowser.selectedTab = newTab;
   },
 };
 
+
+/**
+ * Encapsulates management of the sidebar containing the VariablesView for
+ * object inspection.
+ */
+function ScratchpadSidebar()
+{
+  let ToolSidebar = devtools.require("devtools/framework/sidebar").ToolSidebar;
+  let tabbox = document.querySelector("#scratchpad-sidebar");
+  this._sidebar = new ToolSidebar(tabbox, this);
+  this._splitter = document.querySelector(".devtools-side-splitter");
+}
+
+ScratchpadSidebar.prototype = {
+  /*
+   * The ToolSidebar for this sidebar.
+   */
+  _sidebar: null,
+
+  /*
+   * The splitter element between the sidebar and the editor.
+   */
+  _splitter: null,
+
+  /*
+   * The VariablesView for this sidebar.
+   */
+  variablesView: null,
+
+  /*
+   * Whether the sidebar is currently shown.
+   */
+  visible: false,
+
+  /**
+   * Open the sidebar, if not open already, and populate it with the properties
+   * of the given object.
+   *
+   * @param string aString
+   *        The string that was evaluated.
+   * @param object aObject
+   *        The object to inspect, which is the aEvalString evaluation result.
+   * @return Promise
+   *         A promise that will resolve once the sidebar is open.
+   */
+  open: function SS_open(aEvalString, aObject)
+  {
+    this.show();
+
+    let deferred = Promise.defer();
+
+    let onTabReady = () => {
+      if (!this.variablesView) {
+        let window = this._sidebar.getWindowForTab("variablesview");
+        let container = window.document.querySelector("#variables");
+        this.variablesView = new VariablesView(container);
+      }
+      this._update(aObject).then(() => deferred.resolve());
+    };
+
+    if (this._sidebar.getCurrentTabID() == "variablesview") {
+      onTabReady();
+    }
+    else {
+      this._sidebar.once("variablesview-ready", onTabReady);
+      this._sidebar.addTab("variablesview", VARIABLES_VIEW_URL, true);
+    }
+
+    return deferred.promise;
+  },
+
+  /**
+   * Show the sidebar.
+   */
+  show: function SS_show()
+  {
+    if (!this.visible) {
+      this.visible = true;
+      this._sidebar.show();
+      this._splitter.setAttribute("state", "open");
+    }
+  },
+
+  /**
+   * Hide the sidebar.
+   */
+  hide: function SS_hide()
+  {
+    if (this.visible) {
+      this.visible = false;
+      this._sidebar.hide();
+      this._splitter.setAttribute("state", "collapsed");
+    }
+  },
+
+  /**
+   * Update the object currently inspected by the sidebar.
+   *
+   * @param object aObject
+   *        The object to inspect in the sidebar.
+   * @return Promise
+   *         A promise that resolves when the update completes.
+   */
+  _update: function SS__update(aObject)
+  {
+    let deferred = Promise.defer();
+
+    this.variablesView.rawObject = aObject;
+
+    // In the future this will work on remote values (bug 825039).
+    setTimeout(() => deferred.resolve(), 0);
+    return deferred.promise;
+  }
+};
+
+
+/**
+ * Check whether a value is non-primitive.
+ */
+function isObject(aValue)
+{
+  let type = typeof aValue;
+  return type == "object" ? aValue != null : type == "function";
+}
+
+
 /**
  * The PreferenceObserver listens for preference changes while Scratchpad is
  * running.
  */
 var PreferenceObserver = {
   _initialized: false,
 
   init: function PO_init()
--- a/browser/devtools/scratchpad/scratchpad.xul
+++ b/browser/devtools/scratchpad/scratchpad.xul
@@ -3,32 +3,34 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 #endif
 <!DOCTYPE window [
 <!ENTITY % scratchpadDTD SYSTEM "chrome://browser/locale/devtools/scratchpad.dtd" >
  %scratchpadDTD;
 ]>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://global/skin/global.css"?>
+<?xml-stylesheet href="chrome://browser/skin/devtools/common.css"?>
+<?xml-stylesheet href="chrome://browser/skin/devtools/scratchpad.css"?>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
-<?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
+<?xul-overlay href="chrome://browser/content/devtools/source-editor-overlay.xul"?>
 
 <window id="main-window"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         title="&window.title;"
         windowtype="devtools:scratchpad"
         macanimationtype="document"
         fullscreenbutton="true"
         screenX="4" screenY="4"
         width="640" height="480"
         persist="screenX screenY width height sizemode">
 
 <script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
-<script type="application/javascript" src="chrome://browser/content/scratchpad.js"/>
+<script type="application/javascript" src="chrome://browser/content/devtools/scratchpad.js"/>
 
 <commandset id="editMenuCommands"/>
 <commandset id="sourceEditorCommands"/>
 
 <commandset id="sp-commandset">
   <command id="sp-cmd-newWindow" oncommand="Scratchpad.openScratchpad();"/>
   <command id="sp-cmd-openFile" oncommand="Scratchpad.openFile();"/>
   <command id="sp-cmd-clearRecentFiles" oncommand="Scratchpad.clearRecentFiles();"/>
@@ -275,12 +277,21 @@
     <menuitem id="sp-text-resetContext"
               label="&resetContext2.label;"
               accesskey="&resetContext2.accesskey;"
               command="sp-cmd-resetContext"/>
   </menupopup>
 </popupset>
 
 <notificationbox id="scratchpad-notificationbox" flex="1">
-  <hbox id="scratchpad-editor" flex="1"/>
+  <hbox flex="1">
+    <vbox id="scratchpad-editor" flex="1"/>
+    <splitter class="devtools-side-splitter"
+              collapse="after"
+              state="collapsed"/>
+    <tabbox id="scratchpad-sidebar" class="devtools-sidebar-tabs" width="300">
+      <tabs/>
+      <tabpanels flex="1"/>
+    </tabbox>
+  </hbox>
 </notificationbox>
 
 </window>
--- a/browser/devtools/scratchpad/test/browser_scratchpad_inspect.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_inspect.js
@@ -7,52 +7,40 @@ function test()
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
     gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
     openScratchpad(runTests);
   }, true);
 
-  content.location = "data:text/html,<title>foobarBug636725</title>" +
-    "<p>test inspect() in Scratchpad";
+  content.location = "data:text/html;charset=utf8,<p>test inspect() in Scratchpad</p>";
 }
 
 function runTests()
 {
   let sp = gScratchpadWindow.Scratchpad;
 
-  sp.setText("document");
+  sp.setText("({ a: 'foobarBug636725' })");
 
   sp.inspect().then(function() {
+    let sidebar = sp.sidebar;
+    ok(sidebar.visible, "sidebar is open");
 
-    let propPanel = document.querySelector(".scratchpad_propertyPanel");
-    ok(propPanel, "property panel is open");
 
-    propPanel.addEventListener("popupshown", function onPopupShown() {
-      propPanel.removeEventListener("popupshown", onPopupShown, false);
+    let found = false;
 
-      let tree = propPanel.querySelector("tree");
-      ok(tree, "property panel tree found");
-
-      let column = tree.columns[0];
-      let found = false;
-
-      for (let i = 0; i < tree.view.rowCount; i++) {
-        let cell = tree.view.getCellText(i, column);
-        if (cell == 'title: "foobarBug636725"') {
-          found = true;
-          break;
+    outer: for (let scope in sidebar.variablesView) {
+      for (let [, obj] in scope) {
+        for (let [, prop] in obj) {
+          if (prop.name == "a" && prop.value == "foobarBug636725") {
+            found = true;
+            break outer;
+          }
         }
       }
-      ok(found, "found the document.title property");
-
-      executeSoon(function() {
-        propPanel.hidePopup();
+    }
 
-        finish();
-      });
-    }, false);
-  }, function() {
-    notok(true, "document not found");
+    ok(found, "found the property");
+
     finish();
   });
-}
+}
\ No newline at end of file
--- a/browser/devtools/sourceeditor/source-editor-orion.jsm
+++ b/browser/devtools/sourceeditor/source-editor-orion.jsm
@@ -11,17 +11,17 @@ const Ci = Components.interfaces;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/source-editor-ui.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
                                    "@mozilla.org/widget/clipboardhelper;1",
                                    "nsIClipboardHelper");
 
-const ORION_SCRIPT = "chrome://browser/content/orion.js";
+const ORION_SCRIPT = "chrome://browser/content/devtools/orion.js";
 const ORION_IFRAME = "data:text/html;charset=utf8,<!DOCTYPE html>" +
   "<html style='height:100%' dir='ltr'>" +
   "<head><link rel='stylesheet'" +
   " href='chrome://browser/skin/devtools/orion-container.css'></head>" +
   "<body style='height:100%;margin:0;overflow:hidden'>" +
   "<div id='editor' style='height:100%'></div>" +
   "</body></html>";
 
--- a/browser/devtools/styleeditor/styleeditor.xul
+++ b/browser/devtools/styleeditor/styleeditor.xul
@@ -2,23 +2,23 @@
 <!-- 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/. -->
 <!DOCTYPE window [
 <!ENTITY % styleEditorDTD SYSTEM "chrome://browser/locale/devtools/styleeditor.dtd" >
  %styleEditorDTD;
 ]>
 <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/content/splitview.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/splitview.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/splitview.css" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/content/styleeditor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/styleeditor.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/styleeditor.css" type="text/css"?>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
-<?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
+<?xul-overlay href="chrome://browser/content/devtools/source-editor-overlay.xul"?>
 <xul:window xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns="http://www.w3.org/1999/xhtml"
         id="style-editor-chrome-window">
 
   <xul:script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
 
   <xul:popupset id="style-editor-popups">
     <xul:menupopup id="sourceEditorContextMenu"
--- a/browser/devtools/styleeditor/test/Makefile.in
+++ b/browser/devtools/styleeditor/test/Makefile.in
@@ -20,16 +20,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_styleeditor_import_rule.js \
                  browser_styleeditor_init.js \
                  browser_styleeditor_loading.js \
                  browser_styleeditor_new.js \
                  browser_styleeditor_pretty.js \
                  browser_styleeditor_private_perwindowpb.js \
                  browser_styleeditor_sv_keynav.js \
                  browser_styleeditor_sv_resize.js \
+                 browser_styleeditor_bug_740541_iframes.js \
                  browser_styleeditor_bug_851132_middle_click.js \
                  head.js \
                  helpers.js \
                  four.html \
                  head.js \
                  helpers.js \
                  import.css \
                  import.html \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_bug_740541_iframes.js
@@ -0,0 +1,90 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test()
+{
+
+  function makeStylesheet(selector) {
+    return ("data:text/css;charset=UTF-8," +
+            encodeURIComponent(selector + " { }"));
+  }
+
+  function makeDocument(stylesheets, framedDocuments) {
+    stylesheets = stylesheets || [];
+    framedDocuments = framedDocuments || [];
+    return "data:text/html;charset=UTF-8," + encodeURIComponent(
+      Array.prototype.concat.call(
+        ["<!DOCTYPE html>",
+         "<html>",
+         "<head>",
+         "<title>Bug 740541</title>"],
+        stylesheets.map(function (sheet) {
+          return '<link rel="stylesheet" type="text/css" href="'+sheet+'">';
+        }),
+        ["</head>",
+         "<body>"],
+        framedDocuments.map(function (doc) {
+          return '<iframe src="'+doc+'"></iframe>';
+        }),
+        ["</body>",
+         "</html>"]
+      ).join("\n"));
+  }
+
+  const DOCUMENT_WITH_INLINE_STYLE = "data:text/html;charset=UTF-8," +
+          encodeURIComponent(
+            ["<!DOCTYPE html>",
+             "<html>",
+             " <head>",
+             "  <title>Bug 740541</title>",
+             '  <style type="text/css">',
+             "    .something {",
+             "    }",
+             "  </style>",
+             " </head>",
+             " <body>",
+             " </body>",
+             " </html>"
+            ].join("\n"));
+
+  const FOUR = TEST_BASE_HTTP + "four.html";
+
+  const SIMPLE = TEST_BASE_HTTP + "simple.css";
+
+  const SIMPLE_DOCUMENT = TEST_BASE_HTTP + "simple.html";
+
+
+  const TESTCASE_URI = makeDocument(
+    [makeStylesheet(".a")],
+    [makeDocument([],
+                  [FOUR,
+                   DOCUMENT_WITH_INLINE_STYLE]),
+     makeDocument([makeStylesheet(".b"),
+                   SIMPLE],
+                  [makeDocument([makeStylesheet(".c")],
+                                [])]),
+     makeDocument([SIMPLE], []),
+     SIMPLE_DOCUMENT
+    ]);
+
+  const EXPECTED_STYLE_SHEET_COUNT = 12;
+
+  waitForExplicitFinish();
+  let styleSheetCount = 0;
+  addTabAndOpenStyleEditor(function (aPanel) {
+    aPanel.UI.on("editor-added", function () {
+      ++styleSheetCount;
+      info(styleSheetCount+" out of "+
+           EXPECTED_STYLE_SHEET_COUNT+" style sheets loaded");
+      if (styleSheetCount == EXPECTED_STYLE_SHEET_COUNT) {
+        ok(true, "all style sheets loaded");
+        // The right number of events have been received; check that
+        // they actually show up in the style editor UI.
+        is(aPanel.UI.editors.length, EXPECTED_STYLE_SHEET_COUNT,
+           "UI elements present");
+        finish();
+      }
+    });
+  });
+  content.location = TESTCASE_URI;
+}
--- a/browser/devtools/webconsole/NetworkPanel.jsm
+++ b/browser/devtools/webconsole/NetworkPanel.jsm
@@ -57,17 +57,17 @@ function NetworkPanel(aParent, aHttpActi
     titlebar: "normal",
     noautofocus: "true",
     noautohide: "true",
     close: "true"
   });
 
   // Create the iframe that displays the NetworkPanel XHTML.
   this.iframe = createAndAppendElement(this.panel, "iframe", {
-    src: "chrome://browser/content/NetworkPanel.xhtml",
+    src: "chrome://browser/content/devtools/NetworkPanel.xhtml",
     type: "content",
     flex: "1"
   });
 
   let self = this;
 
   // Destroy the panel when it's closed.
   this.panel.addEventListener("popuphidden", function onPopupHide() {
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -3478,17 +3478,17 @@ JSTerm.prototype = {
         if (setter) {
           setter.evaluationMacro = this._variablesViewGetterOrSetterEvalMacro;
         }
       }
       else {
         aProperty.evaluationMacro = this._variablesViewSimpleValueEvalMacro;
       }
 
-      let grips = [aProperty.value, aProperty.gettter, aProperty.settter];
+      let grips = [aProperty.value, aProperty.getter, aProperty.setter];
       grips.forEach(addActorForDescriptor);
 
       let inspectable = !VariablesView.isPrimitive({ value: aProperty.value });
       let longString = WebConsoleUtils.isActorGrip(aProperty.value) &&
                        aProperty.value.type == "longString";
       if (inspectable) {
         aProperty.onexpand = this._fetchVarProperties;
       }
--- a/browser/installer/windows/nsis/shared.nsh
+++ b/browser/installer/windows/nsis/shared.nsh
@@ -465,17 +465,17 @@ FunctionEnd
   ${If} ${Errors}
     ${If} ${FileExists} "$QUICKLAUNCH\${BrandFullName}.lnk"
       WriteRegDWORD ${RegKey} "$0\InstallInfo" "IconsVisible" 1
     ${Else}
       WriteRegDWORD ${RegKey} "$0\InstallInfo" "IconsVisible" 0
     ${EndIf}
   ${EndIf}
 
-  WriteRegStr ${RegKey} "$0\shell\open\command" "" "$8"
+  WriteRegStr ${RegKey} "$0\shell\open\command" "" "$\"$8$\""
 
   WriteRegStr ${RegKey} "$0\shell\properties" "" "$(CONTEXT_OPTIONS)"
   WriteRegStr ${RegKey} "$0\shell\properties\command" "" "$\"$8$\" -preferences"
 
   WriteRegStr ${RegKey} "$0\shell\safemode" "" "$(CONTEXT_SAFE_MODE)"
   WriteRegStr ${RegKey} "$0\shell\safemode\command" "" "$\"$8$\" -safe-mode"
 
   ; Vista Capabilities registry keys
@@ -577,17 +577,17 @@ FunctionEnd
 
     ; Write the uninstall registry keys
     ${WriteRegStr2} $1 "$0" "Comments" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0
     ${WriteRegStr2} $1 "$0" "DisplayIcon" "$8\${FileMainEXE},0" 0
     ${WriteRegStr2} $1 "$0" "DisplayName" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0
     ${WriteRegStr2} $1 "$0" "DisplayVersion" "${AppVersion}" 0
     ${WriteRegStr2} $1 "$0" "InstallLocation" "$8" 0
     ${WriteRegStr2} $1 "$0" "Publisher" "Mozilla" 0
-    ${WriteRegStr2} $1 "$0" "UninstallString" "$8\uninstall\helper.exe" 0
+    ${WriteRegStr2} $1 "$0" "UninstallString" "$\"$8\uninstall\helper.exe$\"" 0
     ${WriteRegStr2} $1 "$0" "URLInfoAbout" "${URLInfoAbout}" 0
     ${WriteRegStr2} $1 "$0" "URLUpdateInfo" "${URLUpdateInfo}" 0
     ${WriteRegDWORD2} $1 "$0" "NoModify" 1 0
     ${WriteRegDWORD2} $1 "$0" "NoRepair" 1 0
 
     ${GetSize} "$8" "/S=0K" $R2 $R3 $R4
     ${WriteRegDWORD2} $1 "$0" "EstimatedSize" $R2 0
 
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -111,16 +111,27 @@ These should match what Safari and other
 <!ENTITY closeWindow.label "Close Window">
 <!ENTITY closeWindow.accesskey "d">
 
 <!ENTITY bookmarksMenu.label "Bookmarks">
 <!ENTITY bookmarksMenu.accesskey "B">
 <!ENTITY bookmarkThisPageCmd.label "Bookmark This Page">
 <!ENTITY bookmarkThisPageCmd.commandkey "d">
 <!ENTITY markPageCmd.commandkey "l">
+<!ENTITY sharePageCmd.label "Share This Page">
+<!ENTITY sharePageCmd.commandkey "S">
+<!ENTITY sharePageCmd.accesskey "s">
+<!ENTITY shareLinkCmd.label "Share This Link">
+<!ENTITY shareLinkCmd.accesskey "s">
+<!ENTITY shareImageCmd.label "Share This Image">
+<!ENTITY shareImageCmd.accesskey "s">
+<!ENTITY shareSelectCmd.label "Share Selection">
+<!ENTITY shareSelectCmd.accesskey "s">
+<!ENTITY shareVideoCmd.label "Share This Video">
+<!ENTITY shareVideoCmd.accesskey "s">
 <!ENTITY subscribeToPageMenupopup.label "Subscribe to This Page">
 <!ENTITY subscribeToPageMenuitem.label "Subscribe to This Page…">
 <!ENTITY addCurPagesCmd.label "Bookmark All Tabs…">
 <!ENTITY showAllBookmarks2.label "Show All Bookmarks">
 <!ENTITY unsortedBookmarksCmd.label "Unsorted Bookmarks">
 <!ENTITY bookmarksToolbarChevron.tooltip "Show more bookmarks">
 
 <!ENTITY backCmd.label                "Back">
--- a/browser/metro/base/content/RemoteTabs.js
+++ b/browser/metro/base/content/RemoteTabs.js
@@ -5,121 +5,118 @@
 
 'use strict';
 Components.utils.import("resource://services-sync/main.js");
 
 /**
  * Wraps a list/grid control implementing nsIDOMXULSelectControlElement and
  * fills it with the user's synced tabs.
  *
+ * Note, the Sync module takes care of initializing the sync service. We should
+ * not make calls that start sync or sync tabs since this module loads really
+ * early during startup.
+ *
  * @param    aSet         Control implementing nsIDOMXULSelectControlElement.
  * @param    aSetUIAccess The UI element that should be hidden when Sync is
  *                          disabled. Must sanely support 'hidden' attribute.
  *                          You may only have one UI access point at this time.
  */
-function RemoteTabsView(aSet, aSetUIAccess) {
+function RemoteTabsView(aSet, aSetUIAccessList) {
   this._set = aSet;
   this._set.controller = this;
-  this._uiAccessElement = aSetUIAccess;
+  this._uiAccessElements = aSetUIAccessList;
 
   // Sync uses special voodoo observers.
   // If you want to change this code, talk to the fx-si team
-  Weave.Svc.Obs.add("weave:service:setup-complete", this);
   Weave.Svc.Obs.add("weave:service:sync:finish", this);
   Weave.Svc.Obs.add("weave:service:start-over", this);
   if (this.isSyncEnabled() ) {
-    this.populateTabs();
     this.populateGrid();
-    this.setUIAccessVisible(true);
   }
   else {
     this.setUIAccessVisible(false);
   }
 }
 
 RemoteTabsView.prototype = {
   _set: null,
-  _uiAccessElement: null,
+  _uiAccessElements: [],
 
   handleItemClick: function tabview_handleItemClick(aItem) {
     let url = aItem.getAttribute("value");
     BrowserUI.goToURI(url);
   },
 
   observe: function(subject, topic, data) {
     switch (topic) {
-      case "weave:service:setup-complete":
-        this.populateTabs();
-        this.setUIAccessVisible(true);
-        break;
       case "weave:service:sync:finish":
         this.populateGrid();
         break;
       case "weave:service:start-over":
         this.setUIAccessVisible(false);
         break;
     }
   },
 
   setUIAccessVisible: function setUIAccessVisible(aVisible) {
-    this._uiAccessElement.hidden = !aVisible;
+    for (let elem of this._uiAccessElements) {
+      elem.hidden = !aVisible;
+    }
   },
 
   populateGrid: function populateGrid() {
 
     let tabsEngine = Weave.Service.engineManager.get("tabs");
     let list = this._set;
     let seenURLs = new Set();
 
     // Clear grid, We don't know what has happened to tabs since last sync
     // Also can result in duplicate tabs(bug 864614)
     this._set.clearAll();
-
+    let show = false;
     for (let [guid, client] in Iterator(tabsEngine.getAllClients())) {
       client.tabs.forEach(function({title, urlHistory, icon}) {
         let url = urlHistory[0];
         if (tabsEngine.locallyOpenTabMatchesURL(url) || seenURLs.has(url)) {
           return;
         }
         seenURLs.add(url);
+        show = true;
 
         // If we wish to group tabs by client, we should be looking for records
         //  of {type:client, clientName, class:{mobile, desktop}} and will
         //  need to readd logic to reset seenURLs for each client.
 
         let item = this._set.appendItem((title || url), url);
         item.setAttribute("iconURI", Weave.Utils.getIcon(icon));
 
       }, this);
     }
-  },
-
-  populateTabs: function populateTabs() {
-    Weave.Service.scheduler.scheduleNextSync(0);
+    this.setUIAccessVisible(show);
   },
 
   destruct: function destruct() {
-    Weave.Svc.Obs.remove("weave:service:setup-complete", this);
     Weave.Svc.Obs.remove("weave:engine:sync:finish", this);
     Weave.Svc.Obs.remove("weave:service:logout:start-over", this);
   },
 
   isSyncEnabled: function isSyncEnabled() {
     return (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED);
   }
 
 };
 
 let RemoteTabsStartView = {
   _view: null,
   get _grid() { return document.getElementById("start-remotetabs-grid"); },
 
   init: function init() {
     let vbox = document.getElementById("start-remotetabs");
-    this._view = new RemoteTabsView(this._grid, vbox);
+    let uiList = [vbox];
+    this._view = new RemoteTabsView(this._grid, uiList);
   },
 
   uninit: function uninit() {
     this._view.destruct();
   },
 
   show: function show() {
     this._grid.arrangeItems();
@@ -128,19 +125,21 @@ let RemoteTabsStartView = {
 
 let RemoteTabsPanelView = {
   _view: null,
 
   get _grid() { return document.getElementById("remotetabs-list"); },
   get visible() { return PanelUI.isPaneVisible("remotetabs-container"); },
 
   init: function init() {
-    //decks are fragile, don't hide the tab panel(bad things happen), hide link.
+    //decks are fragile, don't hide the tab panel(bad things happen), hide link in menu.
     let menuEntry = document.getElementById("menuitem-remotetabs");
-    this._view = new RemoteTabsView(this._grid, menuEntry);
+    let snappedEntry = document.getElementById("snappedRemoteTabsLabel");
+    let uiList = [menuEntry, snappedEntry];
+    this._view = new RemoteTabsView(this._grid, uiList);
   },
 
   show: function show() {
     this._grid.arrangeItems();
   },
 
   uninit: function uninit() {
     this._view.destruct();
--- a/browser/metro/base/content/TopSites.js
+++ b/browser/metro/base/content/TopSites.js
@@ -252,17 +252,16 @@ TopSitesView.prototype = {
       },0);
     }
   },
   handleEvent: function(aEvent) {
     switch (aEvent.type){
       case "MozAppbarDismissing":
         // clean up when the context appbar is dismissed - we don't remember selections
         this._lastSelectedSites = null;
-        this._set.clearSelection();
     }
   },
 
   update: function() {
     // called by the NewTabUtils.allPages.update, notifying us of data-change in topsites
     let grid = this._set,
         dirtySites = TopSites.dirty();
 
--- a/browser/metro/base/content/appbar.js
+++ b/browser/metro/base/content/appbar.js
@@ -1,23 +1,29 @@
+/* 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";
+
 var Appbar = {
   get appbar()        { return document.getElementById('appbar'); },
   get consoleButton() { return document.getElementById('console-button'); },
   get jsShellButton() { return document.getElementById('jsshell-button'); },
   get zoomInButton()  { return document.getElementById('zoomin-button'); },
   get zoomOutButton() { return document.getElementById('zoomout-button'); },
   get starButton()    { return document.getElementById('star-button'); },
   get pinButton()     { return document.getElementById('pin-button'); },
   get moreButton()    { return document.getElementById('more-button'); },
 
   // track selected/active richgrid/tilegroup - the context for contextual action buttons
   activeTileset: null,
 
   init: function Appbar_init() {
     window.addEventListener('MozAppbarShowing', this, false);
+    window.addEventListener('MozAppbarDismissing', this, false);
     window.addEventListener('MozPrecisePointer', this, false);
     window.addEventListener('MozImprecisePointer', this, false);
     window.addEventListener('MozContextActionsChange', this, false);
     Elements.browsers.addEventListener('URLChanged', this, true);
     Elements.tabList.addEventListener('TabSelect', this, true);
     Elements.panelUI.addEventListener('ToolPanelShown', this, false);
     Elements.panelUI.addEventListener('ToolPanelHidden', this, false);
 
@@ -35,16 +41,23 @@ var Appbar = {
       case 'ToolPanelShown':
       case 'ToolPanelHidden':
         this.appbar.dismiss();
         break;
       case 'MozAppbarShowing':
         this._updatePinButton();
         this._updateStarButton();
         break;
+      case 'MozAppbarDismissing':
+        if (this.activeTileset) {
+          this.activeTileset.clearSelection();
+        }
+        this.clearContextualActions();
+        this.activeTileset = null;
+        break;
       case 'MozPrecisePointer':
       case 'MozImprecisePointer':
         this._updateZoomButtons();
         break;
       case 'MozContextActionsChange':
         let actions = aEvent.actions;
         // could transition in old, new buttons?
         this.showContextualActions(actions);
@@ -157,17 +170,18 @@ var Appbar = {
       event.initEvent("context-action", true, true); // is cancelable
       activeTileset.dispatchEvent(event);
       if (!event.defaultPrevented) {
         activeTileset.clearSelection();
         this.appbar.dismiss();
       }
     }
   },
-  showContextualActions: function(aVerbs){
+
+  showContextualActions: function(aVerbs) {
     let doc = document;
     // button element id to action verb lookup
     let buttonsMap = new Map();
     for (let verb of aVerbs) {
       let id = verb + "-selected-button";
       if (!doc.getElementById(id)) {
         throw new Error("Appbar.showContextualActions: no button for " + verb);
       }
@@ -190,16 +204,21 @@ var Appbar = {
       if (toHide.length) {
         yield Util.transitionElementVisibility(toHide, false);
       }
       if (toShow.length) {
         yield Util.transitionElementVisibility(toShow, true);
       }
     });
   },
+
+  clearContextualActions: function() {
+    this.showContextualActions([]);
+  },
+
   _onTileSelectionChanged: function _onTileSelectionChanged(aEvent){
     let activeTileset = aEvent.target;
 
     // deselect tiles in other tile groups
     if (this.activeTileset && this.activeTileset !== activeTileset) {
       this.activeTileset.clearSelection();
     }
     // keep track of which view is the target/scope for the contextual actions
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/content/bindings/cssthrobber.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<bindings
+    xmlns="http://www.mozilla.org/xbl"
+    xmlns:xbl="http://www.mozilla.org/xbl"
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <binding id="cssthrobberBinding" extends="xul:box">
+    <content>
+      <html:div class="progressContainer">
+        <html:div class="progressBall" />
+        <html:div class="progressBall" />
+        <html:div class="progressBall" />
+        <html:div class="progressBall" />
+        <html:div class="progressBall" />
+      </html:div>
+    </content>
+  </binding>
+</bindings>
--- a/browser/metro/base/content/bookmarks.js
+++ b/browser/metro/base/content/bookmarks.js
@@ -349,24 +349,17 @@ BookmarksView.prototype = {
   handleEvent: function bv_handleEvent(aEvent) {
     switch (aEvent.type){
       case "MozAppbarDismissing":
         // If undo wasn't pressed, time to do definitive actions.
         if (this._toRemove) {
           for (let bookmarkId of this._toRemove) {
             this._bookmarkService.removeItem(bookmarkId);
           }
-
           this._toRemove = null;
-          this._set.clearSelection();
-
-          // Clear context app bar
-          let event = document.createEvent("Events");
-          event.initEvent("MozContextActionsChange", true, false);
-          this._set.dispatchEvent(event);
         }
         break;
 
       case "BookmarksNeedsRefresh":
         this.getBookmarks(true);
         break;
     }
   }
--- a/browser/metro/base/content/browser-scripts.js
+++ b/browser/metro/base/content/browser-scripts.js
@@ -129,17 +129,17 @@ let ScriptContexts = {};
   ["TopSitesView", "chrome://browser/content/TopSites.js"],
   ["TopSitesSnappedView", "chrome://browser/content/TopSites.js"],
   ["TopSitesStartView", "chrome://browser/content/TopSites.js"],
   ["Sanitizer", "chrome://browser/content/sanitize.js"],
   ["SanitizeUI", "chrome://browser/content/sanitizeUI.js"],
   ["SSLExceptions", "chrome://browser/content/exceptions.js"],
   ["ItemPinHelper", "chrome://browser/content/helperui/ItemPinHelper.js"],
 #ifdef MOZ_SERVICES_SYNC
-  ["WeaveGlue", "chrome://browser/content/sync.js"],
+  ["Sync", "chrome://browser/content/sync.js"],
   ["SyncPairDevice", "chrome://browser/content/sync.js"],
   ["RemoteTabsView", "chrome://browser/content/RemoteTabs.js"],
   ["RemoteTabsPanelView", "chrome://browser/content/RemoteTabs.js"],
   ["RemoteTabsStartView", "chrome://browser/content/RemoteTabs.js"],
 #endif
 ].forEach(function (aScript) {
   let [name, script] = aScript;
   XPCOMUtils.defineLazyGetter(window, name, function() {
--- a/browser/metro/base/content/browser-ui.js
+++ b/browser/metro/base/content/browser-ui.js
@@ -72,16 +72,17 @@ var Strings = {};
   });
 });
 
 var BrowserUI = {
   get _edit() { return document.getElementById("urlbar-edit"); },
   get _back() { return document.getElementById("cmd_back"); },
   get _forward() { return document.getElementById("cmd_forward"); },
 
+  lastKnownGoodURL: "", //used when the user wants to escape unfinished url entry
   init: function() {
     // listen content messages
     messageManager.addMessageListener("DOMTitleChanged", this);
     messageManager.addMessageListener("DOMWillOpenModalDialog", this);
     messageManager.addMessageListener("DOMWindowClose", this);
 
     messageManager.addMessageListener("Browser:OpenURI", this);
     messageManager.addMessageListener("Browser:SaveAs:Return", this);
@@ -142,17 +143,17 @@ var BrowserUI = {
       try {
         BrowserUI._updateTabsOnly();
         Downloads.init();
         DialogUI.init();
         FormHelperUI.init();
         FindHelperUI.init();
         PdfJs.init();
 #ifdef MOZ_SERVICES_SYNC
-        WeaveGlue.init();
+        Sync.init();
 #endif
       } catch(ex) {
         Util.dumpLn("Exception in delay load module:", ex.message);
       }
 
 #ifdef MOZ_UPDATER
       // Check for updates in progress
       let updatePrompt = Cc["@mozilla.org/updates/update-prompt;1"].createInstance(Ci.nsIUpdatePrompt);
@@ -637,16 +638,17 @@ var BrowserUI = {
     if (isLoading && mode != "loading")
       Elements.urlbarState.setAttribute("mode", "loading");
     else if (!isLoading && mode != "edit")
       Elements.urlbarState.setAttribute("mode", "view");
   },
 
   _setURI: function _setURI(aURL) {
     this._edit.value = aURL;
+    this.lastKnownGoodURL = aURL;
   },
 
   _urlbarClicked: function _urlbarClicked() {
     // If the urlbar is not already focused, focus it and select the contents.
     if (Elements.urlbarState.getAttribute("mode") != "edit")
       this._editURI(true);
   },
 
@@ -722,16 +724,17 @@ var BrowserUI = {
 
   // Checks if various different parts of the UI is visible and closes
   // them one at a time.
   handleEscape: function (aEvent) {
     aEvent.stopPropagation();
     aEvent.preventDefault();
 
     if (this._edit.popupOpen) {
+      this._edit.value = this.lastKnownGoodURL;
       this._edit.closePopup();
       StartUI.hide();
       ContextUI.dismiss();
       return;
     }
 
     // Check open popups
     if (DialogUI._popup) {
@@ -742,18 +745,19 @@ var BrowserUI = {
     // Check open dialogs
     let dialog = DialogUI.activeDialog;
     if (dialog) {
       dialog.close();
       return;
     }
 
     // Check open modal elements
-    if (DialogUI.modals.length > 0)
+    if (DialogUI.modals.length > 0) {
       return;
+    }
 
     // Check open panel
     if (PanelUI.isVisible) {
       PanelUI.hide();
       return;
     }
 
     // Check content helper
@@ -1036,17 +1040,17 @@ var BrowserUI = {
       case "cmd_bookmarks":
         PanelUI.show("bookmarks-container");
         break;
       case "cmd_history":
         PanelUI.show("history-container");
         break;
       case "cmd_remoteTabs":
         if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED) {
-          WeaveGlue.open();
+          Sync.open();
         } else {
           PanelUI.show("remotetabs-container");
         }
         break;
       case "cmd_quit":
         // Only close one window
         this._closeOrQuit();
         break;
@@ -1473,17 +1477,17 @@ var StartUI = {
 };
 
 var SyncPanelUI = {
   init: function() {
     // Run some setup code the first time the panel is shown.
     Elements.syncFlyout.addEventListener("PopupChanged", function onShow(aEvent) {
       if (aEvent.detail && aEvent.target === Elements.syncFlyout) {
         Elements.syncFlyout.removeEventListener("PopupChanged", onShow, false);
-        WeaveGlue.init();
+        Sync.init();
       }
     }, false);
   }
 };
 
 var FlyoutPanelsUI = {
   get _aboutVersionLabel() {
     return document.getElementById('about-version-label');
--- a/browser/metro/base/content/browser.css
+++ b/browser/metro/base/content/browser.css
@@ -25,16 +25,20 @@ documenttab {
 appbar {
   -moz-binding: url('chrome://browser/content/bindings/appbar.xml#appbarBinding');
 }
 
 flyoutpanel {
   -moz-binding: url('chrome://browser/content/bindings/flyoutpanel.xml#flyoutpanelBinding');
 }
 
+cssthrobber {
+  -moz-binding: url('chrome://browser/content/bindings/cssthrobber.xml#cssthrobberBinding');
+}
+
 settings {
   -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#settings");
 }
 
 setting {
   display: none;
 }
 
--- a/browser/metro/base/content/browser.xul
+++ b/browser/metro/base/content/browser.xul
@@ -3,16 +3,17 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <?xml-stylesheet href="chrome://browser/skin/platform.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/forms.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/cssthrobber.css" type="text/css"?>
 
 <!DOCTYPE window [
 <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
 %globalDTD;
 <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
 %browserDTD;
 <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
 %brandDTD;
@@ -279,23 +280,23 @@
             </vbox>
             </scrollbox>
           </hbox>
           <!-- snapped view -->
           <vbox id="snapped-start" class="start-page" observes="bcast_windowState">
             <scrollbox id="snapped-scrollbox" orient="vertical" flex="1">
               <vbox id="snapped-topsites">
                 <label class="meta-section-title" value="&startTopSitesHeader.label;"/>
-                <richgrid id="snapped-topsites-grid" rows="8" columns="1" flex="1"/>
+                <richgrid id="snapped-topsites-grid" class="canSnapTiles" rows="8" columns="1" flex="1"/>
               </vbox>
               <label class="meta-section-title" value="&startBookmarksHeader.label;"
                 onclick="PanelUI.show('bookmarks-container');"/>
               <label class="meta-section-title" value="&startHistoryHeader.label;"
                 onclick="PanelUI.show('history-container');" inputProcessing="true"/>
-              <label class="meta-section-title" value="&startRemoteTabsHeader.label;"
+              <label id="snappedRemoteTabsLabel" class="meta-section-title" value="&snappedRemoteTabsHeader.label;"
                 onclick="PanelUI.show('remotetabs-container');" inputProcessing="true"/>
             </scrollbox>
           </vbox>
           <!-- Autocompletion interface -->
           <box id="start-autocomplete" observes="bcast_windowState"/>
         </hbox>
       </vbox> <!-- end tray -->
 
@@ -396,29 +397,47 @@
         <label value="&aboutHeader.company.label;"/>
 #expand <label id="about-version-label">__MOZ_APP_VERSION__</label>
         <label id="about-policy-label"
                onclick="if (event.button == 0) { Browser.onAboutPolicyClick(); }"
                class="text-link" value="&aboutHeader.policy.label;"/>
     </flyoutpanel>
 
     <flyoutpanel id="sync-flyoutpanel" headertext="&syncHeader.title;">
-      <setting id="sync-connect" title="&sync.notconnected;" type="control">
-        <button label="&sync.connect;" oncommand="WeaveGlue.tryConnect();" />
+      <description>&sync.setup.description;</description> 
+      <description id="sync-accountinfo" collapsed="true"></description> 
+      <description id="sync-lastsync" collapsed="true"></description> 
+      <description id="sync-errordescription" collapsed="true"></description> 
+      <setting id="sync-connect" type="control" collapsed="true">
+        <button label="&sync.setupbutton.label;" oncommand="Sync.tryConnect();" />
       </setting>
-      <setting id="sync-connected" class="setting-group" title="&sync.connected;" type="control" collapsed="true">
+      <setting id="sync-connected" class="setting-group" type="control" collapsed="true">
         <button id="sync-pairdevice" label="&sync.pair.button;" oncommand="SyncPairDevice.open();" />
       </setting>
-      <setting id="sync-sync" class="setting-subgroup" type="control" collapsed="true">
-        <button id="sync-syncButton" label="&sync.syncNow2;" oncommand="WeaveGlue.sync();"/>
+      <setting id="sync-device" class="setting-subgroup" type="string" title="&sync.deviceName;" onchange="Sync.changeName(this);" collapsed="true"/>
+      <setting id="sync-disconnect" class="setting-subgroup" type="control" collapsed="true">
+        <button label="&sync.removebutton.label;" oncommand="Sync.onDisconnect();" />
       </setting>
-      <setting id="sync-device" class="setting-subgroup" type="string" title="&sync.deviceName;" onchange="WeaveGlue.changeName(this);" collapsed="true"/>
-      <setting id="sync-disconnect" class="setting-subgroup" type="control" collapsed="true">
-        <button label="&sync.disconnect;" oncommand="WeaveGlue.disconnect();" />
-      </setting>
+      <vbox id="sync-disconnectwarnpanel" collapsed="true">
+        <description id="sync-disconnectwarntitle"></description>
+        <description id="sync-disconnectwarnmsg">&sync.removewarn.note;</description>
+        <hbox>
+          <spacer flex="1" />
+          <button label="&sync.setup.cancel;" oncommand="Sync.onCancelDisconnect();" />
+          <button label="&sync.setup.remove;" oncommand="Sync.disconnect();" />
+        </hbox>
+      </vbox>
+      <vbox id="sync-disconnectthrobber" collapsed="true">
+        <hbox>
+          <spacer flex="1" />
+          <cssthrobber id="syncdisconnectthrobber" />
+          <label>&sync.removethrobber.label;</label>
+          <spacer flex="1" />
+        </hbox>
+      </vbox>
     </flyoutpanel>
 
     <flyoutpanel id="prefs-flyoutpanel" headertext="&optionsHeader.title;">
       <settings id="prefs-startup" label="&optionsHeader.startup.title;"> <!-- note, this element has a custom margin-top -->
         <setting id="prefs-homepage" title="&optionsHeader.homepage.title;" type="menulist" pref="browser.startup.sessionRestore" class="setting-expanded">
           <menulist id="prefs-homepage-options">
             <menupopup id="prefs-homepage-popup" position="after_end">
               <menuitem id="prefs-homepage-default" label="&optionsHeader.homepage.startPage.button;" value="false"/>
@@ -473,89 +492,89 @@
       </settings>
     </flyoutpanel>
 
 #ifdef MOZ_SERVICES_SYNC
     <box id="syncsetup-container" class="perm-modal-block" hidden="true">
       <dialog id="syncsetup-dialog" class="content-dialog" flex="1">
         <vbox class="prompt-inner">
           <hbox class="prompt-title">
-            <description>&sync.setup.title;</description>
+            <description>&sync.setup2.title;</description>
           </hbox>
           <vbox id="syncsetup-simple" class="syncsetup-page" flex="1">
             <scrollbox id="sync-message" class="prompt-message" orient="vertical" flex="1">
               <description class="syncsetup-desc" flex="1">&sync.setup.pair2;</description>
-              <description class="link" flex="1" onclick="WeaveGlue.openTutorial();">&sync.setup.tutorial;</description>
+              <description class="link" flex="1" onclick="Sync.openTutorial();">&sync.setup.tutorial;</description>
               <separator/>
               <vbox flex="1" pack="center" align="start">
                 <description id="syncsetup-code1" class="syncsetup-code">....</description>
                 <description id="syncsetup-code2" class="syncsetup-code">....</description>
                 <description id="syncsetup-code3" class="syncsetup-code">....</description>
               </vbox>
               <separator/>
-              <description class="link" flex="1" onclick="WeaveGlue.openManual();">&sync.fallback;</description>
+              <description class="link" flex="1" onclick="Sync.openManual();">&sync.fallback;</description>
               <separator flex="1"/>
             </scrollbox>
             <hbox class="prompt-buttons">
-              <button class="prompt-button" oncommand="WeaveGlue.close();">&sync.setup.cancel;</button>
+              <button oncommand="Sync.close();">&sync.setup.cancel;</button>
             </hbox>
           </vbox>
           <vbox id="syncsetup-waiting" class="syncsetup-page" flex="1" hidden="true">
             <progressmeter id="syncsetup-progressbar" mode="undetermined"/>
             <vbox id="syncsetup-waiting-top" align="center" flex="1">
               <description id="syncsetup-waiting-desc" class="syncsetup-desc" flex="1">&sync.setup.waiting2;</description>
               <description id="syncsetup-waitingdownload-desc" class="syncsetup-desc" hidden="true" flex="1">&sync.setup.waitingdownload;</description>
             </vbox>
             <hbox class="prompt-buttons" pack="center" align="end">
-              <button id="syncsetup-waiting-cancel" class="prompt-button" oncommand="WeaveGlue.close();">&sync.setup.cancel;</button>
-              <button id="syncsetup-waiting-close" class="prompt-button" hidden="true" oncommand="WeaveGlue.close();">&sync.setup.close;</button>
+              <button id="syncsetup-waiting-cancel" oncommand="Sync.close();">&sync.setup.cancel;</button>
+              <button id="syncsetup-waiting-close" hidden="true" oncommand="Sync.close();">&sync.setup.close;</button>
             </hbox>
           </vbox>
           <vbox id="syncsetup-fallback" class="syncsetup-page" flex="1" hidden="true">
             <scrollbox class="prompt-message" orient="vertical" flex="1">
               <description class="syncsetup-desc" flex="1">&sync.setup.manual;</description>
               <separator/>
-              <textbox id="syncsetup-account" class="prompt-edit" placeholder="&sync.account;" oninput="WeaveGlue.canConnect();"/>
-              <textbox id="syncsetup-password" class="prompt-edit" placeholder="&sync.password;" type="password" oninput="WeaveGlue.canConnect();"/>
-              <textbox id="syncsetup-synckey" class="prompt-edit" placeholder="&sync.recoveryKey;" oninput="WeaveGlue.canConnect();"/>
+              <textbox id="syncsetup-account" class="prompt-edit" placeholder="&sync.account;" oninput="Sync.canConnect();"/>
+              <textbox id="syncsetup-password" class="prompt-edit" placeholder="&sync.password;" type="password" oninput="Sync.canConnect();"/>
+              <textbox id="syncsetup-synckey" class="prompt-edit" placeholder="&sync.recoveryKey;" oninput="Sync.canConnect();"/>
               <separator class="thin"/>
-              <checkbox id="syncsetup-usecustomserver" label="&sync.customServer;" oncommand="WeaveGlue.toggleCustomServer();"/>
+              <checkbox id="syncsetup-usecustomserver" label="&sync.customServer;" oncommand="Sync.toggleCustomServer();"/>
               <textbox id="syncsetup-customserver" class="prompt-edit" placeholder="&sync.serverURL;"/>
               <separator flex="1"/>
             </scrollbox>
             <hbox class="prompt-buttons">
-              <button class="prompt-button" oncommand="WeaveGlue.close();">&sync.setup.cancel;</button>
+              <button oncommand="Sync.close();">&sync.setup.cancel;</button>
               <separator/>
-              <button id="syncsetup-button-connect" class="prompt-button" oncommand="WeaveGlue.close(); WeaveGlue.connect();">&sync.setup.connect;</button>
+              <button id="syncsetup-button-connect" oncommand="Sync.close(); Sync.connect();">&sync.setup.connect2;</button>
             </hbox>
           </vbox>
         </vbox>
       </dialog>
     </box>
 
     <box id="syncpair-container" class="perm-modal-block" hidden="true">
       <dialog id="syncpair-dialog" class="content-dialog" flex="1">
         <vbox class="prompt-inner">
           <hbox class="prompt-title">
             <description>&sync.pair.title;</description>
           </hbox>
           <vbox id="syncpair-simple" class="syncsetup-page" flex="1">
             <vbox id="sync-message" class="prompt-message" orient="vertical" flex="1">
               <description class="syncsetup-desc" flex="1">&sync.pair.description;</description>
-              <description class="link" flex="1" onclick="SyncPairDevice.close(); WeaveGlue.openTutorial();">&sync.setup.tutorial;</description>
+              <description class="link" flex="1" onclick="SyncPairDevice.close(); Sync.openTutorial();">&sync.setup.tutorial;</description>
               <separator/>
               <vbox align="center" flex="1">
                 <textbox id="syncpair-code1" class="syncsetup-code" oninput="SyncPairDevice.onTextBoxInput(this);"/>
                 <textbox id="syncpair-code2" class="syncsetup-code" oninput="SyncPairDevice.onTextBoxInput(this);"/>
                 <textbox id="syncpair-code3" class="syncsetup-code" oninput="SyncPairDevice.onTextBoxInput(this);"/>
               </vbox>
             </vbox>
             <hbox class="prompt-buttons" pack="center">
-              <button class="prompt-button" oncommand="SyncPairDevice.close();">&sync.setup.cancel;</button>
-              <button id="syncpair-connectbutton" class="prompt-button" disabled="true" oncommand="SyncPairDevice.connect();">&sync.setup.connect;</button>
+              <button oncommand="SyncPairDevice.close();">&sync.setup.cancel;</button>
+              <button id="syncpair-connectbutton" disabled="true" oncommand="SyncPairDevice.connect();">&sync.setup.connect2;</button>
             </hbox>
           </vbox>
         </vbox>
       </dialog>
     </box>
 #endif
 
     <box onclick="event.stopPropagation();" id="context-container" class="menu-container" hidden="true">
--- a/browser/metro/base/content/history.js
+++ b/browser/metro/base/content/history.js
@@ -189,17 +189,16 @@ HistoryView.prototype = {
           }
 
           // Clear context app bar
           let event = document.createEvent("Events");
           event.initEvent("MozContextActionsChange", true, false);
           this._set.dispatchEvent(event);
 
           this._toRemove = null;
-          this._set.clearSelection();
         }
         break;
 
       case "HistoryNeedsRefresh":
         this.populateGrid(true);
         break;
     }
   },
--- a/browser/metro/base/content/pages/aboutRights.xhtml
+++ b/browser/metro/base/content/pages/aboutRights.xhtml
@@ -36,17 +36,17 @@
   <li>&rights2.intro-point3a;<a href="http://www.mozilla.com/legal/privacy/">&rights2.intro-point3b;</a>&rights.intro-point3c;</li>
   <li>&rights2.intro-point4a;<a href="about:rights#webservices" onclick="showServices();">&rights.intro-point4b;</a>&rights.intro-point4c;</li>
 </ul>
 
 <div id="webservices-container">
   <a name="webservices"/>
   <h3>&rights2.webservices-header;</h3>
 
-  <p>&rights2.webservices-a;<a href="about:rights#disabling-webservices" onclick="showDisablingServices();">&rights2.webservices-b;</a>&rights2.webservices-c;</p>
+  <p>&rights2.webservices-a;<a href="about:rights#disabling-webservices" onclick="showDisablingServices();">&rights2.webservices-b;</a>&rights3.webservices-c;</p>
 
   <div id="disabling-webservices-container" style="margin-left:40px;">
     <a name="disabling-webservices"/>
     <!-- XXX Safe Browsing is not enabled in Firefox Mobile -->
     <!--
     <p><strong>&rights.safebrowsing-a;</strong>&rights.safebrowsing-b;</p>
     <ul>
       <li>&rights.safebrowsing-term1;</li>
--- a/browser/metro/base/content/prompt/confirm.xul
+++ b/browser/metro/base/content/prompt/confirm.xul
@@ -29,13 +29,13 @@
       <scrollbox orient="vertical" class="prompt-message" flex="1">
         <description id="prompt-confirm-message"/>
       </scrollbox>
   
       <checkbox id="prompt-confirm-checkbox" collapsed="true" pack="start" flex="1"/>
     </vbox>
   
     <hbox id="prompt-confirm-buttons-box" class="prompt-buttons">
-      <button class="prompt-button button-default" label="&ok.label;" command="cmd_ok"/>
-      <button class="prompt-button" label="&cancel.label;" command="cmd_cancel"/>
+      <button class="button-default" label="&ok.label;" command="cmd_ok"/>
+      <button label="&cancel.label;" command="cmd_cancel"/>
     </hbox>
   </vbox>
 </dialog>
--- a/browser/metro/base/content/prompt/prompt.xul
+++ b/browser/metro/base/content/prompt/prompt.xul
@@ -31,13 +31,13 @@
       </scrollbox>
   
       <textbox id="prompt-prompt-textbox" class="prompt-edit"/>
   
       <button id="prompt-prompt-checkbox" collapsed="true" pack="start" flex="1"/>
     </vbox>
   
     <hbox class="prompt-buttons">
-      <button class="prompt-button" label="&ok.label;" command="cmd_ok"/>
-      <button class="prompt-button" label="&cancel.label;" command="cmd_cancel"/>
+      <button label="&ok.label;" command="cmd_ok"/>
+      <button label="&cancel.label;" command="cmd_cancel"/>
     </hbox>
   </vbox>
 </dialog>
--- a/browser/metro/base/content/prompt/promptPassword.xul
+++ b/browser/metro/base/content/prompt/promptPassword.xul
@@ -51,13 +51,13 @@
           </row>
         </rows>
       </grid>
     
       <checkbox id="prompt-password-checkbox" collapsed="true" pack="start" flex="1"/>
     </vbox>
   
     <hbox class="prompt-buttons">
-      <button class="prompt-button button-default" label="&ok.label;" command="cmd_ok"/>
-      <button class="prompt-button" label="&cancel.label;" command="cmd_cancel"/>
+      <button class="button-default" label="&ok.label;" command="cmd_ok"/>
+      <button label="&cancel.label;" command="cmd_cancel"/>
   </hbox>
   </vbox>
 </dialog>
--- a/browser/metro/base/content/prompt/select.xul
+++ b/browser/metro/base/content/prompt/select.xul
@@ -29,13 +29,13 @@
       <scrollbox orient="vertical" class="prompt-message" flex="1">
         <description id="prompt-select-message"/>
       </scrollbox>
   
       <menulist id="prompt-select-list"/>
     </vbox>
   
     <hbox class="prompt-buttons">
-      <button class="prompt-button button-default" label="&ok.label;" command="cmd_ok"/>
-      <button class="prompt-button" label="&cancel.label;" command="cmd_cancel"/>
+      <button class="button-default" label="&ok.label;" command="cmd_ok"/>
+      <button label="&cancel.label;" command="cmd_cancel"/>
     </hbox>
   </vbox>
 </dialog>
--- a/browser/metro/base/content/sanitize.js
+++ b/browser/metro/base/content/sanitize.js
@@ -61,17 +61,17 @@ Sanitizer.prototype = {
   
   items: {
     // Clear Sync account before passwords so that Sync still has access to the
     // credentials to clean up device-specific records on the server. Also
     // disable it before wiping history so we don't accidentally sync that.
     syncAccount: {
       clear: function ()
       {
-        WeaveGlue.disconnect();
+        Sync.disconnect();
       },
 
       get canClear()
       {
         return (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED);
       }
     },
 
--- a/browser/metro/base/content/sync.js
+++ b/browser/metro/base/content/sync.js
@@ -1,34 +1,50 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-let WeaveGlue = {
+let Sync = {
   setupData: null,
   _boundOnEngineSync: null,     // Needed to unhook the observers in close().
   _boundOnServiceSync: null,
   jpake: null,
   _bundle: null,
   _loginError: false,
   _progressBar: null,
   _progressValue: 0,
   _progressMax: null,
+  _disconnecting: false,
+
+  get _isSetup() {
+    if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED) {
+      return false;
+    }
+    // check for issues related to failed logins that do not have anything to
+    // do with network, server, and other non-client issues. See the login
+    // failure status codes in sync service.
+    return (Weave.Status.login != Weave.LOGIN_FAILED_NO_USERNAME &&
+            Weave.Status.login != Weave.LOGIN_FAILED_NO_PASSWORD &&
+            Weave.Status.login != Weave.LOGIN_FAILED_NO_PASSPHRASE &&
+            Weave.Status.login != Weave.LOGIN_FAILED_INVALID_PASSPHRASE &&
+            Weave.Status.login != Weave.LOGIN_FAILED_LOGIN_REJECTED);
+  },
 
   init: function init() {
     if (this._bundle) {
       return;
     }
 
     let service = Components.classes["@mozilla.org/weave/service;1"]
                                     .getService(Components.interfaces.nsISupports)
                                     .wrappedJSObject;
 
     if (service.ready) {
       this._init();
+      Weave.Service.scheduler.scheduleNextSync(10*1000); // ten seconds after we startup
     } else {
       Services.obs.addObserver(this, "weave:service:ready", false);
       service.ensureLoaded();
     }
   },
 
 #ifdef XP_WIN
   _securelySetupFromMetro: function() {
@@ -60,34 +76,28 @@ let WeaveGlue = {
 
     this.connect();
     return true;
   },
 #endif
 
   _init: function () {
     this._bundle = Services.strings.createBundle("chrome://browser/locale/sync.properties");
-    this._msg = document.getElementById("prefs-messages");
 
     this._addListeners();
 
     this.setupData = { account: "", password: "" , synckey: "", serverURL: "" };
 
-    if (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED) {
-      // Put the settings UI into a state of "connecting..." if we are going to auto-connect
-      this._elements.connect.firstChild.disabled = true;
-      this._elements.connect.setAttribute("title", this._bundle.GetStringFromName("connecting.label"));
-
-      try {
-        this._elements.device.value = Services.prefs.getCharPref("services.sync.client.name");
-      } catch(e) {}
-    } else if (Weave.Status.login != Weave.LOGIN_FAILED_NO_USERNAME) {
+    if (this._isSetup) {
       this.loadSetupData();
     }
 
+    // Update the state of the ui
+    this._updateUI();
+
     this._boundOnEngineSync = this.onEngineSync.bind(this);
     this._boundOnServiceSync = this.onServiceSync.bind(this);
     this._progressBar = document.getElementById("syncsetup-progressbar");
 
 #ifdef XP_WIN
     if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED) {
       this._securelySetupFromMetro();
     }
@@ -365,179 +375,219 @@ let WeaveGlue = {
       Weave.Service.serverURL = this.setupData.serverURL;
 
     // Sync will use the account value and munge it into a username, as needed
     Weave.Service.identity.account = this.setupData.account;
     Weave.Service.identity.basicPassword = this.setupData.password;
     Weave.Service.identity.syncKey = this.setupData.synckey;
     Weave.Service.persistLogin();
     Weave.Svc.Obs.notify("weave:service:setup-complete");
-    setTimeout(function () { Weave.Service.sync(); }, 0);
+    this.sync();
+  },
+
+  // called when the user taps the disconnect button
+  onDisconnect: function onDisconnect() {
+    Weave.Service.logout();
+    let bundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
+    let brandName = bundle.GetStringFromName("brandShortName");
+    let warnStr = this._bundle.formatStringFromName("sync.disconnectPrompt", [brandName], 1);
+    this._elements.disconnectwarntitle.textContent = warnStr;
+    this._elements.disconnectwarnpanel.collapsed = false;
   },
 
-  disconnect: function disconnect() {
-    // Save credentials for undo
-    let undoData = this.setupData;
-
-    // Remove all credentials
-    this.setupData = null;
-    Weave.Service.startOver();
+  // called when the user taps the cancel button on
+  // the disconnect warning panel.
+  onCancelDisconnect: function onCancelDisconnect() {
+    this._elements.disconnectwarnpanel.collapsed = true;
+    this._updateUI();
+    Weave.Service.login();
+  },
 
-    let message = this._bundle.GetStringFromName("notificationDisconnect.label");
-    let button = this._bundle.GetStringFromName("notificationDisconnect.button");
-    let buttons = [ {
-      label: button,
-      accessKey: "",
-      callback: function() { WeaveGlue.connect(undoData); }
-    } ];
-    this.showMessage(message, "undo-disconnect", buttons);
-
-    // Hide the notification when the panel is changed or closed.
-    let panel = document.getElementById("prefs-container");
-    panel.addEventListener("ToolPanelHidden", function onHide(aEvent) {
-      panel.removeEventListener(aEvent.type, onHide, false);
-      let notification = WeaveGlue._msg.getNotificationWithValue("undo-disconnect");
-      if (notification)
-        notification.close();
-    }, false);
-
-    Weave.Service.logout();
+  // called when the user taps the remove button on
+  // the disconnect warning panel.
+  disconnect: function disconnect() {
+    this._elements.disconnectwarnpanel.collapsed = true;
+    this.setupData = null;
+    this._disconnecting = true;
+    this._updateUI();
+    Weave.Service.startOver();
   },
 
   sync: function sync() {
-    Weave.Service.sync();
+    Weave.Service.scheduler.scheduleNextSync(0);
   },
 
   _addListeners: function _addListeners() {
     let topics = ["weave:service:setup-complete",
       "weave:service:sync:start", "weave:service:sync:finish",
       "weave:service:sync:error", "weave:service:login:start",
       "weave:service:login:finish", "weave:service:login:error",
       "weave:ui:login:error",
+      "weave:service:start-over", "weave:service:start-over:finish",
       "weave:service:logout:finish"];
 
-    // For each topic, add WeaveGlue the observer
+    // For each topic, add Sync the observer
     topics.forEach(function(topic) {
-      Services.obs.addObserver(WeaveGlue, topic, false);
+      Services.obs.addObserver(Sync, topic, false);
     });
 
     // Remove them on unload
     addEventListener("unload", function() {
       topics.forEach(function(topic) {
-        Services.obs.removeObserver(WeaveGlue, topic);
+        Services.obs.removeObserver(Sync, topic);
       });
     }, false);
   },
 
   get _elements() {
-    // Do a quick test to see if the options exist yet
-    let syncButton = document.getElementById("sync-syncButton");
-    if (syncButton == null)
-      return null;
-
     // Get all the setting nodes from the add-ons display
     let elements = {};
     let setupids = ["account", "password", "synckey", "usecustomserver", "customserver"];
     setupids.forEach(function(id) {
       elements[id] = document.getElementById("syncsetup-" + id);
     });
 
-    let settingids = ["device", "connect", "connected", "disconnect", "sync", "pairdevice"];
+    let settingids = ["device", "connect", "connected", "disconnect", "lastsync", "pairdevice",
+                      "errordescription", "accountinfo", "disconnectwarnpanel", "disconnectthrobber",
+                      "disconnectwarntitle"];
     settingids.forEach(function(id) {
       elements[id] = document.getElementById("sync-" + id);
     });
 
     // Replace the getter with the collection of settings
     delete this._elements;
     return this._elements = elements;
   },
 
+  _updateUI: function _updateUI() {
+    if (this._elements == null)
+      return;
+
+    let connect = this._elements.connect;
+    let connected = this._elements.connected;
+    let device = this._elements.device;
+    let disconnect = this._elements.disconnect;
+    let lastsync = this._elements.lastsync;
+    let pairdevice = this._elements.pairdevice;
+    let accountinfo = this._elements.accountinfo;
+    let disconnectthrobber = this._elements.disconnectthrobber;
+
+    // This gets updated when an error occurs
+    this._elements.errordescription.collapsed = true;
+
+    let isConfigured = (!this._loginError && this._isSetup);
+
+    // If we're in the process of disconnecting we are no longer configured.
+    if (this._disconnecting) {
+      isConfigured = false;
+      // display the throbber with the appropriate message
+      disconnectthrobber.collapsed = false;
+    } else {
+      disconnectthrobber.collapsed = true;
+    }
+
+    connect.collapsed = isConfigured;
+    connected.collapsed = !isConfigured;
+    lastsync.collapsed = !isConfigured;
+    device.collapsed = !isConfigured;
+    disconnect.collapsed = !isConfigured;
+
+    if (this._disconnecting) {
+      connect.collapsed = true;
+    }
+
+    // Set the device name text edit to configured name or the auto generated
+    // name if we aren't set up.
+    try {
+      device.value = Services.prefs.getCharPref("services.sync.client.name");
+    } catch(ex) {
+      device.value = Weave.Service.clientsEngine.localName || "";
+    }
+
+    // Account information header
+    accountinfo.collapsed = true;
+    try {
+      let account = Weave.Service.identity.account;
+      if (account != null && isConfigured) {
+        let accountStr = this._bundle.formatStringFromName("account.label", [account], 1);
+        accountinfo.textContent = accountStr;
+        accountinfo.collapsed = false;
+      }
+    } catch (ex) {}
+
+    // If we're already locked, a sync is in progress..
+    if (Weave.Service.locked && isConfigured) {
+      connect.firstChild.disabled = true;
+    }
+
+    // Show the day-of-week and time (HH:MM) of last sync
+    let lastSync = Weave.Svc.Prefs.get("lastSync");
+    lastsync.textContent = "";
+    if (lastSync != null) {
+      let syncDate = new Date(lastSync).toLocaleFormat("%A %I:%M %p");
+      let dateStr = this._bundle.formatStringFromName("lastSync2.label", [syncDate], 1);
+      lastsync.textContent = dateStr;
+    }
+
+    // Check the lock again on a timeout since it's set after observers notify
+    setTimeout(function(self) {
+      // Prevent certain actions when the service is locked
+      if (Weave.Service.locked) {
+        connect.firstChild.disabled = true;
+      } else {
+        connect.firstChild.disabled = false;
+      }
+    }, 100, this);
+  },
+
   observe: function observe(aSubject, aTopic, aData) {
     if (aTopic == "weave:service:ready") {
       Services.obs.removeObserver(this, aTopic);
       this._init();
       return;
     }
 
     // Make sure we're online when connecting/syncing
     Util.forceOnline();
 
+    if (aTopic == "weave:service:start-over") {
+      this._disconnecting = true;
+    } else if (aTopic == "weave:service:start-over:finish") {
+      this._disconnecting = false;
+    }
+
     // Can't do anything before settings are loaded
     if (this._elements == null)
       return;
 
-    // Make some aliases
-    let connect = this._elements.connect;
-    let connected = this._elements.connected;
-    let device = this._elements.device;
-    let disconnect = this._elements.disconnect;
-    let sync = this._elements.sync;
-    let pairdevice = this._elements.pairdevice;
+    // Update the state of the ui
+    this._updateUI();
+
+    let errormsg = this._elements.errordescription;
+    let accountinfo = this._elements.accountinfo;
 
     // Show what went wrong with login if necessary
     if (aTopic == "weave:ui:login:error") {
       this._loginError = true;
-      connect.setAttribute("desc", Weave.Utils.getErrorString(Weave.Status.login));
-    } else {
-      connect.removeAttribute("desc");
+      errormsg.textContent = Weave.Utils.getErrorString(Weave.Status.login);
+      errormsg.collapsed = false;
     }
 
     if (aTopic == "weave:service:login:finish") {
       this._loginError = false;
       // Init the setup data if we just logged in
       if (!this.setupData)
         this.loadSetupData();
     }
 
-    let isConfigured = (!this._loginError && Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED);
-
-    connect.collapsed = isConfigured;
-    connected.collapsed = !isConfigured;
-
-    if (!isConfigured) {
-      connect.setAttribute("title", this._bundle.GetStringFromName("notconnected.label"));
-      connect.firstChild.disabled = false;
-    }
-
-    sync.collapsed = !isConfigured;
-    device.collapsed = !isConfigured;
-    disconnect.collapsed = !isConfigured;
-
-    // Check the lock on a timeout because it's set just after notifying
-    setTimeout(function(self) {
-      // Prevent certain actions when the service is locked
-      if (Weave.Service.locked) {
-        connect.firstChild.disabled = true;
-        sync.firstChild.disabled = true;
-
-        if (aTopic == "weave:service:login:start")
-          connect.setAttribute("title", self._bundle.GetStringFromName("connecting.label"));
-
-        if (aTopic == "weave:service:sync:start")
-          sync.setAttribute("title", self._bundle.GetStringFromName("lastSyncInProgress2.label"));
-      } else {
-        connect.firstChild.disabled = false;
-        sync.firstChild.disabled = false;
-      }
-    }, 0, this);
-
-    // Dynamically generate some strings
-    let accountStr = this._bundle.formatStringFromName("account.label", [Weave.Service.identity.account], 1);
-    disconnect.setAttribute("title", accountStr);
-
-    // Show the day-of-week and time (HH:MM) of last sync
-    let lastSync = Weave.Svc.Prefs.get("lastSync");
-    if (lastSync != null) {
-      let syncDate = new Date(lastSync).toLocaleFormat("%a %H:%M");
-      let dateStr = this._bundle.formatStringFromName("lastSync2.label", [syncDate], 1);
-      sync.setAttribute("title", dateStr);
-    }
-
     // Check for a storage format update, update the user and load the Sync update page
     if (aTopic =="weave:service:sync:error") {
+      errormsg.textContent = Weave.Utils.getErrorString(Weave.Status.sync);
+      errormsg.collapsed = false;
+
       let clientOutdated = false, remoteOutdated = false;
       if (Weave.Status.sync == Weave.VERSION_OUT_OF_DATE) {
         clientOutdated = true;
       } else if (Weave.Status.sync == Weave.DESKTOP_VERSION_OUT_OF_DATE) {
         remoteOutdated = true;
       } else if (Weave.Status.service == Weave.SYNC_FAILED_PARTIAL) {
         // Some engines failed, check for per-engine compat
         for (let [engine, reason] in Iterator(Weave.Status.engines)) {
@@ -560,47 +610,37 @@ let WeaveGlue = {
 
         let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
                     Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_IS_STRING;
         let choice = Services.prompt.confirmEx(window, title, message, flags, button, close, null, null, {});
         if (choice == 0)
           Browser.addTab("https://services.mozilla.com/update/", true, Browser.selectedTab);
       }
     }
-
-    device.value = Weave.Service.clientsEngine.localName || "";
   },
 
   changeName: function changeName(aInput) {
     // Make sure to update to a modified name, e.g., empty-string -> default
     Weave.Service.clientsEngine.localName = aInput.value;
     aInput.value = Weave.Service.clientsEngine.localName;
   },
 
-  showMessage: function showMessage(aMsg, aValue, aButtons) {
-    let notification = this._msg.getNotificationWithValue(aValue);
-    if (notification)
-      return;
-
-    this._msg.appendNotification(aMsg, aValue, "", this._msg.PRIORITY_WARNING_LOW, aButtons);
-  },
-
   _validateServer: function _validateServer(aURL) {
     let uri = Weave.Utils.makeURI(aURL);
 
     if (!uri && aURL)
       uri = Weave.Utils.makeURI("https://" + aURL);
 
     if (!uri)
       return "";
     return uri.spec;
   },
 
   openTutorial: function _openTutorial() {
-    WeaveGlue.close();
+    Sync.close();
 
     let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter);
     let url = formatter.formatURLPref("app.sync.tutorialURL");
     BrowserUI.newTab(url, Browser.selectedTab);
   },
 
   loadSetupData: function _loadSetupData() {
     this.setupData = {};
--- a/browser/metro/base/jar.mn
+++ b/browser/metro/base/jar.mn
@@ -21,16 +21,17 @@ chrome.jar:
   content/bindings/console.xml                 (content/bindings/console.xml)
   content/bindings/dialog.xml                  (content/bindings/dialog.xml)
   content/bindings/arrowbox.xml                (content/bindings/arrowbox.xml)
   content/bindings/grid.xml                    (content/bindings/grid.xml)
   content/bindings/autocomplete.xml            (content/bindings/autocomplete.xml)
   content/bindings/appbar.xml                  (content/bindings/appbar.xml)
   content/bindings/flyoutpanel.xml             (content/bindings/flyoutpanel.xml)
   content/bindings/selectionoverlay.xml        (content/bindings/selectionoverlay.xml)
+  content/bindings/cssthrobber.xml             (content/bindings/cssthrobber.xml)
 
   content/prompt/alert.xul                     (content/prompt/alert.xul)
   content/prompt/confirm.xul                   (content/prompt/confirm.xul)
   content/prompt/prompt.xul                    (content/prompt/prompt.xul)
   content/prompt/promptPassword.xul            (content/prompt/promptPassword.xul)
   content/prompt/select.xul                    (content/prompt/select.xul)
   content/prompt/prompt.js                     (content/prompt/prompt.js)
 
--- a/browser/metro/base/tests/mochitest/browser_remotetabs.js
+++ b/browser/metro/base/tests/mochitest/browser_remotetabs.js
@@ -1,47 +1,48 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-////////////////////////////////////////////////////////////////////////////////
-//// Globals
-
-Components.utils.import("resource://services-sync/main.js");
-////////////////////////////////////////////////////////////////////////////////
-//// Test(s)
-
-function test() {
-  is(Weave.Status.checkSetup(), Weave.CLIENT_NOT_CONFIGURED, "Sync should be disabled on start");
-  // check start page is hidden
-
-  let vbox = document.getElementById("start-remotetabs");
-  ok(vbox.hidden, "remote tabs in the start page should be hidden when sync is not enabled");
-  // check container link is hidden
-  let menulink = document.getElementById("menuitem-remotetabs");
-  ok(menulink.hidden, "link to container should be hidden when sync is not enabled");
-
-  // hacky-fake sync setup and enabled. Note the Sync Tracker will spit
-  // a number of warnings about undefined ids
-  Weave.Status._authManager.username = "jane doe"; // must set username before key
-  Weave.Status._authManager.basicPassword = "goatcheesesalad";
-  Weave.Status._authManager.syncKey = "a-bcdef-abcde-acbde-acbde-acbde";
-  // check that it worked
-  isnot(Weave.Status.checkSetup(), Weave.CLIENT_NOT_CONFIGURED, "Sync is enabled");
-  Weave.Svc.Obs.notify("weave:service:setup-complete");
-
-  // start page grid should be visible
-  ok(vbox, "remote tabs grid is present on start page");
-  //PanelUI.show("remotetabs-container");
-  is(vbox.hidden, false, "remote tabs should be visible in start page when sync is enabled");
-  // container link should be visible
-  is(menulink.hidden, false, "link to container should be visible when sync is enabled");
-
-  // hacky-fake sync disable
-  Weave.Status._authManager.deleteSyncCredentials();
-  Weave.Svc.Obs.notify("weave:service:start-over");
-  is(Weave.Status.checkSetup(), Weave.CLIENT_NOT_CONFIGURED, "Sync has been disabled");
-  ok(vbox.hidden, "remote tabs in the start page should be hidden when sync is not enabled");
-  ok(menulink.hidden, "link to container should be hidden when sync is not enabled");
-
-}
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+////////////////////////////////////////////////////////////////////////////////
+//// Globals
+
+Components.utils.import("resource://services-sync/main.js");
+////////////////////////////////////////////////////////////////////////////////
+//// Test(s)
+
+function test() {
+  runTests();
+}
+
+gTests.push({
+  desc: "Test sync tabs from other devices UI",
+  run: function run() {
+    if (StartUI.isStartPageVisible)
+      return;
+
+    yield addTab("about:start");
+    yield waitForCondition(() => StartUI.isStartPageVisible);
+    yield hideContextUI();
+
+    is(Weave.Status.checkSetup(), Weave.CLIENT_NOT_CONFIGURED, "Sync should be disabled on start");
+
+    let vbox = document.getElementById("start-remotetabs");
+    ok(vbox.hidden, "remote tabs in the start page should be hidden when sync is not enabled");
+
+    // check container link is hidden
+    let menulink = document.getElementById("menuitem-remotetabs");
+    ok(menulink.hidden, "link to container should be hidden when sync is not enabled");
+
+    RemoteTabsStartView._view.setUIAccessVisible(true);
+
+    // start page grid should be visible
+    ok(vbox, "remote tabs grid is present on start page");
+    is(vbox.hidden, false, "remote tabs should be visible in start page when sync is enabled");
+
+    RemoteTabsStartView._view.setUIAccessVisible(false);
+
+    ok(vbox.hidden, "remote tabs in the start page should be hidden when sync is not enabled");
+    ok(menulink.hidden, "link to container should be hidden when sync is not enabled");
+  }
+});
deleted file mode 100644
--- a/browser/metro/components/CapturePicker.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -*- Mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil; -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cr = Components.results;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-function CapturePicker() {
-  this.messageManager = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
-}
-
-CapturePicker.prototype = {
-  _file: null,
-  _mode: -1,
-  _result: -1,
-  _shown: false,
-  _title: "",
-  _type: "",
-  _window: null,
-
-  //
-  // nsICapturePicker
-  //
-  init: function(aWindow, aTitle, aMode) {
-    this._window = aWindow;
-    this._title = aTitle;
-    this._mode = aMode;
-  },
-
-  show: function() {
-    if (this._shown)
-      throw Cr.NS_ERROR_UNEXPECTED;
-
-    this._shown = true;
-
-    let res = this.messageManager.sendSyncMessage("CapturePicker:Show", { title: this._title, mode: this._mode, type: this._type })[0];
-    if (res.value)
-      this._file = res.path;
-
-    return (res.value ? Ci.nsICapturePicker.RETURN_OK : Ci.nsICapturePicker.RETURN_CANCEL);
-  },
-
-  modeMayBeAvailable: function(aMode) {
-    if (aMode != Ci.nsICapturePicker.MODE_STILL)
-      return false;
-    return true;
-  },
-
-  get file() {
-    if (this._file) { 
-      let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
-      file.initWithPath(this._file);
-      let utils = this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-      return utils.wrapDOMFile(file);
-    } else {
-      throw Cr.NS_ERROR_FAILURE;
-    }
-  },
-
-  get type() {
-    return this._type;
-  },
-
-  set type(aNewType) {
-    if (this._shown)
-      throw Cr.NS_ERROR_UNEXPECTED;
-    else 
-      this._type = aNewType;
-  },
-
-  // QI
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsICapturePicker]),
-
-  // XPCOMUtils factory
-  classID: Components.ID("{cb5a47f0-b58c-4fc3-b61a-358ee95f8238}"),
-};
-
-var components = [ CapturePicker ];
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/browser/metro/components/Makefile.in
+++ b/browser/metro/components/Makefile.in
@@ -25,17 +25,16 @@ EXTRA_PP_COMPONENTS = \
 EXTRA_COMPONENTS = \
         AlertsService.js \
         ContentPermissionPrompt.js \
         DownloadManagerUI.js \
         PromptService.js \
         ContentDispatchChooser.js \
         FormAutoComplete.js \
         LoginManagerPrompter.js \
-        CapturePicker.js \
         $(NULL)
 
 ifdef MOZ_SAFE_BROWSING
 EXTRA_COMPONENTS += SafeBrowsing.js
 endif
 
 ifdef MOZ_UPDATER
 EXTRA_COMPONENTS += UpdatePrompt.js
--- a/browser/metro/components/PromptService.js
+++ b/browser/metro/components/PromptService.js
@@ -414,17 +414,16 @@ Prompt.prototype = {
         break;
         case Ci.nsIPromptService.BUTTON_TITLE_IS_STRING :
           bTitle = titles[i];
         break;
       }
 
       if (bTitle) {
         let button = doc.createElement("button");
-        button.className = "prompt-button";
         this.setLabelForNode(button, bTitle);
         if (i == defaultButton) {
           button.setAttribute("command", "cmd_ok");
         }
         else {
           button.setAttribute("oncommand",
             "document.getElementById('prompt-confirm-dialog').PromptHelper.closeConfirm(" + i + ")");
         }
--- a/browser/metro/locales/en-US/chrome/browser.dtd
+++ b/browser/metro/locales/en-US/chrome/browser.dtd
@@ -12,16 +12,19 @@
 
 <!ENTITY appbarFindInPage2.label    "Find in page">
 <!ENTITY appbarViewOnDesktop2.label "View on desktop">
 
 <!ENTITY startTopSitesHeader.label        "Top Sites">
 <!ENTITY startBookmarksHeader.label       "Bookmarks">
 <!ENTITY startHistoryHeader.label         "Recent History">
 <!ENTITY startRemoteTabsHeader.label      "Tabs from Other Devices">
+<!-- LOCALIZATION NOTE (snappedRemoteTabsHeader.label): shortened version of startRemoteTabsHeader.label.
+     Needs to be two words or shorter to fit in narrow vertical space.-->
+<!ENTITY snappedRemoteTabsHeader.label    "Remote Tabs">
 
 <!ENTITY autocompleteResultsHeader.label  "Your Results">
 <!ENTITY autocompleteSearchesHeader.label "Internet Searches"> 
 
 <!ENTITY downloadsHeader.label     "Downloads">
 <!ENTITY downloadShowPage.label    "Go to Page">
 <!ENTITY downloadShow2.label       "Find">
 <!ENTITY downloadOpen2.label       "Open">
--- a/browser/metro/locales/en-US/chrome/sync.dtd
+++ b/browser/metro/locales/en-US/chrome/sync.dtd
@@ -1,32 +1,39 @@
 <!-- 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/. -->
 
 
+<!-- flyout header -->
 <!ENTITY syncHeader.title           "Sync">
-<!ENTITY sync.notconnected          "Not connected">
-<!ENTITY sync.connect               "Connect">
-<!ENTITY sync.connected             "Connected">
+<!-- not connected yet -->
+<!ENTITY sync.setup.description     "Access your bookmarks, passwords, and open tabs across your devices">
+<!ENTITY sync.setupbutton.label     "Set up Sync">
+<!-- sync now button -->
+<!ENTITY sync.syncNow2              "Sync now">
+<!-- device name text edit -->
 <!ENTITY sync.deviceName            "This device">
-<!ENTITY sync.disconnect            "Disconnect">
-<!ENTITY sync.syncNow2              "Sync now">
+<!-- remove this device button -->
+<!ENTITY sync.removebutton.label    "Remove this device">
+<!ENTITY sync.removewarn.note       "Your browser data on this device will remain intact, but you will no longer be able to sync with this account.">
+<!ENTITY sync.removethrobber.label  "Removing device">
 
-<!ENTITY sync.setup.title           "Connect to Sync">
+<!ENTITY sync.setup2.title          "Set up Sync">
 <!ENTITY sync.setup.pair2           "To activate, select &#x0022;Pair a device&#x0022; on your other device.">
-<!ENTITY sync.fallback              "I'm not near my computer…">
+<!ENTITY sync.fallback              "Enter or edit account information…">
 <!ENTITY sync.setup.manual          "Enter your Sync account information">
 <!ENTITY sync.account               "Account Name">
 <!ENTITY sync.password              "Password">
 <!ENTITY sync.recoveryKey           "Recovery Key">
 <!ENTITY sync.customServer          "Use custom server">
 <!ENTITY sync.serverURL             "Server URL">
-<!ENTITY sync.setup.connect         "Connect">
+<!ENTITY sync.setup.connect2        "Add device">
 <!ENTITY sync.setup.cancel          "Cancel">
+<!ENTITY sync.setup.remove          "Remove">
 <!ENTITY sync.setup.tutorial        "Show me how">
 <!ENTITY sync.setup.waiting2        "Waiting for other device…">
 
 <!ENTITY sync.pair.title            "Pair a Device">
 <!ENTITY sync.pair.button           "Pair a device">
 <!ENTITY sync.pair.description      "To activate your new device, select &#x0022;Set up Sync&#x0022; on the device.">
 <!ENTITY sync.setup.close           "Close">
 <!ENTITY sync.setup.waitingdownload "Your data is now being downloaded in the background. You can close this window at any time.">
--- a/browser/metro/locales/en-US/chrome/sync.properties
+++ b/browser/metro/locales/en-US/chrome/sync.properties
@@ -1,21 +1,24 @@
 # 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/.
 
-# Mobile Sync
+# LOCALIZATION NOTE: Used in the default os description when a new account
+# is being set up. Should be unique to Metro, so that it does not conflict
+# with Desktop. See /services/sync/modules/engines/clients.js locaName.
+sync.defaultAccountApplication=Metro %S
+
+sync.disconnectPrompt=Remove Windows 8 style %S from your Sync Account?
 
 # %S is the date and time at which the last sync successfully completed
 lastSync2.label=Last sync: %S
-lastSyncInProgress2.label=Last sync: in progress…
 
 # %S is the username logged in
 account.label=Account: %S
-notconnected.label=Not connected
 connecting.label=Connecting…
 
 notificationDisconnect.label=Your Firefox Sync account has been removed
 notificationDisconnect.button=Undo
 
 # LOCALIZATION NOTE (sync.clientUpdate, sync.remoteUpdate):
 # #1 is the "application name"
 # #2 is the "version"
--- a/browser/metro/profile/metro.js
+++ b/browser/metro/profile/metro.js
@@ -411,17 +411,16 @@ pref("app.update.showInstalledUI", false
 pref("app.update.incompatible.mode", 0);
 
 // replace newlines with spaces on paste into single-line text boxes
 pref("editor.singleLine.pasteNewlines", 2);
 
 #ifdef MOZ_SERVICES_SYNC
 // sync service
 pref("services.sync.registerEngines", "Tab,Bookmarks,Form,History,Password,Prefs");
-pref("services.sync.autoconnectDelay", 5);
 
 // prefs to sync by default
 pref("services.sync.prefs.sync.browser.startup.sessionRestore", true);
 pref("services.sync.prefs.sync.browser.tabs.warnOnClose", true);
 pref("services.sync.prefs.sync.devtools.errorconsole.enabled", true);
 pref("services.sync.prefs.sync.lightweightThemes.isThemeSelected", true);
 pref("services.sync.prefs.sync.lightweightThemes.usedThemes", true);
 pref("services.sync.prefs.sync.privacy.donottrackheader.enabled", true);
--- a/browser/metro/theme/browser.css
+++ b/browser/metro/theme/browser.css
@@ -715,16 +715,41 @@ flyoutpanel > settings:first-child {
 }
 
 /* Sync flyout pane */
 
 #sync-flyoutpanel {
   width: 400px;
 }
 
+#sync-disconnectwarntitle {
+  font-weight: bold;
+}
+
+#sync-disconnectthrobber {
+  margin-top: 25px;
+}
+
+#disconnectthrobber {
+  width: 25px;
+  height: 25px;
+}
+
+#syncdisconnectthrobber .progressContainer {
+  width: 25px;
+  height: 25px;
+  margin-right: 10px;
+}
+
+#syncdisconnectthrobber .progressBall {
+  margin: 2px;
+  width: 22px;
+  height: 22px;
+}
+
 /* About flyout pane */
 
 #about-flyoutpanel {
   width: 350px;
   background-image:url('chrome://browser/skin/images/about-footer.png');
   background-repeat: no-repeat;
   background-attachment: fixed;
   background-position: right bottom;
@@ -866,16 +891,20 @@ setting[type="radio"] > vbox {
   visibility: collapse;
 }
 
 /*tile content should be on same line in snapped view */
 #snapped-topsites-grid > richgriditem > .richgrid-item-content {
   -moz-box-orient: horizontal;
 }
 
+[viewstate="snapped"] .canSnapTiles .richgrid-item-desc {
+ -moz-margin-start: 8px;
+}
+
 /* if snapped, hide the fullscreen awesome screen, if viewstate is anything
  *  other than snapped, hide the snapped awesome screen */
 #start[viewstate="snapped"],
 #snapped-start:not([viewstate="snapped"]) {
   visibility: collapse;
 }
 
 /*Formatting for the limited horizontal space of snapped*/
@@ -1165,22 +1194,8 @@ setting[type="radio"] > vbox {
 #selectionhandle-mark3 {
   list-style-image: url("chrome://browser/skin/images/selection-monocle.png");
   border: 0px solid gray;
   padding: 0px;
   margin-top: -30px;
   margin-left: -18px;
   pointer-events: auto;
 }
-
-/* Capture picker ------------------------------------------------------------- */
-
-#capturepicker-video {
-  border: @border_width_tiny@ solid white;
-}
-
-#capturepicker-container {
-  margin: @margin_normal@;
-}
-
-#capturepicker-container.vertical {
-  height: 330px;
-}
new file mode 100644
--- /dev/null
+++ b/browser/metro/theme/cssthrobber.css
@@ -0,0 +1,102 @@
+/* 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/. */
+
+%filter substitution
+%include defines.inc
+
+.progressContainer {
+}
+
+.progressBall {
+  position: absolute;
+  opacity: 0;
+  transform: rotate(225deg);
+  animation: orbit 7.15s infinite;
+}
+
+.progressBall:nth-child(1) {
+  animation-delay: 1.56s;
+}
+
+.progressBall:nth-child(2) {
+  animation-delay: 0.31s;
+}
+
+.progressBall:nth-child(3) {
+  animation-delay: 0.62s;
+}
+
+.progressBall:nth-child(4) {
+  animation-delay: 0.94s;
+}
+
+.progressBall:nth-child(5) {
+  animation-delay: 1.25s;
+}
+
+.progressBall:nth-child(1)::after,
+.progressBall:nth-child(2)::after,
+.progressBall:nth-child(3)::after,
+.progressBall:nth-child(4)::after,
+.progressBall:nth-child(5)::after {
+  content: "";
+  display: block;
+  width: 5px;
+  height: 5px;
+  border-radius: 5px;
+  position: absolute;
+  background: #0095dd;
+  left:0px;
+  top:0px;
+}
+
+
+@keyframes orbit {
+  0% {
+    opacity: 1;
+    z-index:99;
+    transform: rotate(180deg);
+    animation-timing-function: ease-out;
+  }
+
+  7% {
+    opacity: 1;
+    transform: rotate(300deg);
+    animation-timing-function: linear;
+    origin:0%;
+  }
+
+  30% {
+    opacity: 1;
+    transform:rotate(410deg);
+    animation-timing-function: ease-in-out;
+    origin:7%;
+  }
+
+  39% {
+    opacity: 1;
+    transform: rotate(645deg);
+    animation-timing-function: linear;
+    origin:30%;
+  }
+
+  70% {
+    opacity: 1;
+    transform: rotate(770deg);
+    animation-timing-function: ease-out;
+    origin:39%;
+  }
+
+  75% {
+    opacity: 1;
+    transform: rotate(900deg);
+    animation-timing-function: ease-out;
+    origin:70%;
+  }
+
+  76%, 100% {
+    opacity: 0;
+    transform:rotate(900deg);
+  }
+}
--- a/browser/metro/theme/jar.mn
+++ b/browser/metro/theme/jar.mn
@@ -4,16 +4,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
 chrome.jar:
 % skin browser classic/1.0 %skin/
   skin/aboutPage.css                        (aboutPage.css)
   skin/about.css                            (about.css)
 * skin/flyoutpanel.css                      (flyoutpanel.css)
+* skin/cssthrobber.css                      (cssthrobber.css)
 * skin/browser.css                          (browser.css)
 * skin/content.css                          (content.css)
   skin/config.css                           (config.css)
 * skin/forms.css                            (forms.css)
 * skin/platform.css                         (platform.css)
   skin/touchcontrols.css                    (touchcontrols.css)
   skin/netError.css                         (netError.css)
 % override chrome://global/skin/about.css chrome://browser/skin/about.css
--- a/browser/metro/theme/platform.css
+++ b/browser/metro/theme/platform.css
@@ -567,17 +567,17 @@ richgriditem[customColor] .richgrid-icon
 /* hide icon if there is an image background */
 .richgrid-icon-container[customImage] {
   visibility: collapse;
 }
 
 .richgrid-item-desc {
   width: @tile_width@;
   font-size: @metro_font_normal@;
-  margin-left: 0px !important;
+  margin-left: 0px;
   padding-left: 0px !important;
 }
 
 .richgrid-item-content[customImage] > .richgrid-item-desc {
   background: hsla(0,2%,98%,.95);
   /*margin-bottom: 0px;
   margin-right: 0px;*/
   margin: 0px;
--- a/browser/modules/SignInToWebsite.jsm
+++ b/browser/modules/SignInToWebsite.jsm
@@ -131,35 +131,26 @@ this.SignInToWebsiteUX = {
   },
 
   // Private
 
   /**
    * Return the chrome window and <browser> for the given outer window ID.
    */
   _getUIForWindowID: function(aWindowID) {
-    let someWindow = Services.wm.getMostRecentWindow("navigator:browser");
-    if (!someWindow) {
-      Logger.reportError("SignInToWebsiteUX", "no window");
-      return [null, null];
-    }
-
-    let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIDOMWindowUtils);
-    let content = windowUtils.getOuterWindowWithId(aWindowID);
-
+    let content = Services.wm.getOuterWindowWithId(aWindowID);
     if (content) {
       let browser = content.QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIWebNavigation)
                            .QueryInterface(Ci.nsIDocShell).chromeEventHandler;
       let chromeWin = browser.ownerDocument.defaultView;
       return [chromeWin, browser];
     }
+
     Logger.reportError("SignInToWebsiteUX", "no content");
-
     return [null, null];
   },
 
   /**
    * Open UI with a content frame displaying aAuthURI so that the user can authenticate with their
    * IDP.  Then tell Identity.jsm the identifier for the window so that it knows that the DOM API
    * calls are for this authentication flow.
    */
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -1,30 +1,34 @@
 /* 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";
 
-this.EXPORTED_SYMBOLS = ["Social"];
+this.EXPORTED_SYMBOLS = ["Social", "OpenGraphBuilder"];
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SocialService",
   "resource://gre/modules/SocialService.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
   "resource://gre/modules/commonjs/sdk/core/promise.js");
 
+XPCOMUtils.defineLazyServiceGetter(this, "unescapeService",
+                                   "@mozilla.org/feed-unescapehtml;1",
+                                   "nsIScriptableUnescapeHTML");
+
 // Add a pref observer for the enabled state
 function prefObserver(subject, topic, data) {
   let enable = Services.prefs.getBoolPref("social.enabled");
   if (enable && !Social.provider) {
     Social.provider = Social.defaultProvider;
   } else if (!enable && Social.provider) {
     Social.provider = null;
   }
@@ -429,8 +433,123 @@ SocialErrorListener.prototype = {
       }.bind(this));
     }
   },
 
   onProgressChange: function SPL_onProgressChange() {},
   onStatusChange: function SPL_onStatusChange() {},
   onSecurityChange: function SPL_onSecurityChange() {},
 };
+
+
+this.OpenGraphBuilder = {
+  getData: function(browser) {
+    let res = {
+      url: this._validateURL(browser, browser.currentURI.spec),
+      title: browser.contentDocument.title,
+      previews: []
+    };
+    this._getMetaData(browser, res);
+    this._getLinkData(browser, res);
+    this._getPageData(browser, res);
+    return res;
+  },
+
+  _getMetaData: function(browser, o) {
+    // query for standardized meta data
+    let els = browser.contentDocument
+                  .querySelectorAll("head > meta[property], head > meta[name]");
+    if (els.length < 1)
+      return;
+    let url;
+    for (let el of els) {
+      let value = el.getAttribute("content")
+      if (!value)
+        continue;
+      value = unescapeService.unescape(value.trim());
+      switch (el.getAttribute("property") || el.getAttribute("name")) {
+        case "title":
+        case "og:title":
+          o.title = value;
+          break;
+        case "description":
+        case "og:description":
+          o.description = value;
+          break;
+        case "og:site_name":
+          o.siteName = value;
+          break;
+        case "medium":
+        case "og:type":
+          o.medium = value;
+          break;
+        case "og:video":
+          url = this._validateURL(browser, value);
+          if (url)
+            o.source = url;
+          break;
+        case "og:url":
+          url = this._validateURL(browser, value);
+          if (url)
+            o.url = url;
+          break;
+        case "og:image":
+          url = this._validateURL(browser, value);
+          if (url)
+            o.previews.push(url);
+          break;
+      }
+    }
+  },
+
+  _getLinkData: function(browser, o) {
+    let els = browser.contentDocument
+                  .querySelectorAll("head > link[rel], head > link[id]");
+    for (let el of els) {
+      let url = el.getAttribute("href");
+      if (!url)
+        continue;
+      url = this._validateURL(browser, unescapeService.unescape(url.trim()));
+      switch (el.getAttribute("rel") || el.getAttribute("id")) {
+        case "shorturl":
+        case "shortlink":
+          o.shortUrl = url;
+          break;
+        case "canonicalurl":
+        case "canonical":
+          o.url = url;
+          break;
+        case "image_src":
+          o.previews.push(url);
+          break;
+      }
+    }
+  },
+
+  // scrape through the page for data we want
+  _getPageData: function(browser, o) {
+    if (o.previews.length < 1)
+      o.previews = this._getImageUrls(browser);
+  },
+
+  _validateURL: function(browser, url) {
+    let uri = Services.io.newURI(browser.currentURI.resolve(url), null, null);
+    if (["http", "https", "ftp", "ftps"].indexOf(uri.scheme) < 0)
+      return null;
+    uri.userPass = "";
+    return uri.spec;
+  },
+
+  _getImageUrls: function(browser) {
+    let l = [];
+    let els = browser.contentDocument.querySelectorAll("img");
+    for (let el of els) {
+      let content = el.getAttribute("src");
+      if (content) {
+        l.push(this._validateURL(browser, unescapeService.unescape(content)));
+        // we don't want a billion images
+        if (l.length > 5)
+          break;
+      }
+    }
+    return l;
+  }
+};
--- a/browser/modules/webappsUI.jsm
+++ b/browser/modules/webappsUI.jsm
@@ -82,29 +82,23 @@ this.webappsUI = {
         browser.pinTab(tab);
         browser.selectedTab = tab;
         ss.setTabValue(tab, "appOrigin", aOrigin);
       }
     }
   },
 
   _getBrowserForId: function(aId) {
-    let someWindow = Services.wm.getMostRecentWindow(null);
-
-    if (someWindow) {
-      let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                                  .getInterface(Ci.nsIDOMWindowUtils);
-      let content = windowUtils.getOuterWindowWithId(aId);
-      if (content) {
-        let browser = content.QueryInterface(Ci.nsIInterfaceRequestor)
-                      .getInterface(Ci.nsIWebNavigation)
-                      .QueryInterface(Ci.nsIDocShell).chromeEventHandler;
-        let win = browser.ownerDocument.defaultView;
-        return [win, browser];
-      }
+    let content = Services.wm.getOuterWindowWithId(aId);
+    if (content) {
+      let browser = content.QueryInterface(Ci.nsIInterfaceRequestor)
+                    .getInterface(Ci.nsIWebNavigation)
+                    .QueryInterface(Ci.nsIDocShell).chromeEventHandler;
+      let win = browser.ownerDocument.defaultView;
+      return [win, browser];
     }
 
     return [null, null];
   },
 
   doInstall: function(aData, aBrowser, aWindow) {
     let bundle = aWindow.gNavigatorBundle;
 
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -52,20 +52,17 @@ this.webrtcUI = {
         });
       }
     }
     return activeStreams;
   }
 }
 
 function getBrowserForWindowId(aWindowID) {
-  let someWindow = Services.wm.getMostRecentWindow(null);
-  let contentWindow = someWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIDOMWindowUtils)
-                                .getOuterWindowWithId(aWindowID);
+  let contentWindow = Services.wm.getOuterWindowWithId(aWindowID);
   return contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIWebNavigation)
                       .QueryInterface(Ci.nsIDocShell)
                       .chromeEventHandler;
 }
 
 function handleRequest(aSubject, aTopic, aData) {
   let {windowID: windowID, callID: callID} = JSON.parse(aData);
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1436,16 +1436,74 @@ richlistitem[type~="action"][actiontype=
   list-style-image: url("moz-icon://stock/gtk-stop?size=menu");
 }
 
 /* Popup blocker button */
 #page-report-button {
   list-style-image: url("chrome://browser/skin/Info.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 */
+  transition: height 100ms ease-out, width 100ms ease-out;
+}
+
+#social-share-button {
+  list-style-image: url("chrome://browser/skin/social/share-button.png");
+}
+
+#social-share-button[open],
+#social-share-button:hover:active {
+  list-style-image: url("chrome://browser/skin/social/share-button-active.png");
+}
+
+.social-share-toolbar {
+  border-right: 1px solid #dedede;
+  background: linear-gradient(to bottom, rgba(247,247,247,.99), rgba(247,247,247,.95));
+}
+
+#social-share-provider-buttons {
+  border-right: 1px solid #fbfbfb;
+  padding: 6px;
+}
+
+#social-share-provider-buttons > .share-provider-button {
+  padding: 6px;
+  margin: 0;
+  border: none;
+  border-radius: 2px;
+}
+
+#social-share-provider-buttons > .share-provider-button[checked],
+#social-share-provider-buttons > .share-provider-button:active {
+  padding: 5px;
+  border: 1px solid #b5b5b8;
+  box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.2);
+}
+
+#social-share-provider-buttons > .share-provider-button[checked] {
+  background: linear-gradient(to bottom, #d9d9d9, #e3e3e3);
+}
+
+#social-share-provider-buttons > .share-provider-button > .toolbarbutton-text {
+  display: none;
+}
+#social-share-provider-buttons > .share-provider-button > .toolbarbutton-icon {
+  width: 16px;
+  min-height: 16px;
+  max-height: 16px;
+}
+
 /* social recommending panel */
 
 #social-mark-button {
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 /* bookmarks menu-button */
 
@@ -2189,22 +2247,24 @@ toolbar[iconsize="small"] .toolbarbutton
 
 .chat-titlebar[selected] {
   background-color: #f0f0f0;
 }
 
 .chatbar-button {
   -moz-appearance: none;
   background-color: #d9d9d9;
+  background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
 }
 
 .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));
 }
 
new file mode 100644
--- /dev/null
+++ b/browser/themes/linux/devtools/scratchpad.css
@@ -0,0 +1,5 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+%include ../../shared/devtools/scratchpad.inc.css
\ No newline at end of file
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -100,16 +100,18 @@ browser.jar:
   skin/classic/browser/preferences/Options-sync.png   (preferences/Options-sync.png)
 #endif
 * skin/classic/browser/preferences/preferences.css    (preferences/preferences.css)
   skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
   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/share-button.png        (social/share-button.png)
+  skin/classic/browser/social/share-button-active.png (social/share-button-active.png)
   skin/classic/browser/social/chat-close.png          (social/chat-close.png)
   skin/classic/browser/tabbrowser/connecting.png      (tabbrowser/connecting.png)
   skin/classic/browser/tabbrowser/loading.png         (tabbrowser/loading.png)
   skin/classic/browser/tabbrowser/tab.png             (tabbrowser/tab.png)
   skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png)
   skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabview/edit-light.png         (tabview/edit-light.png)
   skin/classic/browser/tabview/search.png             (tabview/search.png)
@@ -166,16 +168,17 @@ browser.jar:
   skin/classic/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png   (devtools/breadcrumbs/rtl-start-selected-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start.png                    (devtools/breadcrumbs/rtl-start.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
   skin/classic/browser/devtools/splitview.css         (devtools/splitview.css)
   skin/classic/browser/devtools/styleeditor.css       (devtools/styleeditor.css)
   skin/classic/browser/devtools/debugger.css          (devtools/debugger.css)
 * skin/classic/browser/devtools/profiler.css          (devtools/profiler.css)
   skin/classic/browser/devtools/netmonitor.css        (devtools/netmonitor.css)
+* skin/classic/browser/devtools/scratchpad.css        (devtools/scratchpad.css)
   skin/classic/browser/devtools/magnifying-glass.png  (devtools/magnifying-glass.png)
   skin/classic/browser/devtools/option-icon.png       (devtools/option-icon.png)
   skin/classic/browser/devtools/itemToggle.png        (devtools/itemToggle.png)
   skin/classic/browser/devtools/itemArrow-rtl.png     (devtools/itemArrow-rtl.png)
   skin/classic/browser/devtools/itemArrow-ltr.png     (devtools/itemArrow-ltr.png)
   skin/classic/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
   skin/classic/browser/devtools/inspect-button.png    (devtools/inspect-button.png)
   skin/classic/browser/devtools/dropmarker.png        (devtools/dropmarker.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7df438db014c265c35da304c4a846f5e34c46e4b
GIT binary patch
literal 1341
zc%17D@N?(olHy`uVBq!ia0vp@K+MO%1|+}KPrC%9BuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFso#SM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnpCL0(UDwvt+8Jd`y
znHlOR7#SEE=^Fr%nXaLUm8qGPk+}jCC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DRmzV36
z8|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQixgCnn{Wme?vO
z!Mu=L05>+T7#d8#0MoBXEYLU9Gtfs;=<ADLX>KlDb#X~hY8rmk#UYgisro^w#rdU0
z$-sz9QwC`+uyQU+O)SYT3dzsUfrVl~Mt(_taYlZDf^)E$f`)Hma%LV#KohLP*VoE3
zuec;JFFDoI#a0O@qL-POV&!UVZffXaVeV*V=xAu@YUJc%Zf0TPYT@c^VruE^VgS?Y
zlAm0fo0?Yw)0=|OYk^ZQC^0~Erxs<FrKY$Q<>xAZJ#CeV+byQJ-2%~@g4-=-IQ8lS
z9ixvH)i5Do`T;TF2^YwLC;iksV0teCCTu}3&W{WXjO#sJ978H@CH?sS-=5iUMt^@l
zZ-;urjU!nT1Vlvcs3<9Y5;$=^AyI+h$IqX=5s{J03yO>DnTzb1H?j!Z@iH+nCBAv{
z=5$MIt3RV@A>+;aj*oOKM4FFeTUuBwQdLzI|M&a*`Drs}{<Ico&`mtF$WdTLf}pr~
z_>88eLso%-fsqRgw56qQ`@6XvyDu@TVct~+t3+LX{{C%Krd%mxXK!Ebz##OS^UL-8
z1&Q^6CXA*P1w}=Aj9Cu^g@kt9y>w|)>f>X*_Y~?Ga(|vXbm$XzhH!*1cYxu9vk@mw
zpO)t4xyA3m8lQfC-rfbfcHR2&{r&x#0}K`Hn_D|OU&`N5ThJEi(7MurbHeQZe|~-K
zX3jXUeRcTyeIeoD^EtoVp1nSPf6<?xpV^;iZBTP7;4wCM!LX5|BQZZ;e(mbj)w!Ra
zo$YeC+`Dw?()8CaUmDJ}sl4?2@$vpg+w<?QJJ?ZcXlSU&%-np^%F0UC%gd`h{p>7J
zR*~s7Utdj)@bU3cobZ-mGbihblP6gj{=VY!G4ucS?ryb+MhRcX{)QMfFTse*QU<IB
pQqt1tH9tSON}rhSKAoMzfZ@*fm$u(Mb{+v0Xr8WqF6*2UngDoR-GKlA
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c5298c143eaaa74773f5066766f923ef076a74ca
GIT binary patch
literal 1346
zc%17D@N?(olHy`uVBq!ia0vp@K+MO%1|+}KPrC%9BuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFso#SM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnpCL0(UDwvt+8Jd`y
znHlOR7#SEE=^Fr%nXaLUm8qGPk+}jCC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DRmzV36
z8|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQixgCnn{Wme?vO
z!Mu=L05>+T7#d8#0MoBXEYLU9Gtfs;=<ADLX>KlDb#X~hY8rmk#UYgisro^w#rdU0
z$-sz9QwC`+uyQU+O)SYT3dzsUfrVl~Mt(_taYlZDf^)E$f`)Hma%LV#KohLP*VoE3
zuec;JFFDoI#a0O@qL-POV&!UVZffXaVeDvT=xAu@YUJc%Zf0TPYT@c^VruE^VgS?Y
zlAm0fo0?Yw)0=|OYl2fRC^0~Erxs<FrKY$Q<>xAZJ#CeV+bxE;-2%~@g4-=dIQ8lS
z9ixvH)i5Do`T;TF2^YwLC;iksV0teCChUK8@4qlGFmCa5aSW-r)f2Sen<-IZU;MqF
z(Slz^&TO+Wb(~d_!MUjIh+>~o%%Y8Fb&GNYoL24CX#c}3l`}!?c$Wf)YWp!IriUkt
z&%assT)Cx3DZb)i_5Jsi^S&Sd9@v%`@VG)n=%K3TE!Ffksl$sduF&9cI-0dLP0;I(
zM9Y$!IrqL-?X?XFoXBPHUtrq8Iw2mm^>_2O%cl1}*=c`3$M<ry-|}Kp5w1{+zS&!E
z=GewwZ;kid7;&ce-}g6V)j}=CAsj1LWjS^4^;>>e=!{48$BG)RF46wu!rUxO;VVO4
zt-PD(EpX9C?Q%onjDA5Oj?a42Ukfl>FZeg%{PWdct7;D>ZTxaV$L9QgeovVL8T0Rb
z`TaNBZvOkJsgYX)H0Dh6TDoLeri+6j%ahUv`?L=7E!fgG@3+g!`|r8=+MRQ^MxB3H
z@PlK9_?8pO{*6n7g?!^A%y_>~a@LzZ`QxweTcdKBHlOKORM9gd*F>tjYtfHYS6`hg
zs4hQzbJp2sx_a9;_L$F@cs7lFlTQ4CTa_ClVt&SD9=Y`Li;zcg#Hr++G5cIzvE5Uw
x_@rF-cTT5E)43EQ>AQL6eHEXc|6R_&%rJfLnFU)u#2o~cYM!osF6*2UngDMq@oNA8
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1650,16 +1650,72 @@ window[tabsontop="false"] richlistitem[t
   }
 
   #page-report-button:hover:active,
   #page-report-button[open="true"] {
     -moz-image-region: rect(0, 64px, 32px, 32px);
   }
 }
 
+/* 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 */
+  transition: height 100ms ease-out, width 100ms ease-out;
+}
+
+#social-share-button {
+  list-style-image: url("chrome://browser/skin/social/share-button.png");
+}
+
+#social-share-button[open],
+#social-share-button:hover:active {
+  list-style-image: url("chrome://browser/skin/social/share-button-active.png");
+}
+
+.social-share-toolbar {
+  border-right: 1px solid #dedede;
+  background: linear-gradient(to bottom, rgba(247,247,247,.99), rgba(247,247,247,.95));
+}
+
+#social-share-provider-buttons {
+  border-right: 1px solid #fbfbfb;
+  padding: 6px;
+}
+
+#social-share-provider-buttons > .share-provider-button {
+  padding: 6px;
+  margin: 0;
+  border: none;
+  border-radius: 2px;
+}
+
+#social-share-provider-buttons > .share-provider-button[checked],
+#social-share-provider-buttons > .share-provider-button:active {
+  padding: 5px;
+  border: 1px solid #b5b5b8;
+  box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.2);
+}
+
+#social-share-provider-buttons > .share-provider-button[checked] {
+  background: linear-gradient(to bottom, #d9d9d9, #e3e3e3);
+}
+
+#social-share-provider-buttons > .share-provider-button > .toolbarbutton-text {
+  display: none;
+}
+#social-share-provider-buttons > .share-provider-button > .toolbarbutton-icon {
+  width: 16px;
+  min-height: 16px;
+  max-height: 16px;
+}
+
 /* social recommending panel */
 
 #social-mark-button {
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 /* bookmarks menu-button */
 
@@ -3623,16 +3679,20 @@ toolbarbutton.chevron > .toolbarbutton-m
 }
 #social-toolbar-item > .toolbarbutton-1:-moz-locale-dir(rtl):first-child,
 #social-toolbar-item > .toolbarbutton-1:-moz-locale-dir(ltr):last-child {
   margin-right: 4px;
   border-top-right-radius: 3px;
   border-bottom-right-radius: 3px;
 }
 
+#social-toolbar-item > toolbaritem {
+  margin: 0;
+}
+
 #social-provider-button {
   -moz-image-region: rect(0, 16px, 16px, 0);
   list-style-image: url(chrome://browser/skin/social/services-16.png);
 }
 
 @media (min-resolution: 2dppx) {
   #social-provider-button {
     list-style-image: url(chrome://browser/skin/social/services-16@2x.png);
@@ -3751,42 +3811,72 @@ toolbar[mode="icons"] > *|* > .toolbarbu
   margin: 4px;
   -moz-margin-start: 0;
 }
 
 .social-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
-.social-panel-frame {
+/* fixup rounded corners for osx panels */
+.social-panel > .social-panel-frame {
   border-radius: inherit;
 }
 
+#social-share-panel {
+  margin-top: 3px;
+  max-height: 600px;
+  min-height: 100px;
+  max-width: 800px;
+  min-width: 300px;
+}
+
+.social-share-frame {
+  border-top-left-radius: none;
+  border-bottom-left-radius: none;
+  border-top-right-radius: inherit;
+  border-bottom-right-radius: inherit;
+}
+
+#social-share-panel > .social-share-toolbar {
+  border-top-left-radius: inherit;
+  border-bottom-left-radius: inherit;
+}
+
+#social-share-provider-buttons {
+  border-top-left-radius: inherit;
+  border-bottom-left-radius: inherit;
+}
+
 /* === 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));
 }
 
 .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));
+  border-top-left-radius: @toolbarbuttonCornerRadius@;
+  border-top-right-radius: @toolbarbuttonCornerRadius@;
+}
+
+.chatbar-button:hover,
 .chatbar-button[open="true"] {
   background-color: #f0f0f0;
 }
 
-.chatbar-button[activity] {
+.chatbar-button[activity]:not([open]) {
   background-image: radial-gradient(circle farthest-corner at center 2px, rgb(254,254,255) 3%, rgba(210,235,255,0.9) 12%, rgba(148,205,253,0.6) 30%, rgba(148,205,253,0.2) 70%);
 }
 
 chatbox {
   border-top-left-radius: @toolbarbuttonCornerRadius@;
   border-top-right-radius: @toolbarbuttonCornerRadius@;
 }
 
new file mode 100644
--- /dev/null
+++ b/browser/themes/osx/devtools/scratchpad.css
@@ -0,0 +1,5 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+%include ../../shared/devtools/scratchpad.inc.css
\ No newline at end of file
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -167,16 +167,18 @@ browser.jar:
 * skin/classic/browser/preferences/preferences.css          (preferences/preferences.css)
   skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
   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-16@2x.png            (social/services-16@2x.png)
   skin/classic/browser/social/services-64.png               (social/services-64.png)
   skin/classic/browser/social/services-64@2x.png            (social/services-64@2x.png)
+  skin/classic/browser/social/share-button.png              (social/share-button.png)
+  skin/classic/browser/social/share-button-active.png       (social/share-button-active.png)
   skin/classic/browser/social/chat-close.png                             (social/chat-close.png)
   skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon.png             (tabbrowser/alltabs-box-bkgnd-icon.png)
   skin/classic/browser/tabbrowser/newtab.png                             (tabbrowser/newtab.png)
   skin/classic/browser/tabbrowser/newtab@2x.png                          (tabbrowser/newtab@2x.png)
   skin/classic/browser/tabbrowser/connecting.png                         (tabbrowser/connecting.png)
   skin/classic/browser/tabbrowser/connecting@2x.png                      (tabbrowser/connecting@2x.png)
   skin/classic/browser/tabbrowser/loading.png                            (tabbrowser/loading.png)
   skin/classic/browser/tabbrowser/loading@2x.png                         (tabbrowser/loading@2x.png)
@@ -257,16 +259,17 @@ browser.jar:
   skin/classic/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png   (devtools/breadcrumbs/rtl-start-selected-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start.png                    (devtools/breadcrumbs/rtl-start.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
   skin/classic/browser/devtools/splitview.css               (devtools/splitview.css)
   skin/classic/browser/devtools/styleeditor.css             (devtools/styleeditor.css)
 * skin/classic/browser/devtools/debugger.css                (devtools/debugger.css)
 * skin/classic/browser/devtools/profiler.css                (devtools/profiler.css)
   skin/classic/browser/devtools/netmonitor.css              (devtools/netmonitor.css)
+* skin/classic/browser/devtools/scratchpad.css              (devtools/scratchpad.css)
   skin/classic/browser/devtools/magnifying-glass.png        (devtools/magnifying-glass.png)
   skin/classic/browser/devtools/option-icon.png             (devtools/option-icon.png)
   skin/classic/browser/devtools/itemToggle.png              (devtools/itemToggle.png)
   skin/classic/browser/devtools/itemArrow-rtl.png           (devtools/itemArrow-rtl.png)
   skin/classic/browser/devtools/itemArrow-ltr.png           (devtools/itemArrow-ltr.png)
   skin/classic/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
   skin/classic/browser/devtools/inspect-button.png          (devtools/inspect-button.png)
   skin/classic/browser/devtools/dropmarker.png              (devtools/dropmarker.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7df438db014c265c35da304c4a846f5e34c46e4b
GIT binary patch
literal 1341
zc%17D@N?(olHy`uVBq!ia0vp@K+MO%1|+}KPrC%9BuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFso#SM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnpCL0(UDwvt+8Jd`y
znHlOR7#SEE=^Fr%nXaLUm8qGPk+}jCC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DRmzV36
z8|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQixgCnn{Wme?vO
z!Mu=L05>+T7#d8#0MoBXEYLU9Gtfs;=<ADLX>KlDb#X~hY8rmk#UYgisro^w#rdU0
z$-sz9QwC`+uyQU+O)SYT3dzsUfrVl~Mt(_taYlZDf^)E$f`)Hma%LV#KohLP*VoE3
zuec;JFFDoI#a0O@qL-POV&!UVZffXaVeV*V=xAu@YUJc%Zf0TPYT@c^VruE^VgS?Y
zlAm0fo0?Yw)0=|OYk^ZQC^0~Erxs<FrKY$Q<>xAZJ#CeV+byQJ-2%~@g4-=-IQ8lS
z9ixvH)i5Do`T;TF2^YwLC;iksV0teCCTu}3&W{WXjO#sJ978H@CH?sS-=5iUMt^@l
zZ-;urjU!nT1Vlvcs3<9Y5;$=^AyI+h$IqX=5s{J03yO>DnTzb1H?j!Z@iH+nCBAv{
z=5$MIt3RV@A>+;aj*oOKM4FFeTUuBwQdLzI|M&a*`Drs}{<Ico&`mtF$WdTLf}pr~
z_>88eLso%-fsqRgw56qQ`@6XvyDu@TVct~+t3+LX{{C%Krd%mxXK!Ebz##OS^UL-8
z1&Q^6CXA*P1w}=Aj9Cu^g@kt9y>w|)>f>X*_Y~?Ga(|vXbm$XzhH!*1cYxu9vk@mw
zpO)t4xyA3m8lQfC-rfbfcHR2&{r&x#0}K`Hn_D|OU&`N5ThJEi(7MurbHeQZe|~-K
zX3jXUeRcTyeIeoD^EtoVp1nSPf6<?xpV^;iZBTP7;4wCM!LX5|BQZZ;e(mbj)w!Ra
zo$YeC+`Dw?()8CaUmDJ}sl4?2@$vpg+w<?QJJ?ZcXlSU&%-np^%F0UC%gd`h{p>7J
zR*~s7Utdj)@bU3cobZ-mGbihblP6gj{=VY!G4ucS?ryb+MhRcX{)QMfFTse*QU<IB
pQqt1tH9tSON}rhSKAoMzfZ@*fm$u(Mb{+v0Xr8WqF6*2UngDoR-GKlA
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c5298c143eaaa74773f5066766f923ef076a74ca
GIT binary patch
literal 1346
zc%17D@N?(olHy`uVBq!ia0vp@K+MO%1|+}KPrC%9BuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFso#SM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnpCL0(UDwvt+8Jd`y
znHlOR7#SEE=^Fr%nXaLUm8qGPk+}jCC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DRmzV36
z8|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQixgCnn{Wme?vO
z!Mu=L05>+T7#d8#0MoBXEYLU9Gtfs;=<ADLX>KlDb#X~hY8rmk#UYgisro^w#rdU0
z$-sz9QwC`+uyQU+O)SYT3dzsUfrVl~Mt(_taYlZDf^)E$f`)Hma%LV#KohLP*VoE3
zuec;JFFDoI#a0O@qL-POV&!UVZffXaVeDvT=xAu@YUJc%Zf0TPYT@c^VruE^VgS?Y
zlAm0fo0?Yw)0=|OYl2fRC^0~Erxs<FrKY$Q<>xAZJ#CeV+bxE;-2%~@g4-=dIQ8lS
z9ixvH)i5Do`T;TF2^YwLC;iksV0teCChUK8@4qlGFmCa5aSW-r)f2Sen<-IZU;MqF
z(Slz^&TO+Wb(~d_!MUjIh+>~o%%Y8Fb&GNYoL24CX#c}3l`}!?c$Wf)YWp!IriUkt
z&%assT)Cx3DZb)i_5Jsi^S&Sd9@v%`@VG)n=%K3TE!Ffksl$sduF&9cI-0dLP0;I(
zM9Y$!IrqL-?X?XFoXBPHUtrq8Iw2mm^>_2O%cl1}*=c`3$M<ry-|}Kp5w1{+zS&!E
z=GewwZ;kid7;&ce-}g6V)j}=CAsj1LWjS^4^;>>e=!{48$BG)RF46wu!rUxO;VVO4
zt-PD(EpX9C?Q%onjDA5Oj?a42Ukfl>FZeg%{PWdct7;D>ZTxaV$L9QgeovVL8T0Rb
z`TaNBZvOkJsgYX)H0Dh6TDoLeri+6j%ahUv`?L=7E!fgG@3+g!`|r8=+MRQ^MxB3H
z@PlK9_?8pO{*6n7g?!^A%y_>~a@LzZ`QxweTcdKBHlOKORM9gd*F>tjYtfHYS6`hg
zs4hQzbJp2sx_a9;_L$F@cs7lFlTQ4CTa_ClVt&SD9=Y`Li;zcg#Hr++G5cIzvE5Uw
x_@rF-cTT5E)43EQ>AQL6eHEXc|6R_&%rJfLnFU)u#2o~cYM!osF6*2UngDMq@oNA8
--- a/browser/themes/shared/browser.inc
+++ b/browser/themes/shared/browser.inc
@@ -1,3 +1,3 @@
 %filter substitution
 
-%define primaryToolbarButtons #back-button, #forward-button, #reload-button, #stop-button, #home-button, #print-button, #downloads-button, #downloads-indicator, #history-button, #bookmarks-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-in-button, #sync-button, #feed-button, #alltabs-button, #tabview-button, #webrtc-status-button
+%define primaryToolbarButtons #back-button, #forward-button, #reload-button, #stop-button, #home-button, #print-button, #downloads-button, #downloads-indicator, #history-button, #bookmarks-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-in-button, #sync-button, #feed-button, #alltabs-button, #tabview-button, #webrtc-status-button, #social-share-button
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/devtools/scratchpad.inc.css
@@ -0,0 +1,10 @@
+%if 0
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+%endif
+
+#scratchpad-sidebar > tabs {
+  height: 0;
+  border: none;
+}
--- a/browser/themes/shared/social/chat.inc.css
+++ b/browser/themes/shared/social/chat.inc.css
@@ -68,47 +68,37 @@
 .chat-frame {
   padding: 0;
   margin: 0;
   overflow: hidden;
 }
 
 .chatbar-button {
   list-style-image: url("chrome://browser/skin/social/services-16.png");
-  border: none;
   margin: 0;
   padding: 2px;
   height: 21px;
   width: 21px;
-  border-top: 1px solid #ccc;
-  -moz-border-end: 1px solid #ccc;
+  border: 1px solid #ccc;
+  border-bottom: none;
 }
 
 @media (min-resolution: 2dppx) {
   .chatbar-button {
     list-style-image: url("chrome://browser/skin/social/services-16@2x.png");
   }
 }
 
 .chatbar-button > menupopup > .menuitem-iconic > .menu-iconic-left > .menu-iconic-icon {
   width: auto;
   height: auto;
   max-height: 16px;
   max-width: 16px;
 }
 
-.chatbar-button > .toolbarbutton-icon {
-  opacity: .6;
-}
-
-.chatbar-button:hover > .toolbarbutton-icon,
-.chatbar-button[open="true"] > .toolbarbutton-icon {
-  opacity: 1;
-}
-
 .chatbar-button[open="true"] {
   box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
 }
 
 .chatbar-button > .toolbarbutton-text,
 .chatbar-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1708,16 +1708,103 @@ richlistitem[type~="action"][actiontype=
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 #page-report-button:hover:active,
 #page-report-button[open="true"] {
   -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
+
+/* social share panel */
+
+#social-share-panel > iframe {
+  background: linear-gradient(to bottom, #f0f4f7, #fafbfc);
+  width: 300px;
+  height: 150px;
+}
+
+#social-share-button {
+  list-style-image: url(chrome://browser/skin/social/share-button.png);
+  -moz-image-region: rect(0, 16px, 16px, 0);
+}
+
+.social-share-toolbar {
+  border-right: 1px solid #e2e5e8;
+  background: linear-gradient(to bottom, #ffffff, #f5f7fa);
+}
+
+#social-share-provider-buttons {
+  padding: 6px;
+}
+
+#social-share-provider-buttons > .share-provider-button {
+  -moz-appearance: none;
+  padding: 5px;
+  margin: 1px;
+  border: none;
+  background: none;
+  border-radius: 2px;
+}
+
+#social-share-provider-buttons > .share-provider-button[checked="true"]:not([disabled="true"]),
+#social-share-provider-buttons > .share-provider-button:hover,
+#social-share-provider-buttons > .share-provider-button:active {
+  padding: 4px;
+  border: 1px solid #aeb8c1;
+  box-shadow: inset 1px 1px 1px rgba(10, 31, 51, 0.1);
+}
+
+#social-share-provider-buttons > .share-provider-button[checked="true"]:not([disabled="true"]) {
+  background: linear-gradient(to bottom, rgba(230,232,234,.65), #d2d5d9);
+}
+
+#social-share-provider-buttons > .share-provider-button > .toolbarbutton-text {
+  display: none;
+}
+#social-share-provider-buttons > .share-provider-button > .toolbarbutton-icon {
+  width: 16px;
+  min-height: 16px;
+  max-height: 16px;
+}
+
+/* fixup corners for share panel */
+.social-panel > .social-panel-frame {
+  border-radius: inherit;
+}
+
+#social-share-panel {
+  max-height: 600px;
+  min-height: 100px;
+  max-width: 800px;
+  min-width: 300px;
+}
+
+.social-share-frame {
+  background: linear-gradient(to bottom, #f0f4f7, #fafbfc);
+  width: 330px;
+  height: 150px;
+  border-top-left-radius: none;
+  border-bottom-left-radius: none;
+  border-top-right-radius: inherit;
+  border-bottom-right-radius: inherit;
+  /* we resize our panels dynamically, make it look nice */
+  transition: height 100ms ease-out, width 100ms ease-out;
+}
+
+#social-share-panel > .social-share-toolbar {
+  border-top-left-radius: inherit;
+  border-bottom-left-radius: inherit;
+}
+
+#social-share-provider-buttons {
+  border-top-left-radius: inherit;
+  border-bottom-left-radius: inherit;
+}
+
 /* social recommending panel */
 
 #social-mark-button {
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 /* bookmarks menu-button */
 
@@ -2909,22 +2996,24 @@ toolbarbutton.bookmark-item[dragover="tr
 
 .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));
 }
 
 .chatbar-button > .toolbarbutton-icon {
   -moz-margin-end: 0;
 }
 
+.chatbar-button:hover,
 .chatbar-button[open="true"] {
   background-color: #dae3f0;
 }
 
 .chatbar-button[activity]:not([open="true"]) {
   background-image: radial-gradient(circle farthest-corner at center 3px, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 40%, rgba(127,179,255,0.5) 80%, rgba(127,179,255,0.25));
 }
 
new file mode 100644
--- /dev/null
+++ b/browser/themes/windows/devtools/scratchpad.css
@@ -0,0 +1,5 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+%include ../../shared/devtools/scratchpad.inc.css
\ No newline at end of file
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -120,16 +120,18 @@ browser.jar:
 #endif
         skin/classic/browser/preferences/saveFile.png                (preferences/saveFile.png)
 *       skin/classic/browser/preferences/preferences.css             (preferences/preferences.css)
         skin/classic/browser/preferences/in-content/preferences.css  (preferences/in-content/preferences.css)
         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/share-button.png                 (social/share-button.png)
+        skin/classic/browser/social/share-button-active.png          (social/share-button-active.png)
         skin/classic/browser/social/chat-close.png                   (social/chat-close.png)
         skin/classic/browser/tabbrowser/newtab.png                   (tabbrowser/newtab.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.png                      (tabbrowser/tab.png)
         skin/classic/browser/tabbrowser/tab-arrow-left.png           (tabbrowser/tab-arrow-left.png)
         skin/classic/browser/tabbrowser/tab-arrow-left-inverted.png  (tabbrowser/tab-arrow-left-inverted.png)
@@ -194,16 +196,17 @@ browser.jar:
         skin/classic/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png   (devtools/breadcrumbs/rtl-start-selected-pressed.png)
         skin/classic/browser/devtools/breadcrumbs/rtl-start.png                    (devtools/breadcrumbs/rtl-start.png)
         skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
         skin/classic/browser/devtools/splitview.css                 (devtools/splitview.css)
         skin/classic/browser/devtools/styleeditor.css               (devtools/styleeditor.css)
         skin/classic/browser/devtools/debugger.css                  (devtools/debugger.css)
 *       skin/classic/browser/devtools/profiler.css                  (devtools/profiler.css)
         skin/classic/browser/devtools/netmonitor.css                (devtools/netmonitor.css)
+*       skin/classic/browser/devtools/scratchpad.css                (devtools/scratchpad.css)
         skin/classic/browser/devtools/magnifying-glass.png          (devtools/magnifying-glass.png)
         skin/classic/browser/devtools/option-icon.png               (devtools/option-icon.png)
         skin/classic/browser/devtools/itemToggle.png                (devtools/itemToggle.png)
         skin/classic/browser/devtools/itemArrow-rtl.png             (devtools/itemArrow-rtl.png)
         skin/classic/browser/devtools/itemArrow-ltr.png             (devtools/itemArrow-ltr.png)
         skin/classic/browser/devtools/background-noise-toolbar.png  (devtools/background-noise-toolbar.png)
         skin/classic/browser/devtools/inspect-button.png            (devtools/inspect-button.png)
         skin/classic/browser/devtools/dropmarker.png                (devtools/dropmarker.png)
@@ -367,16 +370,18 @@ browser.jar:
 #endif
         skin/classic/aero/browser/preferences/saveFile.png           (preferences/saveFile-aero.png)
 *       skin/classic/aero/browser/preferences/preferences.css        (preferences/preferences.css)
         skin/classic/aero/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
         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/share-button.png            (social/share-button.png)
+        skin/classic/aero/browser/social/share-button-active.png     (social/share-button-active.png)
         skin/classic/aero/browser/social/chat-close.png              (social/chat-close.png)
         skin/classic/aero/browser/tabbrowser/newtab.png              (tabbrowser/newtab.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.png                 (tabbrowser/tab.png)
         skin/classic/aero/browser/tabbrowser/tab-arrow-left.png      (tabbrowser/tab-arrow-left.png)
         skin/classic/aero/browser/tabbrowser/tab-arrow-left-inverted.png (tabbrowser/tab-arrow-left-inverted.png)
@@ -441,16 +446,17 @@ browser.jar:
         skin/classic/aero/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png   (devtools/breadcrumbs/rtl-start-selected-pressed.png)
         skin/classic/aero/browser/devtools/breadcrumbs/rtl-start.png                    (devtools/breadcrumbs/rtl-start.png)
         skin/classic/aero/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
         skin/classic/aero/browser/devtools/splitview.css             (devtools/splitview.css)
         skin/classic/aero/browser/devtools/styleeditor.css           (devtools/styleeditor.css)
         skin/classic/aero/browser/devtools/debugger.css              (devtools/debugger.css)
 *       skin/classic/aero/browser/devtools/profiler.css              (devtools/profiler.css)
         skin/classic/aero/browser/devtools/netmonitor.css            (devtools/netmonitor.css)
+*       skin/classic/aero/browser/devtools/scratchpad.css            (devtools/scratchpad.css)
         skin/classic/aero/browser/devtools/magnifying-glass.png      (devtools/magnifying-glass.png)
         skin/classic/aero/browser/devtools/option-icon.png           (devtools/option-icon.png)
         skin/classic/aero/browser/devtools/itemToggle.png            (devtools/itemToggle.png)
         skin/classic/aero/browser/devtools/itemArrow-rtl.png         (devtools/itemArrow-rtl.png)
         skin/classic/aero/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
         skin/classic/aero/browser/devtools/itemArrow-ltr.png         (devtools/itemArrow-ltr.png)
         skin/classic/aero/browser/devtools/inspect-button.png        (devtools/inspect-button.png)
         skin/classic/aero/browser/devtools/dropmarker.png            (devtools/dropmarker.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e819a740bf2e8a837d5f09e2e3c84b159acd508f
GIT binary patch
literal 1469
zc%17D@N?(olHy`uVBq!ia0vp^{6H+g!3HExhN-duDajJoh?3y^w370~qErUQl>DSr
z1<%~X^wgl##FWaylc_cg49qH-ArU1JzCKpT`MG+DAT@dwxdjX$U}IlVkeHmETB4AY
znx2_wtMq>NekFy>6kDZmQ(pt$0_W6>OpmIf)Zi+=kmRcDWXlvKdpiZ23M-%ixv3?I
z3Kh9IdBs*0wn|`gt$=Khu)dN4SV>8?trEmh5xxNm&iO^D3Z{C-y2%EHh6-k8dWI&Z
zW@d&u3PuKoM*0RoWTtCqVr6P(Wn``Z1xi5Mic-?7f?V97b^&>|N*N_31y=g{<>lpi
z<;HsXMd|v6mX?+vGmMOMfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZ_=!pRr6smX
zN-!_v7Ql_oD~1LWFu?RH5)1SV^$hfp6#Dw&SDKp(S6y5Zl$wTLb#X{#L8^XGYH@yP
zQ8F;%(v(4(3#^=rQWHz^i$e1Ab6}wukda@KU!0L&px_*Arl8@Qn4Fmh63_(e@b$Iw
z%quQQ%u7!7bg@+eis)r#rdS!f8W_2no0vM989Eypx*9pTn44LcxLUY6o0wWUyBNUq
zy5uL9=BDPA!1Sgd^qS$+3rY+S-Kj;HWvMA{Mftf3U{70R;&zKMZnr@6rr>sq2~NHG
zK*#8#MKw$an0`P^c)|s8;7LC<518JIfC+o<3Na%F1}1$^7srr_TT>>V&lhqOIbL42
zQioe)Q>)W%QGta^9oC9wbcAFER~ba`A9MD7d{V-H-k<V4)t8#t`K9(|bl6JVp0Q<V
z?vx2SmpBA76VvN|Ut>^=;`ICUN$q~+{GaFcoKc9q-kI2LUU-^QlOb?bUCl*>|IBkX
zU3fP2`1kz$GBX7q=cb3Bh1Wef-22CL{p?i7PtG~B+Zdh;Z49V-oK`lm)apr~v~q(F
zUkTd@Hq9F4*%5K4b&g2;E)?Qqj|dI>=pf<Hx9G&`^3T`PCx0{u*9qmj{CV>m%dV{X
zNjDQN%rs~)=Chu>XZt>x-3CuLih2JLw@!96(_Wh~YuTx;lvh@h>l>#3o&0Vod-=6T
zjOTo(?Z3Kecl%Q}lP8-GY+A5#)`AmV9L1}i^Gw(%vESsa_tVXtoYxGyem>sy<IB_C
zuNI%RS+3E=py=IkfwgDry}68YTsWQ@eO3&A=G9VoYwg)-4Oi9A-@6jL@qvcpi&-2j
zwoaO}vMz1V5c<p8{X|Up9)r2vqNZkzu1zXlEh?v1=q5b+x%yDQi;2fs7K^i|E_l7(
z()#P+qt|O~1-{kX-MxO9QqO(sw6a?nO`k2!w!W?XQ}%lEzAXm1Oup|AesHTiQ4@dp
z*!}l1YtOUpEm_^GD%ky`@a^)b{B7Lv+F!r8=DpdzFtGdFFNqC~9mO|`<*v2ein#dg
z^!@S!PncgEn|Rp3UgFE4z8|+va)nH)`FrHWJ9TH469rZ;#1_`qp6v4$N!rf**R+n)
ZfMFl|(+8(bmd^ndsGhEVF6*2UngHQAGEx8l
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..931874dc36ca2057d91682fd6d69af3e42356ed1
GIT binary patch
literal 1437
zc%17D@N?(olHy`uVBq!ia0vp^{6H+g!3HExhN-duDajJoh?3y^w370~qErUQl>DSr
z1<%~X^wgl##FWaylc_cg49qH-ArU1JzCKpT`MG+DAT@dwxdjX$U}IlVkeHmETB4AY
znx2_wtMq>NekFy>6kDZmQ(pt$0_W6>OpmIf)Zi+=kmRcDWXlvKdpiZ23M-%ixv3?I
z3Kh9IdBs*0wn|`gt$=Khu)dN4SV>8?trEmh5xxNm&iO^D3Z{C-y2%EHh6-k8dWI&Z
zW@d&u3PuKoM*0RoWTtCqVr6P(Wn``Z1xi5Mic-?7f?V97b^&>|N*N_31y=g{<>lpi
z<;HsXMd|v6mX?+vGmMOMfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZ_=!pRr6smX
zN-!_v7Ql_oD~1LWFu?RH5)1SV^$hfp6#Dw&SDKp(S6y5Zl$wTLb#X{#L8^XGYH@yP
zQ8F;%(v(4(3#^=rQWHz^i$e1Ab6}wukda@KU!0L&px_*Arl8@Qn4Fmh63_(e@b$Iw
z%quQQ%u7!7bg@+eis)r#rdU~+n3$MbSUNkJ89Eypx*9pTn44LcxLUY6o0wWUyBNUq
zy5uL9=BDPA!1Sgd^t#~G3rY+S-Kj;HWvMA{Mftf3U{70R;&zK8Znr@6rr>sq6HdMQ
zK*#8#MKw$an0`P^c)|s8;7LC<518JIfC;<AP~bcR0~5cei(^Q|t)xHy|JyTjHb{5;
zZ2X}tP@k&gxcI}&&*H9AzpnYUfX%?5AxDkL+obf1^r@^_^8znyWGVVTo7qsAThPpl
z_4pF0c~;eRyA~`EFcud-@sy`YfoXmkpMscC`4`UGf1g6z=d8IS$LHrKZ)R4ugDGYf
ztGr#+q1R#pp`Sm0e;*>7yY}b*f5tzG3kwbZxN^nkFsd0Qzf00&Uw>gKP<+{|tk-J<
z1w?`pQd7l~(w`?JB&Ho)8L6eXIAHbO{8M3ha&pq8rB{{3(%iP++x!2;iF4<U9XNOJ
z;DIxzx)w^RFl{>f`N74>vt3+Vo<4mlx^DWDWoPY5-h`-Wa~m_OUpV>Z%^RLGK0X?=
ze%Al_p}8#iVbG^HM^E20GBUcesc6&t+poQ(#MegT|9*SB+|g`-+JySZ#%)H1#)~ta
zT{9}4_51Pj^-h6>oNj`JoNQuzdU<hi^YZ=Y+t;sOxatZ+$-AxZ?dzGCU)wV)Pdck`
zzkYA|%M76j)7qELd2wdbrJtv-Mb-ZNb@jukv$xA`NxjM~+H`6Ey1Tn(e|&sh-ZJH^
z{K6lWI)AOAB<*8&SB6W=%isSlZ~x!G>SolQKCW*!zkj?u-S=$m<wpx&{WE@aLgG+d
zBIm{b|BWj>ygY4ZnQu(B4R~W9P|uzuIKfS!u31~xxbFWyXDbD@y-#0X&tGsvr`uOn
pd7jQmjw49{-?UfcYA`4qU~oP3NvK6gj{{U-db;|#taD0e0sxHR7<vEz
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -88,16 +88,17 @@ include $(topsrcdir)/config/rules.mk
 TARGET_DEPTH = ..
 include $(srcdir)/automation-build.mk
 
 _LEAKTEST_DIR = $(DEPTH)/_leaktest
 
 _LEAKTEST_FILES =    \
 		automation.py \
 		automationutils.py \
+		$(topsrcdir)/testing/profiles/prefs_general.js \
 		leaktest.py \
 		bloatcycle.html \
 		$(topsrcdir)/build/pgo/server-locations.txt \
 		$(topsrcdir)/build/pgo/favicon.ico \
 		$(topsrcdir)/build/pgo/blueprint/sample.html \
 		$(topsrcdir)/build/pgo/blueprint/elements.html \
 		$(topsrcdir)/build/pgo/blueprint/forms.html \
 		$(topsrcdir)/build/pgo/blueprint/grid.html \
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -38,16 +38,18 @@ except:
             'mozlog']
     for dep in deps:
         module = os.path.join(mozbase, dep)
         if module not in sys.path:
             sys.path.append(module)
     import mozcrash
 # ---------------------------------------------------------------
 
+_DEFAULT_PREFERENCE_FILE = os.path.join(SCRIPT_DIR, 'prefs_general.js')
+
 _DEFAULT_WEB_SERVER = "127.0.0.1"
 _DEFAULT_HTTP_PORT = 8888
 _DEFAULT_SSL_PORT = 4443
 _DEFAULT_WEBSOCKET_PORT = 9988
 
 # from nsIPrincipal.idl
 _APP_STATUS_NOT_INSTALLED = 0
 _APP_STATUS_INSTALLED     = 1
@@ -428,154 +430,41 @@ class Automation(object):
 
       manifestDir = os.path.join(webappsDir, app['name'])
       os.mkdir(manifestDir)
 
       manifestFile = open(os.path.join(manifestDir, "manifest.webapp"), "a")
       manifestFile.write(manifest)
       manifestFile.close()
 
-  def initializeProfile(self, profileDir, extraPrefs=[],
-                        useServerLocations=False,
-                        initialProfile=None):
+  def initializeProfile(self, profileDir,
+                              extraPrefs=None,
+                              useServerLocations=False,
+                              initialProfile=None,
+                              prefsPath=_DEFAULT_PREFERENCE_FILE):
     " Sets up the standard testing profile."
 
+    extraPrefs = extraPrefs or []
     prefs = []
     # Start with a clean slate.
     shutil.rmtree(profileDir, True)
 
     if initialProfile:
       shutil.copytree(initialProfile, profileDir)
     else:
       os.mkdir(profileDir)
 
     # Set up permissions database
     locations = self.readLocations()
     self.setupPermissionsDatabase(profileDir,
       {'allowXULXBL':[(l.host, 'noxul' not in l.options) for l in locations]});
 
-    # NOTE: For refactoring purposes we are temporarily storing these prefs
-    #       in two locations. If you update a pref below, please also update
-    #       it in source/testing/profiles/prefs_general.js.
-    #       See bug 830430 for more details.
-    part = """\
-user_pref("browser.console.showInPanel", true);
-user_pref("browser.dom.window.dump.enabled", true);
-user_pref("browser.firstrun.show.localepicker", false);
-user_pref("browser.firstrun.show.uidiscovery", false);
-user_pref("browser.startup.page", 0); // use about:blank, not browser.startup.homepage
-user_pref("browser.ui.layout.tablet", 0); // force tablet UI off
-user_pref("dom.allow_scripts_to_close_windows", true);
-user_pref("dom.disable_open_during_load", false);
-user_pref("dom.experimental_forms", true); // on for testing
-user_pref("dom.experimental_forms_range", true); // on for testing
-user_pref("dom.max_script_run_time", 0); // no slow script dialogs
-user_pref("hangmonitor.timeout", 0); // no hang monitor
-user_pref("dom.max_chrome_script_run_time", 0);
-user_pref("dom.popup_maximum", -1);
-user_pref("dom.send_after_paint_to_content", true);
-user_pref("dom.successive_dialog_time_limit", 0);
-user_pref("signed.applets.codebase_principal_support", true);
-user_pref("browser.shell.checkDefaultBrowser", false);
-user_pref("shell.checkDefaultClient", false);
-user_pref("browser.warnOnQuit", false);
-user_pref("accessibility.typeaheadfind.autostart", false);
-user_pref("javascript.options.showInConsole", true);
-user_pref("devtools.errorconsole.enabled", true);
-user_pref("devtools.debugger.remote-port", 6023);
-user_pref("layout.debug.enable_data_xbl", true);
-user_pref("browser.EULA.override", true);
-user_pref("javascript.options.jit_hardening", true);
-user_pref("gfx.color_management.force_srgb", true);
-user_pref("network.manage-offline-status", false);
-user_pref("dom.min_background_timeout_value", 1000);
-user_pref("test.mousescroll", true);
-user_pref("security.default_personal_cert", "Select Automatically"); // Need to client auth test be w/o any dialogs
-user_pref("network.http.prompt-temp-redirect", false);
-user_pref("media.cache_size", 100);
-user_pref("media.volume_scale", "0.01");
-user_pref("security.warn_viewing_mixed", false);
-user_pref("app.update.enabled", false);
-user_pref("app.update.staging.enabled", false);
-user_pref("browser.panorama.experienced_first_run", true); // Assume experienced
-user_pref("dom.w3c_touch_events.enabled", 1);
-user_pref("dom.undo_manager.enabled", true);
-user_pref("dom.webcomponents.enabled", true);
-// Set a future policy version to avoid the telemetry prompt.
-user_pref("toolkit.telemetry.prompted", 999);
-user_pref("toolkit.telemetry.notifiedOptOut", 999);
-// Existing tests assume there is no font size inflation.
-user_pref("font.size.inflation.emPerLine", 0);
-user_pref("font.size.inflation.minTwips", 0);
-
-// Only load extensions from the application and user profile
-// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
-user_pref("extensions.enabledScopes", 5);
-// Disable metadata caching for installed add-ons by default
-user_pref("extensions.getAddons.cache.enabled", false);
-// Disable intalling any distribution add-ons
-user_pref("extensions.installDistroAddons", false);
-
-user_pref("geo.wifi.uri", "http://%(server)s/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs");
-user_pref("geo.wifi.testing", true);
-user_pref("geo.ignore.location_filter", true);
-
-user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others
-
-// Make url-classifier updates so rare that they won't affect tests
-user_pref("urlclassifier.updateinterval", 172800);
-// Point the url-classifier to the local testing server for fast failures
-user_pref("browser.safebrowsing.gethashURL", "http://%(server)s/safebrowsing-dummy/gethash");
-user_pref("browser.safebrowsing.keyURL", "http://%(server)s/safebrowsing-dummy/newkey");
-user_pref("browser.safebrowsing.updateURL", "http://%(server)s/safebrowsing-dummy/update");
-// Point update checks to the local testing server for fast failures
-user_pref("extensions.update.url", "http://%(server)s/extensions-dummy/updateURL");
-user_pref("extensions.update.background.url", "http://%(server)s/extensions-dummy/updateBackgroundURL");
-user_pref("extensions.blocklist.url", "http://%(server)s/extensions-dummy/blocklistURL");
-user_pref("extensions.hotfix.url", "http://%(server)s/extensions-dummy/hotfixURL");
-// Turn off extension updates so they don't bother tests
-user_pref("extensions.update.enabled", false);
-// Make sure opening about:addons won't hit the network
-user_pref("extensions.webservice.discoverURL", "http://%(server)s/extensions-dummy/discoveryURL");
-// Make sure AddonRepository won't hit the network
-user_pref("extensions.getAddons.maxResults", 0);
-user_pref("extensions.getAddons.get.url", "http://%(server)s/extensions-dummy/repositoryGetURL");
-user_pref("extensions.getAddons.getWithPerformance.url", "http://%(server)s/extensions-dummy/repositoryGetWithPerformanceURL");
-user_pref("extensions.getAddons.search.browseURL", "http://%(server)s/extensions-dummy/repositoryBrowseURL");
-user_pref("extensions.getAddons.search.url", "http://%(server)s/extensions-dummy/repositorySearchURL");
-// Make sure that opening the plugins check page won't hit the network
-user_pref("plugins.update.url", "http://%(server)s/plugins-dummy/updateCheckURL");
-
-// Existing tests don't wait for the notification button security delay
-user_pref("security.notification_enable_delay", 0);
-
-// Make enablePrivilege continue to work for test code. :-(
-user_pref("security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", true);
-
-// In the default configuration, we bypass XBL scopes (a security feature) for
-// domains whitelisted for remote XUL, so that intranet apps and such continue
-// to work without major rewrites. However, we also use the whitelist mechanism
-// to run our XBL tests in automation, in which case we really want to be testing
-// the configuration that we ship to users without special whitelisting. So we
-// use an additional pref here to allow automation to use the "normal" behavior.
-user_pref("dom.use_xbl_scopes_for_remote_xul", true);
-
-// Get network events.
-user_pref("network.activity.blipIntervalMilliseconds", 250);
-
-// Don't allow the Data Reporting service to prompt for policy acceptance.
-user_pref("datareporting.policy.dataSubmissionPolicyBypassAcceptance", true);
-
-// Point Firefox Health Report at a local server. We don't care if it actually
-// works. It just can't hit the default production endpoint.
-user_pref("datareporting.healthreport.documentServerURI", "http://%(server)s/healthreport/");
-
-// Make sure CSS error reporting is enabled for tests
-user_pref("layout.css.report_errors", true);
-""" % { "server" : self.webServer + ":" + str(self.httpPort) }
+    f = open(prefsPath, 'r')
+    part = f.read() % {"server" : "%s:%s" % (self.webServer, self.httpPort)}
+    f.close()
     prefs.append(part)
 
     if useServerLocations:
       # We need to proxy every server but the primary one.
       origins = ["'%s://%s:%s'" % (l.scheme, l.host, l.port)
                 for l in filter(lambda l: "primary" not in l.options, locations)]
       origins = ", ".join(origins)
 
@@ -614,26 +503,25 @@ function FindProxyForURL(url, host)
     return 'PROXY %(remote)s:%(sslport)s';
   return 'DIRECT';
 }""" % { "origins": origins,
          "remote":  self.webServer,
          "httpport":self.httpPort,
          "sslport": self.sslPort }
       pacURL = "".join(pacURL.splitlines())
 
-      part += """
+      part = """
 user_pref("network.proxy.type", 2);
 user_pref("network.proxy.autoconfig_url", "%(pacURL)s");
 
 user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless to others
 """ % {"pacURL": pacURL}
-      prefs.append(part)
     else:
       part = 'user_pref("network.proxy.type", 0);\n'
-      prefs.append(part)
+    prefs.append(part)
 
     for v in extraPrefs:
       thispref = v.split("=", 1)
       if len(thispref) < 2:
         print "Error: syntax error in --setpref=" + v
         sys.exit(1)
       part = 'user_pref("%s", %s);\n' % (thispref[0], thispref[1])
       prefs.append(part)
new file mode 100644
--- /dev/null
+++ b/build/defines.sh
@@ -0,0 +1,3 @@
+# Define indicating that this build is prior to one of the early betas. To be
+# unset mid-way through the beta cycle.
+EARLY_BETA_OR_EARLIER=1
--- a/build/dumbmake-dependencies
+++ b/build/dumbmake-dependencies
@@ -42,11 +42,27 @@ toolkit/library
   image/build
     image
   intl/build
     intl
   media
   profile
   services
   startupcache
-browser
+browser/app
+  browser/base
+  browser/components
+  browser/devtools
+  browser/locales
+  browser/modules
+  browser/themes
+  toolkit
+  toolkit/components
+  toolkit/content
+  toolkit/crashreporter
+  toolkit/devtools
+  toolkit/forgetaboutsite
+  toolkit/identity
+  toolkit/modules
   toolkit/mozapps/extensions
-  toolkit/content
+  toolkit/profile
+  toolkit/themes
+  toolkit/webapps
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -17,37 +17,80 @@ SEARCH_PATHS = [
     'python/psutil',
     'python/which',
     'build/pymake',
     'config',
     'other-licenses/ply',
     'xpcom/idl-parser',
     'testing',
     'testing/xpcshell',
+    'testing/marionette/client',
+    'testing/marionette/client/marionette',
     'testing/mozbase/mozcrash',
+    'testing/mozbase/mozdevice',
+    'testing/mozbase/mozfile',
+    'testing/mozbase/mozhttpd',
     'testing/mozbase/mozlog',
+    'testing/mozbase/moznetwork',
     'testing/mozbase/mozprocess',
-    'testing/mozbase/mozfile',
+    'testing/mozbase/mozprofile',
+    'testing/mozbase/mozrunner',
     'testing/mozbase/mozinfo',
 ]
 
 # Individual files providing mach commands.
 MACH_MODULES = [
     'addon-sdk/mach_commands.py',
     'layout/tools/reftest/mach_commands.py',
     'python/mach/mach/commands/commandinfo.py',
     'python/mozboot/mozboot/mach_commands.py',
     'python/mozbuild/mozbuild/config.py',
     'python/mozbuild/mozbuild/mach_commands.py',
     'python/mozbuild/mozbuild/frontend/mach_commands.py',
+    'testing/marionette/mach_commands.py',
     'testing/mochitest/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
     'tools/mach_commands.py',
 ]
 
+
+CATEGORIES = {
+    'build': {
+        'short': 'Build Commands',
+        'long': 'Interact with the build system',
+        'priority': 80,
+    },
+    'post-build': {
+        'short': 'Post-build Commands',
+        'long': 'Common actions performed after completing a build.',
+        'priority': 70,
+    },
+    'testing': {
+        'short': 'Testing',
+        'long': 'Run tests.',
+        'priority': 60,
+    },
+    'devenv': {
+        'short': 'Development Environment',
+        'long': 'Set up and configure your development environment.',
+        'priority': 50,
+    },
+    'build-dev': {
+        'short': 'Low-level Build System Interaction',
+        'long': 'Interact with specific parts of the build system.',
+        'priority': 20,
+    },
+    'misc': {
+        'short': 'Potpourri',
+        'long': 'Potent potables and assorted snacks.',
+        'priority': 10,
+    }
+}
+
+
 def bootstrap(topsrcdir, mozilla_dir=None):
     if mozilla_dir is None:
         mozilla_dir = topsrcdir
 
     # Ensure we are running Python 2.7+. We put this check here so we generate a
     # user-friendly error message rather than a cryptic stack trace on module
     # import.
     if sys.version_info[0] != 2 or sys.version_info[1] < 7:
@@ -57,11 +100,16 @@ def bootstrap(topsrcdir, mozilla_dir=Non
 
     try:
         import mach.main
     except ImportError:
         sys.path[0:0] = [os.path.join(mozilla_dir, path) for path in SEARCH_PATHS]
         import mach.main
 
     mach = mach.main.Mach(topsrcdir)
+    for category, meta in CATEGORIES.items():
+        mach.define_category(category, meta['short'], meta['long'],
+            meta['priority'])
+
     for path in MACH_MODULES:
         mach.load_commands_from_file(os.path.join(mozilla_dir, path))
+
     return mach
--- a/build/mobile/b2gautomation.py
+++ b/build/mobile/b2gautomation.py
@@ -115,26 +115,16 @@ class B2GRemoteAutomation(Automation):
                 crashed = mozcrash.check_for_crashes(local_dump_dir, symbolsPath, test_name=self.lastTestSeen)
             except:
                 traceback.print_exc()
             finally:
                 shutil.rmtree(local_dump_dir)
                 self._devicemanager.removeDir(remote_dump_dir)
         return crashed
 
-    def initializeProfile(self,  profileDir, extraPrefs=[],
-                          useServerLocations=False,
-                          initialProfile=None):
-        # add b2g specific prefs
-        extraPrefs.extend(["browser.manifestURL='dummy (bug 772307)'"])
-        return Automation.initializeProfile(self, profileDir,
-                                            extraPrefs,
-                                            useServerLocations,
-                                            initialProfile)
-
     def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
         # if remote profile is specified, use that instead
         if (self._remoteProfile):
             profileDir = self._remoteProfile
 
         cmd, args = Automation.buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs)
 
         return app, args
--- a/build/pgo/Makefile.in
+++ b/build/pgo/Makefile.in
@@ -25,16 +25,17 @@ else
 browser_path = \"$(TARGET_DIST)/$(MOZ_APP_NAME)/$(PROGRAM)\"
 endif
    
 # Stuff to make a build with a profile
 
 _PGO_FILES = 	\
   automation.py \
   $(topsrcdir)/build/automationutils.py \
+  $(topsrcdir)/testing/profiles/prefs_general.js \
   profileserver.py \
   genpgocert.py \
   index.html \
   server-locations.txt \
   favicon.ico \
   $(NULL)
 
 genpgocert.py: genpgocert.py.in
new file mode 100644
--- /dev/null
+++ b/build/pymake/tests/default-goal-set-first.mk
@@ -0,0 +1,7 @@
+.DEFAULT_GOAL := default
+
+not-default:
+	@echo TEST-FAIL did not run default rule
+
+default:
+	@echo TEST-PASS
--- a/caps/src/nsSecurityManagerFactory.cpp
+++ b/caps/src/nsSecurityManagerFactory.cpp
@@ -60,18 +60,19 @@ static const JSFunctionSpec PrivilegeMan
 
 /*
  * "Steal" calls to netscape.security.PrivilegeManager.enablePrivilege,
  * et al. so that code that worked with 4.0 can still work.
  */
 NS_IMETHODIMP
 nsSecurityNameSet::InitializeNameSet(nsIScriptContext* aScriptContext)
 {
-    AutoPushJSContext cx(aScriptContext->GetNativeContext());
-    JS::Rooted<JSObject*> global(cx, JS_ObjectToInnerObject(cx, JS_GetGlobalObject(cx)));
+    AutoJSContext cx;
+    JS::Rooted<JSObject*> global(cx, aScriptContext->GetNativeGlobal());
+    JSAutoCompartment ac(cx, global);
 
     /*
      * Find Object.prototype's class by walking up the global object's
      * prototype chain.
      */
     JS::Rooted<JSObject*> obj(cx, global);
     JS::Rooted<JSObject*> proto(cx);
     JSAutoRequest ar(cx);
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1281,22 +1281,16 @@ ifneq (,$(DIST_SUBDIR)$(XPI_NAME)$(LIBXU
 PREF_DIR = defaults/preferences
 endif
 
 # on win32, pref files need CRLF line endings... see bug 206029
 ifeq (WINNT,$(OS_ARCH))
 PREF_PPFLAGS += --line-endings=crlf
 endif
 
-# Set a flag that can be used in pref files to disable features if
-# we are not building for Aurora or Nightly.
-ifeq (,$(findstring a,$(GRE_MILESTONE)))
-PREF_PPFLAGS += -DRELEASE_BUILD
-endif
-
 ifneq ($(PREF_JS_EXPORTS),)
 ifndef NO_DIST_INSTALL
 PREF_JS_EXPORTS_PATH := $(FINAL_TARGET)/$(PREF_DIR)
 PREF_JS_EXPORTS_FLAGS := $(PREF_PPFLAGS)
 PP_TARGETS += PREF_JS_EXPORTS
 endif
 endif
 
--- a/config/writemozinfo.py
+++ b/config/writemozinfo.py
@@ -75,16 +75,19 @@ def build_dict(env=os.environ):
         d["bits"] = 32
     # other CPUs will wind up with unknown bits
 
     # debug
     d["debug"] = 'MOZ_DEBUG' in env and env['MOZ_DEBUG'] == '1'
 
     # crashreporter
     d["crashreporter"] = 'MOZ_CRASHREPORTER' in env and env['MOZ_CRASHREPORTER'] == '1'
+
+    # asan
+    d["asan"] = 'MOZ_ASAN' in env and env['MOZ_ASAN'] == '1'
     return d
 
 def write_json(file, env=os.environ):
     """
     Write JSON data about the configuration specified in |env|
     to |file|, which may be a filename or file-like object.
     See build_dict for information about what  environment variables are used,
     and what keys are produced.
--- a/configure.in
+++ b/configure.in
@@ -200,16 +200,20 @@ if test -n "$gonkdir" ; then
         ARCH_DIR=arch-x86
         ;;
     esac
 
     case "$ANDROID_VERSION" in
     15)
         GONK_INCLUDES="-I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/frameworks/base/include -I$gonkdir/frameworks/base/services/camera -I$gonkdir/frameworks/base/include/media/stagefright -I$gonkdir/frameworks/base/include/media/stagefright/openmax -I$gonkdir/frameworks/base/media/libstagefright/rtsp -I$gonkdir/frameworks/base/media/libstagefright/include -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib -I$gonkdir/dalvik/libnativehelper/include/nativehelper"
         MOZ_B2G_BT=1
+        MOZ_B2G_CAMERA=1
+        MOZ_OMX_DECODER=1
+        AC_DEFINE(MOZ_OMX_DECODER)
+        AC_SUBST(MOZ_OMX_DECODER)
         ;;
     17)
         GONK_INCLUDES="-I$gonkdir/frameworks/native/include"
         ;;
     *)
         AC_MSG_ERROR([Unsupported platform version: $ANDROID_VERSION])
         ;;
     esac
@@ -3898,16 +3902,36 @@ dnl set GRE_MILESTONE
 dnl ========================================================
 if test -n "$LIBXUL_SDK"; then
     GRE_MILESTONE=`$PYTHON "$_topsrcdir"/config/printconfigsetting.py "$LIBXUL_DIST"/bin/platform.ini Build Milestone`
 else
     GRE_MILESTONE=`tail -n 1 "$_topsrcdir"/config/milestone.txt 2>/dev/null || tail -1 "$_topsrcdir"/config/milestone.txt`
 fi
 AC_SUBST(GRE_MILESTONE)
 
+# set RELEASE_BUILD and NIGHTLY_BUILD variables depending on the cycle we're in
+# The logic works like this:
+# - if we have "a1" in GRE_MILESTONE, we're building Nightly (define NIGHTLY_BUILD)
+# - otherwise, if we have "a" in GRE_MILESTONE, we're building Nightly or Aurora
+# - otherwise, we're building Release/Beta (define RELEASE_BUILD)
+case "$GRE_MILESTONE" in
+  *a1*)
+      NIGHTLY_BUILD=1
+      AC_DEFINE(NIGHTLY_BUILD)
+      ;;
+  *a*)
+      ;;
+  *)
+      RELEASE_BUILD=1
+      AC_DEFINE(RELEASE_BUILD)
+      ;;
+esac
+AC_SUBST(NIGHTLY_BUILD)
+AC_SUBST(RELEASE_BUILD)
+
 dnl system libevent Support
 dnl ========================================================
 MOZ_ARG_WITH_STRING(system-libevent,
 [  --with-system-libevent[=PFX]
                           Use system libevent [installed at prefix PFX]],
     LIBEVENT_DIR=$withval)
 
 _SAVE_CFLAGS=$CFLAGS
@@ -4343,25 +4367,37 @@ MOZ_ARG_ENABLE_STRING([update-channel],
 
 if test -z "$MOZ_UPDATE_CHANNEL"; then
     MOZ_UPDATE_CHANNEL=default
 fi
 AC_DEFINE_UNQUOTED(MOZ_UPDATE_CHANNEL, $MOZ_UPDATE_CHANNEL)
 AC_SUBST(MOZ_UPDATE_CHANNEL)
 
 # Allow the application to influence configure with a confvars.sh script.
-
 AC_MSG_CHECKING([if app-specific confvars.sh exists])
 if test -f "${srcdir}/${MOZ_BUILD_APP}/confvars.sh" ; then
   AC_MSG_RESULT([${srcdir}/${MOZ_BUILD_APP}/confvars.sh])
   . "${srcdir}/${MOZ_BUILD_APP}/confvars.sh"
 else
   AC_MSG_RESULT([no])
 fi
 
+# Allow influencing configure with a defines.sh script.
+. "${srcdir}/build/defines.sh"
+
+# If we're not building a release build, define EARLY_BETA_OR_EARLIER if it is
+# set in defines.sh
+if test "$BUILDING_RELEASE"; then
+  # Override value in defines.sh, if any
+  EARLY_BETA_OR_EARLIER=
+elif test "$EARLY_BETA_OR_EARLIER"; then
+  AC_DEFINE(EARLY_BETA_OR_EARLIER)
+fi
+AC_SUBST(EARLY_BETA_OR_EARLIER)
+
 # Allow the application to provide a subconfigure script
 if test -f "${srcdir}/${MOZ_BUILD_APP}/configure.in" ; then
   do_output_subdirs() {
     if test -n "$_subconfigure_subdirs"; then
       AC_MSG_ERROR([Cannot specify more than one sub-sub-configure])
      fi
     _subconfigure_subdir="$1"
     _subconfigure_config_args="$ac_configure_args"
@@ -9155,16 +9191,17 @@ fi
 OS_TARGET=${OS_TARGET} \
 TARGET_CPU=${TARGET_CPU} \
 MOZ_DEBUG=${MOZ_DEBUG} \
 MOZ_WIDGET_TOOLKIT=${MOZ_WIDGET_TOOLKIT} \
 UNIVERSAL_BINARY=${UNIVERSAL_BINARY} \
 MOZ_CRASHREPORTER=${MOZ_CRASHREPORTER} \
 MOZ_APP_NAME=${MOZ_APP_NAME} \
 TOPSRCDIR=${_topsrcdir} \
+MOZ_ASAN=${MOZ_ASAN} \
   $PYTHON ${_topsrcdir}/config/writemozinfo.py ./mozinfo.json.tmp
 if cmp -s ./mozinfo.json.tmp ./mozinfo.json; then
   rm ./mozinfo.json.tmp
 else
   mv -f ./mozinfo.json.tmp ./mozinfo.json
 fi
 
 # Run jemalloc configure script
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1721,17 +1721,17 @@ public:
   /**
    * Creates an arraybuffer from a binary string.
    */
   static nsresult CreateArrayBuffer(JSContext *aCx, const nsACString& aData,
                                     JSObject** aResult);
 
   static nsresult CreateBlobBuffer(JSContext* aCx,
                                    const nsACString& aData,
-                                   JS::Value& aBlob);
+                                   JS::MutableHandle<JS::Value> aBlob);
 
   static void StripNullChars(const nsAString& aInStr, nsAString& aOutStr);
 
   /**
    * Strip all \n, \r and nulls from the given string
    * @param aString the string to remove newlines from [in/out]
    */
   static void RemoveNewlines(nsString &aString);
--- a/content/base/public/nsIAttribute.h
+++ b/content/base/public/nsIAttribute.h
@@ -7,18 +7,18 @@
 #define nsIAttribute_h___
 
 #include "nsINode.h"
 
 class nsDOMAttributeMap;
 class nsIContent;
 
 #define NS_IATTRIBUTE_IID  \
-{ 0x536167ae, 0x8a9c, 0x4712, \
-  { 0x8b, 0x61, 0x3, 0x43, 0xf6, 0xbc, 0x64, 0x75 } }
+{ 0x8d9d7dbf, 0xc42d, 0x4715, \
+  { 0x95, 0xcf, 0x7a, 0x5e, 0xd5, 0xa4, 0x47, 0x70 } }
 
 class nsIAttribute : public nsINode
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IATTRIBUTE_IID)
 
   virtual void SetMap(nsDOMAttributeMap *aMap) = 0;
   
@@ -38,21 +38,18 @@ public:
    * Called when our ownerElement is moved into a new document.
    * Updates the nodeinfo of this node.
    */
   virtual nsresult SetOwnerDocument(nsIDocument* aDocument) = 0;
 
 protected:
 #ifdef MOZILLA_INTERNAL_API
   nsIAttribute(nsDOMAttributeMap *aAttrMap, already_AddRefed<nsINodeInfo> aNodeInfo,
-               bool aNsAware)
-    : nsINode(aNodeInfo), mAttrMap(aAttrMap), mNsAware(aNsAware)
-  {
-  }
+               bool aNsAware);
 #endif //MOZILLA_INTERNAL_API
 
-  nsDOMAttributeMap *mAttrMap; // WEAK
+  nsRefPtr<nsDOMAttributeMap> mAttrMap;
   bool mNsAware;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIAttribute, NS_IATTRIBUTE_IID)
 
 #endif /* nsIAttribute_h___ */
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -108,18 +108,18 @@ template<typename> class OwningNonNull;
 template<typename> class Sequence;
 
 template<typename, typename> class CallbackObjectHolder;
 typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
 } // namespace dom
 } // namespace mozilla
 
 #define NS_IDOCUMENT_IID \
-{ 0x4be4a58d, 0x7fce, 0x4315, \
-  { 0x9d, 0x6c, 0x8e, 0x9f, 0xc7, 0x2e, 0x51, 0xb } };
+{ 0x308f8444, 0x7679, 0x445a, \
+ { 0xa6, 0xcc, 0xb9, 0x5c, 0x61, 0xff, 0xe2, 0x66 } }
 
 // Flag for AddStyleSheet().
 #define NS_STYLESHEET_FROM_CATALOG                (1 << 0)
 
 // Enum for requesting a particular type of document when creating a doc
 enum DocumentFlavor {
   DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant
   DocumentFlavorHTML, // HTMLDocument with HTMLness bit set to true
@@ -2023,17 +2023,17 @@ public:
   void MozCancelFullScreen();
   Element* GetMozPointerLockElement();
   void MozExitPointerLock()
   {
     UnlockPointer(this);
   }
   bool Hidden() const
   {
-    return mVisibilityState != mozilla::dom::VisibilityStateValues::Visible;
+    return mVisibilityState != mozilla::dom::VisibilityState::Visible;
   }
   bool MozHidden() // Not const because of WarnOnceAbout
   {
     WarnOnceAbout(ePrefixedVisibilityAPI);
     return Hidden();
   }
   mozilla::dom::VisibilityState VisibilityState()
   {
@@ -2093,16 +2093,19 @@ public:
   already_AddRefed<nsIDOMTouchList>
     CreateTouchList(mozilla::dom::Touch& aTouch,
                     const mozilla::dom::Sequence<mozilla::dom::OwningNonNull<mozilla::dom::Touch> >& aTouches);
   already_AddRefed<nsIDOMTouchList>
     CreateTouchList(const mozilla::dom::Sequence<mozilla::dom::OwningNonNull<mozilla::dom::Touch> >& aTouches);
 
   virtual nsHTMLDocument* AsHTMLDocument() { return nullptr; }
 
+  virtual JSObject* WrapObject(JSContext *aCx,
+                               JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
 private:
   uint64_t mWarnedAbout;
 
 protected:
   ~nsIDocument();
   nsPropertyTable* GetExtraPropertyTable(uint16_t aCategory);
 
   // Never ever call this. Only call GetWindow!
@@ -2134,20 +2137,16 @@ protected:
     mContentType = aType;
   }
 
   nsCString GetContentTypeInternal() const
   {
     return mContentType;
   }
 
-  // All document WrapNode implementations MUST call this method.  A
-  // false return value means an exception was thrown.
-  bool PostCreateWrapper(JSContext* aCx, JS::Handle<JSObject*> aNewObject);
-
   nsCString mReferrer;
   nsString mLastModified;
 
   nsCOMPtr<nsIURI> mDocumentURI;
   nsCOMPtr<nsIURI> mOriginalURI;
   nsCOMPtr<nsIURI> mDocumentBaseURI;
 
   nsWeakPtr mDocumentLoadGroup;
--- a/content/base/src/Attr.cpp
+++ b/content/base/src/Attr.cpp
@@ -24,16 +24,23 @@
 #include "nsNodeUtils.h"
 #include "nsEventListenerManager.h"
 #include "nsTextNode.h"
 #include "mozAutoDocUpdate.h"
 #include "nsMutationEvent.h"
 #include "nsAsyncDOMEvent.h"
 #include "nsWrapperCacheInlines.h"
 
+nsIAttribute::nsIAttribute(nsDOMAttributeMap* aAttrMap,
+                           already_AddRefed<nsINodeInfo> aNodeInfo,
+                           bool aNsAware)
+: nsINode(aNodeInfo), mAttrMap(aAttrMap), mNsAware(aNsAware)
+{
+}
+
 namespace mozilla {
 namespace dom {
 
 //----------------------------------------------------------------------
 bool Attr::sInitialized;
 
 Attr::Attr(nsDOMAttributeMap *aAttrMap,
            already_AddRefed<nsINodeInfo> aNodeInfo,
@@ -51,32 +58,59 @@ Attr::Attr(nsDOMAttributeMap *aAttrMap,
 }
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Attr)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 
   if (!nsINode::Traverse(tmp, cb)) {
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAttrMap)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Attr)
   nsINode::Trace(tmp, aCallback, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Attr)
   nsINode::Unlink(tmp);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mAttrMap)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(Attr)
+  Element* ownerElement = tmp->GetContentInternal();
+  if (tmp->IsBlack()) {
+    if (ownerElement) {
+      // The attribute owns the element via attribute map so we can
+      // mark it when the attribute is certainly alive.
+      mozilla::dom::FragmentOrElement::MarkNodeChildren(ownerElement);
+    }
+    return true;
+  }
+  if (ownerElement &&
+      mozilla::dom::FragmentOrElement::CanSkip(ownerElement, true)) {
+    return true;
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(Attr)
+  return tmp->IsBlackAndDoesNotNeedTracing(static_cast<nsIAttribute*>(tmp));
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(Attr)
+  return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
 // QueryInterface implementation for Attr
 NS_INTERFACE_TABLE_HEAD(Attr)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_NODE_INTERFACE_TABLE5(Attr, nsIDOMAttr, nsIAttribute, nsIDOMNode,
                            nsIDOMEventTarget, EventTarget)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(Attr)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAttribute)
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
                                  new nsNodeSupportsWeakRefTearoff(this))
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
                                  new nsNode3Tearoff(this))
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Attr)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(Attr,
--- a/content/base/src/Attr.h
+++ b/content/base/src/Attr.h
@@ -67,18 +67,18 @@ public:
   virtual nsresult AppendChildTo(nsIContent* aKid, bool aNotify);
   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify);
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual already_AddRefed<nsIURI> GetBaseURI() const;
 
   static void Initialize();
   static void Shutdown();
 
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Attr,
-                                                         nsIAttribute)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Attr,
+                                                                   nsIAttribute)
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
 
   // WebIDL
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   // XPCOM GetName() is OK
--- a/content/base/src/EventSource.cpp
+++ b/content/base/src/EventSource.cpp
@@ -1227,17 +1227,17 @@ EventSource::DispatchAllMessageEvents()
   AutoPushJSContext cx(scriptContext->GetNativeContext());
   NS_ENSURE_TRUE_VOID(cx);
 
   while (mMessagesToDispatch.GetSize() > 0) {
     nsAutoPtr<Message>
       message(static_cast<Message*>(mMessagesToDispatch.PopFront()));
 
     // Now we can turn our string into a jsval
-    JS::Value jsData;
+    JS::Rooted<JS::Value> jsData(cx);
     {
       JSString* jsString;
       JSAutoRequest ar(cx);
       jsString = JS_NewUCStringCopyN(cx,
                                      message->mData.get(),
                                      message->mData.Length());
       NS_ENSURE_TRUE_VOID(jsString);
 
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -448,17 +448,17 @@ WebSocket::WebSocket()
   mCheckMustKeepAlive(true),
   mOnCloseScheduled(false),
   mFailed(false),
   mDisconnected(false),
   mCloseEventWasClean(false),
   mCloseEventCode(nsIWebSocketChannel::CLOSE_ABNORMAL),
   mReadyState(WebSocket::CONNECTING),
   mOutgoingBufferedAmount(0),
-  mBinaryType(BinaryTypeValues::Blob),
+  mBinaryType(dom::BinaryType::Blob),
   mScriptLine(0),
   mInnerWindowID(0)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsLayoutStatics::AddRef();
 
   SetIsDOMBinding();
 }
@@ -879,26 +879,26 @@ WebSocket::CreateAndDispatchMessageEvent
 
   nsIScriptContext* scriptContext = sgo->GetContext();
   NS_ENSURE_TRUE(scriptContext, NS_ERROR_FAILURE);
 
   AutoPushJSContext cx(scriptContext->GetNativeContext());
   NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
 
   // Create appropriate JS object for message
-  JS::Value jsData;
+  JS::Rooted<JS::Value> jsData(cx);
   {
     JSAutoRequest ar(cx);
     if (isBinary) {
-      if (mBinaryType == BinaryTypeValues::Blob) {
-        rv = nsContentUtils::CreateBlobBuffer(cx, aData, jsData);
+      if (mBinaryType == dom::BinaryType::Blob) {
+        rv = nsContentUtils::CreateBlobBuffer(cx, aData, &jsData);
         NS_ENSURE_SUCCESS(rv, rv);
-      } else if (mBinaryType == BinaryTypeValues::Arraybuffer) {
-        JSObject* arrayBuf;
-        rv = nsContentUtils::CreateArrayBuffer(cx, aData, &arrayBuf);
+      } else if (mBinaryType == dom::BinaryType::Arraybuffer) {
+        JS::Rooted<JSObject*> arrayBuf(cx);
+        rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
         NS_ENSURE_SUCCESS(rv, rv);
         jsData = OBJECT_TO_JSVAL(arrayBuf);
       } else {
         NS_RUNTIMEABORT("Unknown binary type!");
         return NS_ERROR_UNEXPECTED;
       }
     } else {
       // JS string
--- a/content/base/src/nsCCUncollectableMarker.cpp
+++ b/content/base/src/nsCCUncollectableMarker.cpp
@@ -414,19 +414,17 @@ struct TraceClosure
   uint32_t mGCNumber;
 };
 
 static PLDHashOperator
 TraceActiveWindowGlobal(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
 {
   if (aWindow->GetDocShell() && aWindow->IsOuterWindow()) {
     TraceClosure* closure = static_cast<TraceClosure*>(aClosure);
-    if (JSObject* global = aWindow->FastGetGlobalJSObject()) {
-      JS_CallObjectTracer(closure->mTrc, global, "active window global");
-    }
+    aWindow->TraceGlobalJSObject(closure->mTrc);
 #ifdef MOZ_XUL
     nsIDocument* doc = aWindow->GetExtantDoc();
     if (doc && doc->IsXUL()) {
       XULDocument* xulDoc = static_cast<XULDocument*>(doc);
       xulDoc->TraceProtos(closure->mTrc, closure->mGCNumber);
     }
 #endif
   }
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -670,18 +670,18 @@ nsContentList::NamedItem(JSContext* cx, 
                          mozilla::ErrorResult& error)
 {
   nsIContent *item = NamedItem(name, true);
   if (!item) {
     return nullptr;
   }
   JS::Rooted<JSObject*> wrapper(cx, GetWrapper());
   JSAutoCompartment ac(cx, wrapper);
-  JS::Value v;
-  if (!mozilla::dom::WrapObject(cx, wrapper, item, item, nullptr, &v)) {
+  JS::Rooted<JS::Value> v(cx);
+  if (!mozilla::dom::WrapObject(cx, wrapper, item, item, nullptr, v.address())) {
     error.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   return &v.toObject();
 }
 
 void
 nsContentList::AttributeChanged(nsIDocument *aDocument, Element* aElement,
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -1642,17 +1642,18 @@ nsContentUtils::GetContextFromDocument(n
 void
 nsContentUtils::TraceSafeJSContext(JSTracer* aTrc)
 {
   JSContext* cx = GetSafeJSContext();
   if (!cx) {
     return;
   }
   if (JSObject* global = JS_GetGlobalObject(cx)) {
-    JS_CallObjectTracer(aTrc, global, "safe context");
+    JS_CallObjectTracer(aTrc, &global, "safe context");
+    MOZ_ASSERT(global == JS_GetGlobalObject(cx));
   }
 }
 
 nsPIDOMWindow *
 nsContentUtils::GetWindowFromCaller()
 {
   JSContext *cx = GetCurrentJSContext();
   if (cx) {
@@ -3357,17 +3358,17 @@ nsContentUtils::GetWrapperSafeScriptFile
       // aURI is a script from a URL that doesn't get wrapper
       // automation. aDocument is a chrome document that does get
       // wrapper automation. Prepend the chrome document's URI
       // followed by the string " -> " to the URI of the script we're
       // loading here so that script in that URI gets the same wrapper
       // automation that the chrome document expects.
       nsAutoCString spec;
       docURI->GetSpec(spec);
-      spec.AppendASCII(" -> ");
+      spec.AppendLiteral(" -> ");
       spec.Append(aScriptURI);
 
       aScriptURI = spec;
 
       scriptFileNameModified = true;
     }
   }
 
@@ -5914,29 +5915,30 @@ nsContentUtils::CreateArrayBuffer(JSCont
   return NS_OK;
 }
 
 // Initial implementation: only stores to RAM, not file
 // TODO: bug 704447: large file support
 nsresult
 nsContentUtils::CreateBlobBuffer(JSContext* aCx,
                                  const nsACString& aData,
-                                 JS::Value& aBlob)
+                                 JS::MutableHandle<JS::Value> aBlob)
 {
   uint32_t blobLen = aData.Length();
   void* blobData = moz_malloc(blobLen);
   nsCOMPtr<nsIDOMBlob> blob;
   if (blobData) {
     memcpy(blobData, aData.BeginReading(), blobLen);
     blob = new nsDOMMemoryFile(blobData, blobLen, EmptyString());
   } else {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   JS::Rooted<JSObject*> scope(aCx, JS_GetGlobalForScopeChain(aCx));
-  return nsContentUtils::WrapNative(aCx, scope, blob, &aBlob, nullptr, true);
+  return nsContentUtils::WrapNative(aCx, scope, blob, aBlob.address(), nullptr,
+                                    true);
 }
 
 void
 nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr)
 {
   // In common cases where we don't have nulls in the
   // string we can simple simply bypass the checking code.
   int32_t firstNullPos = aInStr.FindChar('\0');
@@ -6620,18 +6622,18 @@ void
 nsContentUtils::ReleaseWrapper(void* aScriptObjectHolder,
                                nsWrapperCache* aCache)
 {
   if (aCache->PreservingWrapper()) {
     // PreserveWrapper puts new DOM bindings in the JS holders hash, but they
     // can also be in the DOM expando hash, so we need to try to remove them
     // from both here.
     JSObject* obj = aCache->GetWrapperPreserveColor();
-    if (aCache->IsDOMBinding() && obj) {
-      xpc::GetObjectScope(obj)->RemoveDOMExpandoObject(obj);
+    if (aCache->IsDOMBinding() && obj && js::IsProxy(obj)) {
+        DOMProxyHandler::GetAndClearExpandoObject(obj);
     }
     aCache->SetPreservingWrapper(false);
     DropJSObjects(aScriptObjectHolder);
   }
 }
 
 // static
 void
--- a/content/base/src/nsDOMAttributeMap.cpp
+++ b/content/base/src/nsDOMAttributeMap.cpp
@@ -15,16 +15,17 @@
 #include "nsAttrName.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsINameSpaceManager.h"
 #include "nsNodeInfoManager.h"
 #include "nsUnicharUtils.h"
+#include "nsWrapperCacheInlines.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 
 nsDOMAttributeMap::nsDOMAttributeMap(Element* aContent)
   : mContent(aContent)
@@ -57,16 +58,17 @@ nsDOMAttributeMap::DropReference()
 {
   mAttributeCache.Enumerate(RemoveMapRef, nullptr);
   mContent = nullptr;
 }
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMAttributeMap)
   tmp->DropReference();
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 
 PLDHashOperator
 TraverseMapEntry(nsAttrHashKey::KeyType aKey, nsRefPtr<Attr>& aData,
                  void* aUserArg)
 {
   nsCycleCollectionTraversalCallback *cb = 
@@ -75,20 +77,44 @@ TraverseMapEntry(nsAttrHashKey::KeyType 
   cb->NoteXPCOMChild(static_cast<nsINode*>(aData.get()));
 
   return PL_DHASH_NEXT;
 }
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttributeMap)
   tmp->mAttributeCache.Enumerate(TraverseMapEntry, &cb);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsDOMAttributeMap)
 
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDOMAttributeMap)
+  if (tmp->IsBlack()) {
+    if (tmp->mContent) {
+      // The map owns the element so we can mark it when the
+      // map itself is certainly alive.
+      mozilla::dom::FragmentOrElement::MarkNodeChildren(tmp->mContent);
+    }
+    return true;
+  }
+  if (tmp->mContent &&
+      mozilla::dom::FragmentOrElement::CanSkip(tmp->mContent, true)) {
+    return true;
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDOMAttributeMap)
+  return tmp->IsBlackAndDoesNotNeedTracing(tmp);
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDOMAttributeMap)
+  return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
 // QueryInterface implementation for nsDOMAttributeMap
 NS_INTERFACE_TABLE_HEAD(nsDOMAttributeMap)
   NS_INTERFACE_TABLE1(nsDOMAttributeMap, nsIDOMMozNamedAttrMap)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDOMAttributeMap)
 NS_INTERFACE_MAP_END
 
@@ -330,17 +356,20 @@ nsDOMAttributeMap::RemoveNamedItem(const
   ErrorResult rv;
   *aReturn = RemoveNamedItem(aName, rv).get();
   return rv.ErrorCode();
 }
 
 already_AddRefed<Attr>
 nsDOMAttributeMap::RemoveNamedItem(const nsAString& aName, ErrorResult& aError)
 {
-  NS_ENSURE_TRUE(mContent, nullptr);
+  if (!mContent) {
+    aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
+    return nullptr;
+  }
 
   nsCOMPtr<nsINodeInfo> ni = mContent->GetExistingAttrNameFromQName(aName);
   if (!ni) {
     aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
     return nullptr;
   }
 
   nsRefPtr<Attr> attribute = GetAttribute(ni, true);
--- a/content/base/src/nsDOMAttributeMap.h
+++ b/content/base/src/nsDOMAttributeMap.h
@@ -94,17 +94,17 @@ public:
   typedef mozilla::dom::Attr Attr;
   typedef mozilla::dom::Element Element;
   typedef mozilla::ErrorResult ErrorResult;
 
   nsDOMAttributeMap(Element *aContent);
   virtual ~nsDOMAttributeMap();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMAttributeMap)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsDOMAttributeMap)
 
   // nsIDOMMozNamedAttrMap interface
   NS_DECL_NSIDOMMOZNAMEDATTRMAP
 
   void DropReference();
 
   Element* GetContent()
   {
@@ -179,17 +179,17 @@ public:
   void GetSupportedNames(nsTArray<nsString>& aNames)
   {
     // No supported names we want to show up in iteration.
   }
 
   size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 
 private:
-  Element *mContent; // Weak reference
+  nsCOMPtr<Element> mContent;
 
   /**
    * Cache of Attrs.
    */
   AttrCache mAttributeCache;
 
   /**
    * SetNamedItem() (aWithNS = false) and SetNamedItemNS() (aWithNS =
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -187,24 +187,24 @@ nsDOMMultipartFile::InitBlob(JSContext* 
   bool nativeEOL = false;
   if (aArgc > 1) {
     if (NS_IsMainThread()) {
       BlobPropertyBag d;
       if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]))) {
         return NS_ERROR_TYPE_ERR;
       }
       mContentType = d.mType;
-      nativeEOL = d.mEndings == EndingTypesValues::Native;
+      nativeEOL = d.mEndings == EndingTypes::Native;
     } else {
       BlobPropertyBagWorkers d;
       if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]))) {
         return NS_ERROR_TYPE_ERR;
       }
       mContentType = d.mType;
-      nativeEOL = d.mEndings == EndingTypesValues::Native;
+      nativeEOL = d.mEndings == EndingTypes::Native;
     }
   }
 
   if (aArgc > 0) {
     if (!aArgv[0].isObject()) {
       return NS_ERROR_TYPE_ERR; // We're not interested
     }
 
--- a/content/base/src/nsDOMDataChannel.cpp
+++ b/content/base/src/nsDOMDataChannel.cpp
@@ -333,20 +333,21 @@ nsDOMDataChannel::GetSendParams(nsIVaria
       dataType == nsIDataType::VTYPE_INTERFACE_IS) {
     nsCOMPtr<nsISupports> supports;
     nsID* iid;
     rv = aData->GetAsInterface(&iid, getter_AddRefs(supports));
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsMemory::Free(iid);
 
+    AutoSafeJSContext cx;
     // ArrayBuffer?
-    JS::Value realVal;
-    JSObject* obj;
-    nsresult rv = aData->GetAsJSVal(&realVal);
+    JS::Rooted<JS::Value> realVal(cx);
+    JS::Rooted<JSObject*> obj(cx);
+    nsresult rv = aData->GetAsJSVal(realVal.address());
     if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal) &&
         (obj = JSVAL_TO_OBJECT(realVal)) &&
         (JS_IsArrayBufferObject(obj))) {
       int32_t len = JS_GetArrayBufferByteLength(obj);
       char* data = reinterpret_cast<char*>(JS_GetArrayBufferData(obj));
 
       aStringOut.Assign(data, len);
       aIsBinary = true;
@@ -409,25 +410,25 @@ nsDOMDataChannel::DoOnMessageAvailable(c
 
   nsIScriptContext* sc = sgo->GetContext();
   NS_ENSURE_TRUE(sc, NS_ERROR_FAILURE);
 
   AutoPushJSContext cx(sc->GetNativeContext());
   NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
 
   JSAutoRequest ar(cx);
-  JS::Value jsData;
+  JS::Rooted<JS::Value> jsData(cx);
 
   if (aBinary) {
     if (mBinaryType == DC_BINARY_TYPE_BLOB) {
-      rv = nsContentUtils::CreateBlobBuffer(cx, aData, jsData);
+      rv = nsContentUtils::CreateBlobBuffer(cx, aData, &jsData);
       NS_ENSURE_SUCCESS(rv, rv);
     } else if (mBinaryType == DC_BINARY_TYPE_ARRAYBUFFER) {
-      JSObject* arrayBuf;
-      rv = nsContentUtils::CreateArrayBuffer(cx, aData, &arrayBuf);
+      JS::Rooted<JSObject*> arrayBuf(cx);
+      rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
       NS_ENSURE_SUCCESS(rv, rv);
       jsData = OBJECT_TO_JSVAL(arrayBuf);
     } else {
       NS_RUNTIMEABORT("Unknown binary type!");
       return NS_ERROR_UNEXPECTED;
     }
   } else {
     NS_ConvertUTF8toUTF16 utf16data(aData);
--- a/content/base/src/nsDOMParser.cpp
+++ b/content/base/src/nsDOMParser.cpp
@@ -36,23 +36,29 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMParser, mOwner)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMParser)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMParser)
 
+static const char*
+StringFromSupportedType(SupportedType aType)
+{
+  return SupportedTypeValues::strings[static_cast<int>(aType)].value;
+}
+
 already_AddRefed<nsIDocument>
 nsDOMParser::ParseFromString(const nsAString& aStr, SupportedType aType,
                              ErrorResult& rv)
 {
   nsCOMPtr<nsIDOMDocument> domDocument;
   rv = ParseFromString(aStr,
-                       SupportedTypeValues::strings[aType].value,
+                       StringFromSupportedType(aType),
                        getter_AddRefs(domDocument));
   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
   return document.forget();