Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 07 May 2013 22:10:19 -0400
changeset 131199 b980d32c366f82691e99f065b1743e535df64843
parent 131031 b25afb305360511da06f4aa48fb632519245941f (current diff)
parent 131198 fe3fc1746cae26fbca26b586e213c48066b828d5 (diff)
child 131200 8b3f78b002c2294ae23c8343e0232d1738411e06
child 131201 64c5d1f3d72802881a471e5530b610d6927e2ad2
child 131205 9b321cd729e5b4edb7f9fcbcb20b96edd8f8dbe1
child 131241 8b12845b9563a32d73eb42249c1b22ad3858a41d
child 131543 b3a6bee35493d41d82c4159f5be649b83de3e7b5
push id24649
push userryanvm@gmail.com
push dateWed, 08 May 2013 02:10:32 +0000
treeherdermozilla-central@b980d32c366f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone23.0a1
first release with
nightly linux32
b980d32c366f / 23.0a1 / 20130508031113 / files
nightly linux64
b980d32c366f / 23.0a1 / 20130508031113 / files
nightly mac
b980d32c366f / 23.0a1 / 20130508031113 / files
nightly win32
b980d32c366f / 23.0a1 / 20130508031113 / files
nightly win64
b980d32c366f / 23.0a1 / 20130508031113 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c.
browser/metro/components/CapturePicker.js
configure.in
content/canvas/src/CanvasRenderingContext2D.cpp
dom/payment/interfaces/nsIDOMNavigatorPayment.idl
gfx/layers/Makefile.in
layout/base/tests/cpp-tests/Makefile.in
layout/base/tests/cpp-tests/TestPoisonArea.cpp
layout/base/tests/cpp-tests/moz.build
mobile/android/base/AnimatorProxy.java
mobile/android/base/HeightChangeAnimation.java
mobile/android/base/PropertyAnimator.java
mobile/android/base/Rotate3DAnimation.java
mobile/android/chrome/content/WebrtcUI.js
modules/libpref/src/init/all.js
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -1079,18 +1079,21 @@ HyperTextAccessible::GetTextAtOffset(int
         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/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/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
@@ -1199,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/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-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) {
@@ -689,23 +1000,27 @@ SocialToolbar = {
   update: function() {
     this._updateButtonHiddenState();
     this.updateProvider();
     this.populateProviderMenus();
   },
 
   // Called when the Social.provider changes
   updateProvider: function () {
-    let provider = Social.provider || Social.defaultProvider;
+    let provider = Social.provider;
     if (provider) {
       this.button.setAttribute("label", provider.name);
       this.button.setAttribute("tooltiptext", provider.name);
       this.button.style.listStyleImage = "url(" + provider.iconURL + ")";
 
       this.updateProfile();
+    } else {
+      this.button.setAttribute("label", gNavigatorBundle.getString("service.toolbarbutton.label"));
+      this.button.setAttribute("tooltiptext", gNavigatorBundle.getString("service.toolbarbutton.tooltiptext"));
+      this.button.style.removeProperty("list-style-image");
     }
     this.updateButton();
   },
 
   get button() {
     return document.getElementById("social-provider-button");
   },
 
@@ -989,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 (!SocialUI.enabled || 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"
@@ -736,17 +756,17 @@
                       accesskey="&social.toggleSidebar.accesskey;"/>
             <menuitem class="social-toggle-notifications-menuitem"
                       type="checkbox"
                       autocheck="false"
                       command="Social:ToggleNotifications"
                       label="&social.toggleNotifications.label;"
                       accesskey="&social.toggleNotifications.accesskey;"/>
             <menuitem class="social-toggle-menuitem" command="Social:Toggle"/>
-            <menuseparator class="social-statusarea-separator"/>
+            <menuseparator/>
             <menuseparator class="social-provider-menu" hidden="true"/>
             <menuitem class="social-addons-menuitem" command="Social:Addons"
                       label="&social.addons.label;"/>
             <menuitem label="&social.learnMore.label;"
                       accesskey="&social.learnMore.accesskey;"
                       oncommand="SocialUI.showLearnMore();"/>
           </menupopup>
         </toolbarbutton>
--- 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_multiprovider.js
+++ b/browser/base/content/test/social/browser_social_multiprovider.js
@@ -44,17 +44,26 @@ var tests = {
     // Now wait for the initial provider profile to be set
     waitForProviderLoad(function() {
       checkUIStateMatchesProvider(gProviders[0]);
 
       // Now activate "provider 2"
       observeProviderSet(function () {
         waitForProviderLoad(function() {
           checkUIStateMatchesProvider(gProviders[1]);
-          next();
+          // disable social, click on the provider menuitem to switch providers
+          Social.enabled = false;
+          let menu = document.getElementById("social-statusarea-popup");
+          let el = menu.getElementsByAttribute("origin", gProviders[0].origin);
+          is(el.length, 1, "selected provider menu item exists");
+          el[0].click();
+          waitForProviderLoad(function() {
+            checkUIStateMatchesProvider(gProviders[0]);
+            next();
+          });
         });
       });
       Social.activateFromOrigin("https://test1.example.com");
     });
   }
 }
 
 function checkUIStateMatchesProvider(provider) {
--- a/browser/base/content/test/social/head.js
+++ b/browser/base/content/test/social/head.js
@@ -185,18 +185,23 @@ function checkSocialUI(win) {
   isbool(win.SocialChatBar.isAvailable, enabled && Social.haveLoggedInUser(), "chatbar available?");
   isbool(!win.SocialChatBar.chatbar.hidden, enabled && Social.haveLoggedInUser(), "chatbar visible?");
 
   let markVisible = enabled && provider.pageMarkInfo;
   let canMark = markVisible && win.SocialMark.canMarkPage(win.gBrowser.currentURI);
   isbool(!win.SocialMark.button.hidden, markVisible, "SocialMark button visible?");
   isbool(!win.SocialMark.button.disabled, canMark, "SocialMark button enabled?");
   isbool(!doc.getElementById("social-toolbar-item").hidden, active, "toolbar items visible?");
-  if (active)
-    is(win.SocialToolbar.button.style.listStyleImage, 'url("' + Social.defaultProvider.iconURL + '")', "toolbar button has provider icon");
+  if (active) {
+    if (!enabled) {
+      ok(!win.SocialToolbar.button.style.listStyleImage, "toolbar button is default icon");
+    } else {
+      is(win.SocialToolbar.button.style.listStyleImage, 'url("' + Social.defaultProvider.iconURL + '")', "toolbar button has provider icon");
+    }
+  }
   // the menus should always have the provider name
   if (provider) {
     for (let id of ["menu_socialSidebar", "menu_socialAmbientMenu"])
       is(document.getElementById(id).getAttribute("label"), Social.provider.name, "element has the provider name");
   }
 
   // and for good measure, check all the social commands.
   isbool(!doc.getElementById("Social:Toggle").hidden, active, "Social:Toggle visible?");
--- 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/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/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/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/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
copy from browser/config/mozconfigs/win32/release
copy to browser/config/mozconfigs/win32/beta
--- 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/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 \
@@ -133,11 +132,19 @@ MOCHITEST_BROWSER_PAGES = \
 	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
--- 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/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -370,16 +370,19 @@ webapps.install.accesskey = I
 webapps.requestInstall = Do you want to install "%1$S" from this site (%2$S)?
 webapps.install.success = Application Installed
 
 # LOCALIZATION NOTE (fullscreen.entered): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
 fullscreen.entered=%S is now fullscreen.
 # LOCALIZATION NOTE (fullscreen.rememberDecision): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
 fullscreen.rememberDecision=Remember decision for %S
 
+service.toolbarbutton.label=Services
+service.toolbarbutton.tooltiptext=Services
+
 # LOCALIZATION NOTE (social.install.description): %1$S is the hostname of the social provider, %2$S is brandShortName (e.g. Firefox)
 service.install.description=Would you like to enable services from %1$S to display in your %2$S toolbar and sidebar?
 service.install.ok.label=Enable Services
 service.install.ok.accesskey=E
 service.install.learnmore=Learn More…
 
 # LOCALIZATION NOTE (social.turnOff.label): %S is the name of the social provider
 social.turnOff.label=Turn off %S
--- a/browser/metro/base/content/RemoteTabs.js
+++ b/browser/metro/base/content/RemoteTabs.js
@@ -5,35 +5,36 @@
 
 '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) {
   this._set = aSet;
   this._set.controller = this;
   this._uiAccessElement = aSetUIAccess;
 
   // 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,
@@ -41,20 +42,16 @@ RemoteTabsView.prototype = {
 
   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;
     }
   },
@@ -67,42 +64,39 @@ RemoteTabsView.prototype = {
 
     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);
   }
 
--- 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 progressBall" />
+        <html:div class="progressBall progressBall" />
+        <html:div class="progressBall progressBall" />
+        <html:div class="progressBall progressBall" />
+        <html:div class="progressBall 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,17 +280,17 @@
             </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;"
                 onclick="PanelUI.show('remotetabs-container');" inputProcessing="true"/>
             </scrollbox>
@@ -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/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/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/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 */
 
@@ -2089,16 +2147,21 @@ toolbar[mode="text"] toolbarbutton.chevr
   color: #FDF3DE;
   min-width: 16px;
   text-shadow: none;
   background-image: linear-gradient(#B4211B, #8A1915);
   border-radius: 1px;
   -moz-margin-end: 2px;
 }
 
+#social-provider-button {
+  -moz-image-region: rect(0, 16px, 16px, 0);
+  list-style-image: url(chrome://browser/skin/social/services-16.png);
+}
+
 #social-provider-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
 .toolbarbutton-badge-container {
   margin: 5px 3px;
   position: relative;
 }
@@ -2184,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));
 }
 
--- 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)
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,18 +3679,29 @@ 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);
+  }
 }
 
 #social-provider-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
 .toolbarbutton-badge-container {
   margin: 0;
@@ -3744,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@;
 }
 
--- 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)
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
--- 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 */
 
@@ -2760,16 +2847,17 @@ toolbarbutton.bookmark-item[dragover="tr
   border-radius: 1px;
   -moz-margin-end: 5px;
 }
 
 /* Social toolbar item */
 
 #social-provider-button {
   -moz-image-region: rect(0, 16px, 16px, 0);
+  list-style-image: url(chrome://browser/skin/social/services-16.png);
 }
 
 #social-provider-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
 .toolbarbutton-badge-container {
   margin: 0;
@@ -2908,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));
 }
 
--- 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)
@@ -368,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)
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,32 +17,40 @@ 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',
 ]
 
 def bootstrap(topsrcdir, mozilla_dir=None):
     if mozilla_dir is None:
         mozilla_dir = topsrcdir
--- a/build/macosx/mozconfig.common
+++ b/build/macosx/mozconfig.common
@@ -20,8 +20,11 @@ if [ -z "$CC" ]; then
 fi
 
 # If not set use the system default clang++
 if [ -z "$CXX" ]; then
     export CXX=clang++
 fi
 
 ac_add_options --with-ccache
+
+# Enable ECMAScript Internationalization API
+ac_add_options --enable-intl-api
--- 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/mozconfig.vs2010-common
+++ b/build/mozconfig.vs2010-common
@@ -1,8 +1,11 @@
-# Pymake needs Windows-style paths. Use cmd.exe to hack around this.
-mk_export_correct_style() {
-  if test -n "${_PYMAKE}"; then
-    mk_add_options "export $1=$(cmd.exe //c echo %$1%)"
-  else
-    mk_add_options "export $1=$(eval echo \$$1)"
-  fi
-}
+# Pymake needs Windows-style paths. Use cmd.exe to hack around this.
+mk_export_correct_style() {
+  if test -n "${_PYMAKE}"; then
+    mk_add_options "export $1=$(cmd.exe //c echo %$1%)"
+  else
+    mk_add_options "export $1=$(eval echo \$$1)"
+  fi
+}
+
+# Enable ECMAScript Internationalization API
+ac_add_options --enable-intl-api
--- 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/build/unix/mozconfig.linux
+++ b/build/unix/mozconfig.linux
@@ -1,4 +1,7 @@
 . "$topsrcdir/build/mozconfig.common"
 
 CC=/tools/gcc-4.5-0moz3/bin/gcc
 CXX=/tools/gcc-4.5-0moz3/bin/g++
+
+# Enable ECMAScript Internationalization API
+ac_add_options --enable-intl-api
--- 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
@@ -3902,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
@@ -4347,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"
@@ -9159,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/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/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();
 }
@@ -883,20 +883,20 @@ WebSocket::CreateAndDispatchMessageEvent
   AutoPushJSContext cx(scriptContext->GetNativeContext());
   NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
 
   // Create appropriate JS object for message
   JS::Value jsData;
   {
     JSAutoRequest ar(cx);
     if (isBinary) {
-      if (mBinaryType == BinaryTypeValues::Blob) {
+      if (mBinaryType == dom::BinaryType::Blob) {
         rv = nsContentUtils::CreateBlobBuffer(cx, aData, jsData);
         NS_ENSURE_SUCCESS(rv, rv);
-      } else if (mBinaryType == BinaryTypeValues::Arraybuffer) {
+      } else if (mBinaryType == dom::BinaryType::Arraybuffer) {
         JSObject* arrayBuf;
         rv = nsContentUtils::CreateArrayBuffer(cx, aData, &arrayBuf);
         NS_ENSURE_SUCCESS(rv, rv);
         jsData = OBJECT_TO_JSVAL(arrayBuf);
       } else {
         NS_RUNTIMEABORT("Unknown binary type!");
         return NS_ERROR_UNEXPECTED;
       }
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -3357,17 +3357,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;
     }
   }
 
--- 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/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();
 }
 
 NS_IMETHODIMP 
 nsDOMParser::ParseFromString(const PRUnichar *str, 
                              const char *contentType,
@@ -116,33 +122,33 @@ nsDOMParser::ParseFromBuffer(const Seque
                              SupportedType aType, ErrorResult& rv)
 {
   if (aBufLen > aBuf.Length()) {
     rv.Throw(NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY);
     return nullptr;
   }
   nsCOMPtr<nsIDOMDocument> domDocument;
   rv = nsDOMParser::ParseFromBuffer(aBuf.Elements(), aBufLen,
-                                    SupportedTypeValues::strings[aType].value,
+                                    StringFromSupportedType(aType),
                                     getter_AddRefs(domDocument));
   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
   return document.forget();
 }
 
 already_AddRefed<nsIDocument>
 nsDOMParser::ParseFromBuffer(const Uint8Array& aBuf, uint32_t aBufLen,
                              SupportedType aType, ErrorResult& rv)
 {
   if (aBufLen > aBuf.Length()) {
     rv.Throw(NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY);
     return nullptr;
   }
   nsCOMPtr<nsIDOMDocument> domDocument;
   rv = nsDOMParser::ParseFromBuffer(aBuf.Data(), aBufLen,
-                                    SupportedTypeValues::strings[aType].value,
+                                    StringFromSupportedType(aType),
                                     getter_AddRefs(domDocument));
   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
   return document.forget();
 }
 
 NS_IMETHODIMP 
 nsDOMParser::ParseFromBuffer(const uint8_t *buf,
                              uint32_t bufLen,
@@ -170,17 +176,17 @@ nsDOMParser::ParseFromStream(nsIInputStr
                              int32_t aContentLength,
                              SupportedType aType,
                              ErrorResult& rv)
 {
   nsCOMPtr<nsIDOMDocument> domDocument;
   rv = nsDOMParser::ParseFromStream(aStream,
                                     NS_ConvertUTF16toUTF8(aCharset).get(),
                                     aContentLength,
-                                    SupportedTypeValues::strings[aType].value,
+                                    StringFromSupportedType(aType),
                                     getter_AddRefs(domDocument));
   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
   return document.forget();
 }
 
 NS_IMETHODIMP 
 nsDOMParser::ParseFromStream(nsIInputStream *stream, 
                              const char *charset, 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1340,17 +1340,17 @@ struct nsIDocument::FrameRequest
 // ==================================================================
 // =
 // ==================================================================
 nsIDocument::nsIDocument()
   : nsINode(nullptr),
     mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")),
     mNodeInfoManager(nullptr),
     mCompatMode(eCompatibility_FullStandards),
-    mVisibilityState(VisibilityStateValues::Hidden),
+    mVisibilityState(dom::VisibilityState::Hidden),
     mIsInitialDocumentInWindow(false),
     mMayStartLayout(true),
     mVisible(true),
     mRemovedFromDocShell(false),
     // mAllowDNSPrefetch starts true, so that we can always reliably && it
     // with various values that might disable it.  Since we never prefetch
     // unless we get a window, and in that case the docshell value will get
     // &&-ed in, this is safe.
@@ -10956,20 +10956,20 @@ nsDocument::GetVisibilityState() const
   // 1)  Are we in bfcache (!IsVisible())?  If so, nothing else matters.
   // 2)  Do we have an outer window?  If not, we're hidden.  Note that we don't
   //     want to use GetWindow here because it does weird groveling for windows
   //     in some cases.
   // 3)  Is our outer window background?  If so, we're hidden.
   // Otherwise, we're visible.
   if (!IsVisible() || !mWindow || !mWindow->GetOuterWindow() ||
       mWindow->GetOuterWindow()->IsBackground()) {
-    return VisibilityStateValues::Hidden;
-  }
-
-  return VisibilityStateValues::Visible;
+    return dom::VisibilityState::Hidden;
+  }
+
+  return dom::VisibilityState::Visible;
 }
 
 /* virtual */ void
 nsDocument::PostVisibilityUpdateEvent()
 {
   nsCOMPtr<nsIRunnable> event =
     NS_NewRunnableMethod(this, &nsDocument::UpdateVisibilityState);
   NS_DispatchToMainThread(event);
@@ -10994,17 +10994,18 @@ nsDocument::GetMozVisibilityState(nsAStr
 {
   WarnOnceAbout(ePrefixedVisibilityAPI);
   return GetVisibilityState(aState);
 }
 
 NS_IMETHODIMP
 nsDocument::GetVisibilityState(nsAString& aState)
 {
-  const EnumEntry& entry = VisibilityStateValues::strings[mVisibilityState];
+  const EnumEntry& entry =
+    VisibilityStateValues::strings[static_cast<int>(mVisibilityState)];
   aState.AssignASCII(entry.value, entry.length);
   return NS_OK;
 }
 
 /* virtual */ void
 nsIDocument::DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
 {
   aWindowSizes->mDOMOther +=
@@ -11224,53 +11225,63 @@ nsIDocument::Evaluate(const nsAString& a
   nsCOMPtr<nsISupports> res;
   rv = evaluator->Evaluate(aExpression, contextNode, aResolver, aType,
                            aResult, getter_AddRefs(res));
   return res.forget();
 }
 
 // This is just a hack around the fact that window.document is not
 // [Unforgeable] yet.
-bool
-nsIDocument::PostCreateWrapper(JSContext* aCx, JS::Handle<JSObject*> aNewObject)
+JSObject*
+nsIDocument::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   MOZ_ASSERT(IsDOMBinding());
 
+  JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, aScope));
+  if (!obj) {
+    return nullptr;
+  }
+
   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(GetScriptGlobalObject());
   if (!win) {
     // No window, nothing else to do here
-    return true;
+    return obj;
   }
 
   if (this != win->GetExtantDoc()) {
     // We're not the current document; we're also done here
-    return true;
-  }
-
-  JSAutoCompartment ac(aCx, aNewObject);
+    return obj;
+  }
+
+  JSAutoCompartment ac(aCx, obj);
 
   JS::Rooted<JS::Value> winVal(aCx);
   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-  nsresult rv = nsContentUtils::WrapNative(aCx, aNewObject, win,
+  nsresult rv = nsContentUtils::WrapNative(aCx, obj, win,
                                            &NS_GET_IID(nsIDOMWindow),
                                            winVal.address(),
                                            getter_AddRefs(holder),
                                            false);
   if (NS_FAILED(rv)) {
-    return Throw<true>(aCx, rv);
+    Throw<true>(aCx, rv);
+    return nullptr;
   }
 
   NS_NAMED_LITERAL_STRING(doc_str, "document");
 
-  return JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(winVal),
-                             reinterpret_cast<const jschar *>
-                                             (doc_str.get()),
-                             doc_str.Length(), JS::ObjectValue(*aNewObject),
-                             JS_PropertyStub, JS_StrictPropertyStub,
-                             JSPROP_READONLY | JSPROP_ENUMERATE);
+  if (!JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(winVal),
+                           reinterpret_cast<const jschar *>
+                                           (doc_str.get()),
+                           doc_str.Length(), JS::ObjectValue(*obj),
+                           JS_PropertyStub, JS_StrictPropertyStub,
+                           JSPROP_READONLY | JSPROP_ENUMERATE)) {
+    return nullptr;
+  }
+
+  return obj;
 }
 
 bool
 MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
 {
   nsCOMArray<nsIDocument>* documents =
     static_cast<nsCOMArray<nsIDocument>*>(aData);
   if (aDoc) {
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -544,17 +544,17 @@ ConvertAndWrite(const nsAString& aString
   int32_t unicodeLength = aString.Length();
   int32_t startLength = unicodeLength;
 
   rv = aEncoder->GetMaxLength(unicodeBuf, unicodeLength, &charLength);
   startCharLength = charLength;
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString charXferString;
-  if (!EnsureStringLength(charXferString, charLength))
+  if (!charXferString.SetLength(charLength, fallible_t()))
     return NS_ERROR_OUT_OF_MEMORY;
 
   char* charXferBuf = charXferString.BeginWriting();
   nsresult convert_rv = NS_OK;
 
   do {
     unicodeLength = startLength;
     charLength = startCharLength;
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -2391,17 +2391,18 @@ nsINode::WrapObject(JSContext *aCx, JS::
       !hasHadScriptHandlingObject &&
       !nsContentUtils::IsCallerChrome()) {
     Throw<true>(aCx, NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   JSObject* obj = WrapNode(aCx, aScope);
   if (obj && ChromeOnlyAccess() &&
-      !nsContentUtils::IsSystemPrincipal(NodePrincipal()))
+      !nsContentUtils::IsSystemPrincipal(NodePrincipal()) &&
+      xpc::AllowXBLScope(js::GetContextCompartment(aCx)))
   {
     // Create a new wrapper and cache it.
     JSAutoCompartment ac(aCx, obj);
     JSObject* wrapper = xpc::WrapperFactory::WrapSOWObject(aCx, obj);
     if (!wrapper) {
       ClearWrapper();
       return nullptr;
     }
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -1291,45 +1291,44 @@ nsImageLoadingContent::UnbindFromTree(bo
 
   UntrackImage(mCurrentRequest);
   UntrackImage(mPendingRequest);
 
   if (mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD)
     doc->UnblockOnload(false);
 }
 
-nsresult
+void
 nsImageLoadingContent::TrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0 */)
 {
   if (!aImage)
-    return NS_OK;
+    return;
 
   MOZ_ASSERT(aImage == mCurrentRequest || aImage == mPendingRequest,
              "Why haven't we heard of this request?");
 
   nsIDocument* doc = GetOurCurrentDoc();
   if (doc && ((aFlags & SKIP_FRAME_CHECK) || GetOurPrimaryFrame()) &&
       (mVisibleCount > 0)) {
     if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
       mCurrentRequestFlags |= REQUEST_IS_TRACKED;
       doc->AddImage(mCurrentRequest);
     }
     if (aImage == mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) {
       mPendingRequestFlags |= REQUEST_IS_TRACKED;
       doc->AddImage(mPendingRequest);
     }
   }
-  return NS_OK;
 }
 
-nsresult
+void
 nsImageLoadingContent::UntrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0 */)
 {
   if (!aImage)
-    return NS_OK;
+    return;
 
   MOZ_ASSERT(aImage == mCurrentRequest || aImage == mPendingRequest,
              "Why haven't we heard of this request?");
 
   // We may not be in the document.  If we outlived our document that's fine,
   // because the document empties out the tracker and unlocks all locked images
   // on destruction.  But if we were never in the document we may need to force
   // discarding the image here, since this is the only chance we have.
@@ -1351,17 +1350,16 @@ nsImageLoadingContent::UntrackImage(imgI
       doc->RemoveImage(mPendingRequest,
                        (aFlags & REQUEST_DISCARD) ? nsIDocument::REQUEST_DISCARD : 0);
     }
     else if (aFlags & REQUEST_DISCARD) {
       // If we're not in the document we may still need to be discarded.
       aImage->RequestDiscard();
     }
   }
-  return NS_OK;
 }
 
 
 void
 nsImageLoadingContent::CreateStaticImageClone(nsImageLoadingContent* aDest) const
 {
   aDest->mCurrentRequest = nsContentUtils::GetStaticRequest(mCurrentRequest);
   aDest->TrackImage(aDest->mCurrentRequest);
--- a/content/base/src/nsImageLoadingContent.h
+++ b/content/base/src/nsImageLoadingContent.h
@@ -332,21 +332,21 @@ protected:
    * frame, there is only one valid use of this: when calling from FrameCreated.
    *
    * REQUEST_DISCARD passed to UntrackImage means we request the discard of the
    * decoded data of the image.
    */
   enum {
     SKIP_FRAME_CHECK = 0x1
   };
-  nsresult TrackImage(imgIRequest* aImage, uint32_t aFlags = 0);
+  void TrackImage(imgIRequest* aImage, uint32_t aFlags = 0);
   enum {
     REQUEST_DISCARD = 0x1
   };
-  nsresult UntrackImage(imgIRequest* aImage, uint32_t aFlags = 0);
+  void UntrackImage(imgIRequest* aImage, uint32_t aFlags = 0);
 
   /* MEMBERS */
   nsRefPtr<imgRequestProxy> mCurrentRequest;
   nsRefPtr<imgRequestProxy> mPendingRequest;
   uint32_t mCurrentRequestFlags;
   uint32_t mPendingRequestFlags;
 
   enum {
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -159,17 +159,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsInProcessTabChildGlobal)
   NS_INTERFACE_MAP_ENTRY(nsIMessageListenerManager)
   NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
   NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender)
   NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager)
   NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager)
-  NS_INTERFACE_MAP_ENTRY(nsIScriptContextPrincipal)
   NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
   NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ContentFrameMessageManager)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(nsInProcessTabChildGlobal, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(nsInProcessTabChildGlobal, nsDOMEventTargetHelper)
--- a/content/base/src/nsInProcessTabChildGlobal.h
+++ b/content/base/src/nsInProcessTabChildGlobal.h
@@ -20,17 +20,16 @@
 #include "nsCOMArray.h"
 #include "nsThreadUtils.h"
 #include "nsIGlobalObject.h"
 #include "nsWeakReference.h"
 
 class nsInProcessTabChildGlobal : public nsDOMEventTargetHelper,
                                   public nsFrameScriptExecutor,
                                   public nsIInProcessContentFrameMessageManager,
-                                  public nsIScriptContextPrincipal,
                                   public nsIGlobalObject,
                                   public nsSupportsWeakReference,
                                   public mozilla::dom::ipc::MessageManagerCallback
 {
 public:
   nsInProcessTabChildGlobal(nsIDocShell* aShell, nsIContent* aOwner,
                             nsFrameMessageManager* aChrome);
   virtual ~nsInProcessTabChildGlobal();
@@ -88,17 +87,16 @@ public:
   {
     return nsDOMEventTargetHelper::AddEventListener(aType, aListener,
                                                     aUseCapture,
                                                     aWantsUntrusted,
                                                     optional_argc);
   }
   using nsDOMEventTargetHelper::AddEventListener;
 
-  virtual nsIScriptObjectPrincipal* GetObjectPrincipal() { return this; }
   virtual JSContext* GetJSContextForEventHandlers() { return mCx; }
   virtual nsIPrincipal* GetPrincipal() { return mPrincipal; }
   void LoadFrameScript(const nsAString& aURL);
   void Disconnect();
   void SendMessageToParent(const nsString& aMessage, bool aSync,
                            const nsString& aJSON,
                            nsTArray<nsString>* aJSONRetVal);
   nsFrameMessageManager* GetInnerManager()
--- a/content/base/src/nsNodeInfoManager.cpp
+++ b/content/base/src/nsNodeInfoManager.cpp
@@ -326,61 +326,72 @@ nsNodeInfoManager::GetNodeInfo(const nsA
   }
 
   return GetNodeInfo(aName, aPrefix, nsid, aNodeType, aNodeInfo);
 }
 
 already_AddRefed<nsINodeInfo>
 nsNodeInfoManager::GetTextNodeInfo()
 {
+  nsCOMPtr<nsINodeInfo> nodeInfo;
+
   if (!mTextNodeInfo) {
-    mTextNodeInfo = GetNodeInfo(nsGkAtoms::textTagName, nullptr,
-                                kNameSpaceID_None,
-                                nsIDOMNode::TEXT_NODE, nullptr).get();
-  }
-  else {
-    NS_ADDREF(mTextNodeInfo);
+    nodeInfo = GetNodeInfo(nsGkAtoms::textTagName, nullptr, kNameSpaceID_None,
+                           nsIDOMNode::TEXT_NODE, nullptr);
+    // Hold a weak ref; the nodeinfo will let us know when it goes away
+    mTextNodeInfo = nodeInfo;
+  } else {
+    nodeInfo = mTextNodeInfo;
   }
 
-  return mTextNodeInfo;
+  return nodeInfo.forget();
 }
 
 already_AddRefed<nsINodeInfo>
 nsNodeInfoManager::GetCommentNodeInfo()
 {
+  nsCOMPtr<nsINodeInfo> nodeInfo;
+
   if (!mCommentNodeInfo) {
-    mCommentNodeInfo = GetNodeInfo(nsGkAtoms::commentTagName, nullptr,
-                                   kNameSpaceID_None,
-                                   nsIDOMNode::COMMENT_NODE, nullptr).get();
+    nodeInfo = GetNodeInfo(nsGkAtoms::commentTagName, nullptr,
+                           kNameSpaceID_None, nsIDOMNode::COMMENT_NODE,
+                           nullptr);
+    // Hold a weak ref; the nodeinfo will let us know when it goes away
+    mCommentNodeInfo = nodeInfo;
   }
   else {
-    NS_ADDREF(mCommentNodeInfo);
+    nodeInfo = mCommentNodeInfo;
   }
 
-  return mCommentNodeInfo;
+  return nodeInfo.forget();
 }
 
 already_AddRefed<nsINodeInfo>
 nsNodeInfoManager::GetDocumentNodeInfo()
 {
+  nsCOMPtr<nsINodeInfo> nodeInfo;
+
   if (!mDocumentNodeInfo) {
     NS_ASSERTION(mDocument, "Should have mDocument!");
-    mDocumentNodeInfo = GetNodeInfo(nsGkAtoms::documentNodeName, nullptr,
-                                    kNameSpaceID_None,
-                                    nsIDOMNode::DOCUMENT_NODE, nullptr).get();
+    nodeInfo = GetNodeInfo(nsGkAtoms::documentNodeName, nullptr,
+                           kNameSpaceID_None, nsIDOMNode::DOCUMENT_NODE,
+                           nullptr);
+    // Hold a weak ref; the nodeinfo will let us know when it goes away
+    mDocumentNodeInfo = nodeInfo;
+
     --mNonDocumentNodeInfos;
     if (!mNonDocumentNodeInfos) {
       mDocument->Release(); // Don't set mDocument to null!
     }
   }
   else {
-    NS_ADDREF(mDocumentNodeInfo);
+    nodeInfo = mDocumentNodeInfo;
   }
 
-  return mDocumentNodeInfo;
+  return nodeInfo.forget();
 }
 
 void
 nsNodeInfoManager::SetDocumentPrincipal(nsIPrincipal *aPrincipal)
 {
   NS_RELEASE(mPrincipal);
   if (!aPrincipal) {
     aPrincipal = mDefaultPrincipal;
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -1057,17 +1057,17 @@ nsScriptLoader::ConvertToUTF16(nsIChanne
 
   int32_t unicodeLength = 0;
 
   nsresult rv =
     unicodeDecoder->GetMaxLength(reinterpret_cast<const char*>(aData),
                                  aLength, &unicodeLength);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (!EnsureStringLength(aString, unicodeLength)) {
+  if (!aString.SetLength(unicodeLength, fallible_t())) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   PRUnichar *ustr = aString.BeginWriting();
 
   rv = unicodeDecoder->Convert(reinterpret_cast<const char*>(aData),
                                (int32_t *) &aLength, ustr,
                                &unicodeLength);
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -842,18 +842,18 @@ NS_IMETHODIMP nsXMLHttpRequest::GetRespo
 }
 
 #ifdef DEBUG
 void
 nsXMLHttpRequest::StaticAssertions()
 {
 #define ASSERT_ENUM_EQUAL(_lc, _uc) \
   MOZ_STATIC_ASSERT(\
-    XMLHttpRequestResponseTypeValues::_lc                \
-    == XMLHttpRequestResponseType(XML_HTTP_RESPONSE_TYPE_ ## _uc), \
+    static_cast<int>(XMLHttpRequestResponseType::_lc)  \
+    == XML_HTTP_RESPONSE_TYPE_ ## _uc, \
     #_uc " should match")
 
   ASSERT_ENUM_EQUAL(_empty, DEFAULT);
   ASSERT_ENUM_EQUAL(Arraybuffer, ARRAYBUFFER);
   ASSERT_ENUM_EQUAL(Blob, BLOB);
   ASSERT_ENUM_EQUAL(Document, DOCUMENT);
   ASSERT_ENUM_EQUAL(Json, JSON);
   ASSERT_ENUM_EQUAL(Text, TEXT);
@@ -894,17 +894,17 @@ NS_IMETHODIMP nsXMLHttpRequest::SetRespo
   SetResponseType(responseType, rv);
   return rv.ErrorCode();
 }
 
 void
 nsXMLHttpRequest::SetResponseType(XMLHttpRequestResponseType aType,
                                   ErrorResult& aRv)
 {
-  SetResponseType(ResponseTypeEnum(aType), aRv);
+  SetResponseType(ResponseTypeEnum(static_cast<int>(aType)), aRv);
 }
 
 void
 nsXMLHttpRequest::SetResponseType(nsXMLHttpRequest::ResponseTypeEnum aResponseType,
                                   ErrorResult& aRv)
 {
   // If the state is not OPENED or HEADERS_RECEIVED raise an
   // INVALID_STATE_ERR exception and terminate these steps.
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -1867,17 +1867,17 @@ CanvasRenderingContext2D::EnsureWritable
     mPath = nullptr;
   }
 }
 
 void
 CanvasRenderingContext2D::EnsureUserSpacePath(const CanvasWindingRule& winding)
 {
   FillRule fillRule = CurrentState().fillRule;
-  if(winding == CanvasWindingRuleValues::Evenodd)
+  if(winding == CanvasWindingRule::Evenodd)
     fillRule = FILL_EVEN_ODD;
 
   if (!mPath && !mPathBuilder && !mDSPathBuilder) {
     EnsureTarget();
     mPathBuilder = mTarget->CreatePathBuilder(fillRule);
   }
 
   if (mPathBuilder) {
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -500,17 +500,17 @@ protected:
   /* This function ensures there is a writable pathbuilder available, this
    * pathbuilder may be working in user space or in device space or
    * device space.
    * After calling this function mPathTransformWillUpdate will be false
    */
   void EnsureWritablePath();
 
   // Ensures a path in UserSpace is available.
-  void EnsureUserSpacePath(const CanvasWindingRule& winding = CanvasWindingRuleValues::Nonzero);
+  void EnsureUserSpacePath(const CanvasWindingRule& winding = CanvasWindingRule::Nonzero);
 
   /**
    * Needs to be called before updating the transform. This makes a call to
    * EnsureTarget() so you don't have to.
    */
   void TransformWillUpdate();
 
   // Report the fillRule has changed.
--- a/content/canvas/test/reftest/reftest.list
+++ b/content/canvas/test/reftest/reftest.list
@@ -132,18 +132,18 @@ pref(webgl.force-layers-readback,true) r
 pref(webgl.force-layers-readback,true) random-if(B2G) == webgl-color-test.html?readback&aa&_____&preserve  wrapper.html?colors.png # Bug 844439
 pref(webgl.force-layers-readback,true) random-if(B2G) == webgl-color-test.html?readback&__&alpha&preserve  wrapper.html?colors.png # Bug 844439
 pref(webgl.force-layers-readback,true) random-if(B2G) == webgl-color-test.html?readback&aa&alpha&preserve  wrapper.html?colors.png # Bug 844439
 
 
 # Check alpha behavior:
 fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0&nogl        wrapper.html?colors.png
 fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0             wrapper.html?colors.png
-fails-if(B2G)  == webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0&nogl        wrapper.html?black.png
-fails-if(B2G)  == webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0             wrapper.html?black.png
+fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0&nogl        wrapper.html?black.png
+fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0             wrapper.html?black.png
 
 fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&nogl        wrapper.html?colors.png
 fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0             wrapper.html?colors.png
 fuzzy-if(B2G,256,83)  == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha&nogl  wrapper.html?white.png
 fails-if(B2G)         == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha       wrapper.html?white.png
 
 fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536)  == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0&nogl  wrapper.html?half-colors.png
 fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536)  == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0       wrapper.html?half-colors.png
--- a/content/events/src/nsDOMDataTransfer.cpp
+++ b/content/events/src/nsDOMDataTransfer.cpp
@@ -490,17 +490,17 @@ nsDOMDataTransfer::MozGetDataAt(const ns
         nsCOMPtr<nsISupports> data;
         formatitem.mData->GetAsISupports(getter_AddRefs(data));
         // Make sure the code that is calling us is same-origin with the data.
         nsCOMPtr<EventTarget> pt = do_QueryInterface(data);
         if (pt) {
           nsresult rv = NS_OK;
           nsIScriptContext* c = pt->GetContextForEventHandlers(&rv);
           NS_ENSURE_TRUE(c && NS_SUCCEEDED(rv), NS_ERROR_DOM_SECURITY_ERR);
-          nsIScriptObjectPrincipal* sp = c->GetObjectPrincipal();
+          nsIScriptObjectPrincipal* sp = c->GetGlobalObject();
           NS_ENSURE_TRUE(sp, NS_ERROR_DOM_SECURITY_ERR);
           nsIPrincipal* dataPrincipal = sp->GetPrincipal();
           NS_ENSURE_TRUE(dataPrincipal, NS_ERROR_DOM_SECURITY_ERR);
           NS_ENSURE_TRUE(principal || (principal = GetCurrentPrincipal(&rv)),
                          NS_ERROR_DOM_SECURITY_ERR);
           NS_ENSURE_SUCCESS(rv, rv);
           bool equals = false;
           NS_ENSURE_TRUE(NS_SUCCEEDED(principal->Equals(dataPrincipal, &equals)) && equals,
--- a/content/html/document/public/nsIImageDocument.idl
+++ b/content/html/document/public/nsIImageDocument.idl
@@ -6,41 +6,45 @@
 #include "nsISupports.idl"
 
 /**
  * @status UNDER_DEVELOPMENT
  */
 
 interface imgIRequest;
 
-[scriptable, uuid(7b80eebc-c98e-4461-8bdb-6e3b6e828890)]
+[scriptable, uuid(87c27f98-37dc-4b64-a8cd-92003624bcee)]
 interface nsIImageDocument : nsISupports {
 
   /* Whether the pref for image resizing has been set. */
   readonly attribute boolean imageResizingEnabled;
 
   /* Whether the image is overflowing visible area. */
   readonly attribute boolean imageIsOverflowing;
 
   /* Whether the image has been resized to fit visible area. */
   readonly attribute boolean imageIsResized;
 
   /* The image request being displayed in the content area */
   readonly attribute imgIRequest imageRequest;
 
   /* Resize the image to fit visible area. */
+  [binaryname(DOMShrinkToFit)]
   void shrinkToFit();
 
   /* Restore image original size. */
+  [binaryname(DOMRestoreImage)]
   void restoreImage();
 
   /* Restore the image, trying to keep a certain pixel in the same position.
    * The coordinate system is that of the shrunken image.
    */
+  [binaryname(DOMRestoreImageTo)]
   void restoreImageTo(in long x, in long y);
 
   /* A helper method for switching between states.
    * The switching logic is as follows. If the image has been resized
    * restore image original size, otherwise if the image is overflowing
    * current visible area resize the image to fit the area.
    */
+  [binaryname(DOMToggleImageSize)]
   void toggleImageSize();
 };  
--- a/content/html/document/src/ImageDocument.cpp
+++ b/content/html/document/src/ImageDocument.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "MediaDocument.h"
+#include "ImageDocument.h"
+#include "mozilla/dom/ImageDocumentBinding.h"
 #include "nsRect.h"
-#include "nsHTMLDocument.h"
-#include "nsIImageDocument.h"
 #include "nsIImageLoadingContent.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIDocumentInlines.h"
 #include "nsDOMTokenList.h"
 #include "nsIDOMHTMLImageElement.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMMouseEvent.h"
@@ -47,117 +46,26 @@
 #define AUTOMATIC_IMAGE_RESIZING_PREF "browser.enable_automatic_image_resizing"
 #define CLICK_IMAGE_RESIZING_PREF "browser.enable_click_image_resizing"
 //XXX A hack needed for Firefox's site specific zoom.
 #define SITE_SPECIFIC_ZOOM "browser.zoom.siteSpecific"
 
 namespace mozilla {
 namespace dom {
  
-class ImageDocument;
-
 class ImageListener : public MediaDocumentStreamListener
 {
 public:
   ImageListener(ImageDocument* aDocument);
   virtual ~ImageListener();
 
   /* nsIRequestObserver */
   NS_IMETHOD OnStartRequest(nsIRequest* request, nsISupports *ctxt);
 };
 
-class ImageDocument : public MediaDocument
-                    , public nsIImageDocument
-                    , public imgINotificationObserver
-                    , public nsIDOMEventListener
-{
-public:
-  ImageDocument();
-  virtual ~ImageDocument();
-
-  NS_DECL_ISUPPORTS_INHERITED
-
-  virtual nsresult Init();
-
-  virtual nsresult StartDocumentLoad(const char*         aCommand,
-                                     nsIChannel*         aChannel,
-                                     nsILoadGroup*       aLoadGroup,
-                                     nsISupports*        aContainer,
-                                     nsIStreamListener** aDocListener,
-                                     bool                aReset = true,
-                                     nsIContentSink*     aSink = nullptr);
-
-  virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject);
-  virtual void Destroy();
-  virtual void OnPageShow(bool aPersisted,
-                          EventTarget* aDispatchStartTarget);
-
-  NS_DECL_NSIIMAGEDOCUMENT
-  NS_DECL_IMGINOTIFICATIONOBSERVER
-
-  // nsIDOMEventListener
-  NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ImageDocument, MediaDocument)
-
-  friend class ImageListener;
-
-  void DefaultCheckOverflowing() { CheckOverflowing(mResizeImageByDefault); }
-
-  virtual nsXPCClassInfo* GetClassInfo();
-protected:
-  virtual nsresult CreateSyntheticDocument();
-
-  nsresult CheckOverflowing(bool changeState);
-
-  void UpdateTitleAndCharset();
-
-  nsresult ScrollImageTo(int32_t aX, int32_t aY, bool restoreImage);
-
-  float GetRatio() {
-    return std::min(mVisibleWidth / mImageWidth,
-                    mVisibleHeight / mImageHeight);
-  }
-
-  void ResetZoomLevel();
-  float GetZoomLevel();
-
-  enum eModeClasses {
-    eNone,
-    eShrinkToFit,
-    eOverflowing
-  };
-  void SetModeClass(eModeClasses mode);
-
-  nsresult OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage);
-  nsresult OnStopRequest(imgIRequest *aRequest, nsresult aStatus);
-
-  nsCOMPtr<nsIContent>          mImageContent;
-
-  float                         mVisibleWidth;
-  float                         mVisibleHeight;
-  int32_t                       mImageWidth;
-  int32_t                       mImageHeight;
-
-  bool                          mResizeImageByDefault;
-  bool                          mClickResizingEnabled;
-  bool                          mImageIsOverflowing;
-  // mImageIsResized is true if the image is currently resized
-  bool                          mImageIsResized;
-  // mShouldResize is true if the image should be resized when it doesn't fit
-  // mImageIsResized cannot be true when this is false, but mImageIsResized
-  // can be false when this is true
-  bool                          mShouldResize;
-  bool                          mFirstResize;
-  // mObservingImageLoader is true while the observer is set.
-  bool                          mObservingImageLoader;
-
-  float                         mOriginalZoomLevel;
-};
-
 ImageListener::ImageListener(ImageDocument* aDocument)
   : MediaDocumentStreamListener(aDocument)
 {
 }
 
 ImageListener::~ImageListener()
 {
 }
@@ -212,17 +120,17 @@ ImageListener::OnStartRequest(nsIRequest
   imageLoader->AddObserver(imgDoc);
   imgDoc->mObservingImageLoader = true;
   imageLoader->LoadImageWithChannel(channel, getter_AddRefs(mNextStream));
 
   return MediaDocumentStreamListener::OnStartRequest(request, ctxt);
 }
 
 ImageDocument::ImageDocument()
-  : MediaDocument(true),
+  : MediaDocument(),
     mOriginalZoomLevel(1.0)
 {
   // NOTE! nsDocument::operator new() zeroes out all members, so don't
   // bother initializing members to 0.
 }
 
 ImageDocument::~ImageDocument()
 {
@@ -235,26 +143,23 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ImageDocument, MediaDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageContent)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ADDREF_INHERITED(ImageDocument, MediaDocument)
 NS_IMPL_RELEASE_INHERITED(ImageDocument, MediaDocument)
 
-DOMCI_NODE_DATA(ImageDocument, ImageDocument)
-
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(ImageDocument)
   NS_HTML_DOCUMENT_INTERFACE_TABLE_BEGIN(ImageDocument)
     NS_INTERFACE_TABLE_ENTRY(ImageDocument, nsIImageDocument)
     NS_INTERFACE_TABLE_ENTRY(ImageDocument, imgINotificationObserver)
     NS_INTERFACE_TABLE_ENTRY(ImageDocument, nsIDOMEventListener)
   NS_OFFSET_AND_INTERFACE_TABLE_END
   NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ImageDocument)
 NS_INTERFACE_MAP_END_INHERITING(MediaDocument)
 
 
 nsresult
 ImageDocument::Init()
 {
   nsresult rv = MediaDocument::Init();
   NS_ENSURE_SUCCESS(rv, rv);
@@ -262,16 +167,22 @@ ImageDocument::Init()
   mResizeImageByDefault = Preferences::GetBool(AUTOMATIC_IMAGE_RESIZING_PREF);
   mClickResizingEnabled = Preferences::GetBool(CLICK_IMAGE_RESIZING_PREF);
   mShouldResize = mResizeImageByDefault;
   mFirstResize = true;
 
   return NS_OK;
 }
 
+JSObject*
+ImageDocument::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return ImageDocumentBinding::Wrap(aCx, aScope, this);
+}
+
 nsresult
 ImageDocument::StartDocumentLoad(const char*         aCommand,
                                  nsIChannel*         aChannel,
                                  nsILoadGroup*       aLoadGroup,
                                  nsISupports*        aContainer,
                                  nsIStreamListener** aDocListener,
                                  bool                aReset,
                                  nsIContentSink*     aSink)
@@ -375,147 +286,169 @@ ImageDocument::OnPageShow(bool aPersiste
       Preferences::GetBool(SITE_SPECIFIC_ZOOM, false) ? 1.0 : GetZoomLevel();
   }
   MediaDocument::OnPageShow(aPersisted, aDispatchStartTarget);
 }
 
 NS_IMETHODIMP
 ImageDocument::GetImageResizingEnabled(bool* aImageResizingEnabled)
 {
-  *aImageResizingEnabled = true;
+  *aImageResizingEnabled = ImageResizingEnabled();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ImageDocument::GetImageIsOverflowing(bool* aImageIsOverflowing)
 {
-  *aImageIsOverflowing = mImageIsOverflowing;
+  *aImageIsOverflowing = ImageIsOverflowing();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ImageDocument::GetImageIsResized(bool* aImageIsResized)
 {
-  *aImageIsResized = mImageIsResized;
+  *aImageIsResized = ImageIsResized();
   return NS_OK;
 }
 
+already_AddRefed<imgIRequest>
+ImageDocument::GetImageRequest(ErrorResult& aRv)
+{
+  nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
+  nsCOMPtr<imgIRequest> imageRequest;
+  if (imageLoader) {
+    aRv = imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
+                                  getter_AddRefs(imageRequest));
+  }
+  return imageRequest.forget();
+}
+
 NS_IMETHODIMP
 ImageDocument::GetImageRequest(imgIRequest** aImageRequest)
 {
-  nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
-  if (imageLoader) {
-    return imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
-                                   aImageRequest);
-  }
-
-  *aImageRequest = nullptr;
-  return NS_OK;
+  ErrorResult rv;
+  *aImageRequest = GetImageRequest(rv).get();
+  return rv.ErrorCode();
 }
 
-NS_IMETHODIMP
+void
 ImageDocument::ShrinkToFit()
 {
   if (!mImageContent) {
-    return NS_OK;
+    return;
   }
   if (GetZoomLevel() != mOriginalZoomLevel && mImageIsResized &&
       !nsContentUtils::IsChildOfSameType(this)) {
-    return NS_OK;
+    return;
   }
 
   // Keep image content alive while changing the attributes.
   nsCOMPtr<nsIContent> imageContent = mImageContent;
   nsCOMPtr<nsIDOMHTMLImageElement> image = do_QueryInterface(mImageContent);
   image->SetWidth(std::max(1, NSToCoordFloor(GetRatio() * mImageWidth)));
   image->SetHeight(std::max(1, NSToCoordFloor(GetRatio() * mImageHeight)));
   
   // The view might have been scrolled when zooming in, scroll back to the
   // origin now that we're showing a shrunk-to-window version.
-  (void) ScrollImageTo(0, 0, false);
+  ScrollImageTo(0, 0, false);
 
   SetModeClass(eShrinkToFit);
   
   mImageIsResized = true;
   
   UpdateTitleAndCharset();
+}
 
+NS_IMETHODIMP
+ImageDocument::DOMShrinkToFit()
+{
+  ShrinkToFit();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-ImageDocument::RestoreImageTo(int32_t aX, int32_t aY)
+ImageDocument::DOMRestoreImageTo(int32_t aX, int32_t aY)
 {
-  return ScrollImageTo(aX, aY, true);
+  RestoreImageTo(aX, aY);
+  return NS_OK;
 }
 
-nsresult
+void
 ImageDocument::ScrollImageTo(int32_t aX, int32_t aY, bool restoreImage)
 {
   float ratio = GetRatio();
 
   if (restoreImage) {
     RestoreImage();
     FlushPendingNotifications(Flush_Layout);
   }
 
   nsIPresShell *shell = GetShell();
   if (!shell)
-    return NS_OK;
+    return;
 
   nsIScrollableFrame* sf = shell->GetRootScrollFrameAsScrollable();
   if (!sf)
-    return NS_OK;
+    return;
 
   nsRect portRect = sf->GetScrollPortRect();
   sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aX/ratio) - portRect.width/2,
                        nsPresContext::CSSPixelsToAppUnits(aY/ratio) - portRect.height/2),
                nsIScrollableFrame::INSTANT);
-  return NS_OK;
 }
 
-NS_IMETHODIMP
+void
 ImageDocument::RestoreImage()
 {
   if (!mImageContent) {
-    return NS_OK;
+    return;
   }
   // Keep image content alive while changing the attributes.
   nsCOMPtr<nsIContent> imageContent = mImageContent;
   imageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::width, true);
   imageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::height, true);
   
   if (mImageIsOverflowing) {
     SetModeClass(eOverflowing);
   }
   else {
     SetModeClass(eNone);
   }
   
   mImageIsResized = false;
   
   UpdateTitleAndCharset();
+}
 
+NS_IMETHODIMP
+ImageDocument::DOMRestoreImage()
+{
+  RestoreImage();
   return NS_OK;
 }
 
-NS_IMETHODIMP
+void
 ImageDocument::ToggleImageSize()
 {
   mShouldResize = true;
   if (mImageIsResized) {
     mShouldResize = false;
     ResetZoomLevel();
     RestoreImage();
   }
   else if (mImageIsOverflowing) {
     ResetZoomLevel();
     ShrinkToFit();
   }
+}
 
+NS_IMETHODIMP
+ImageDocument::DOMToggleImageSize()
+{
+  ToggleImageSize();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ImageDocument::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
 {
   if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     nsCOMPtr<imgIContainer> image;
copy from content/html/document/src/ImageDocument.cpp
copy to content/html/document/src/ImageDocument.h
--- a/content/html/document/src/ImageDocument.cpp
+++ b/content/html/document/src/ImageDocument.h
@@ -1,78 +1,27 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef mozilla_dom_ImageDocument_h
+#define mozilla_dom_ImageDocument_h
 
-#include "MediaDocument.h"
-#include "nsRect.h"
-#include "nsHTMLDocument.h"
-#include "nsIImageDocument.h"
-#include "nsIImageLoadingContent.h"
-#include "nsGenericHTMLElement.h"
-#include "nsIDocumentInlines.h"
-#include "nsDOMTokenList.h"
-#include "nsIDOMHTMLImageElement.h"
-#include "nsIDOMEvent.h"
-#include "nsIDOMKeyEvent.h"
-#include "nsIDOMMouseEvent.h"
-#include "nsIDOMEventListener.h"
-#include "nsGkAtoms.h"
-#include "imgIRequest.h"
-#include "imgILoader.h"
-#include "imgIContainer.h"
 #include "imgINotificationObserver.h"
-#include "nsIPresShell.h"
-#include "nsPresContext.h"
-#include "nsStyleContext.h"
-#include "nsAutoPtr.h"
-#include "nsStyleSet.h"
-#include "nsIChannel.h"
-#include "nsIContentPolicy.h"
-#include "nsContentPolicyUtils.h"
-#include "nsPIDOMWindow.h"
-#include "nsIDOMElement.h"
-#include "nsIDOMHTMLElement.h"
-#include "nsError.h"
-#include "nsURILoader.h"
-#include "nsIDocShell.h"
-#include "nsIContentViewer.h"
-#include "nsIMarkupDocumentViewer.h"
-#include "nsThreadUtils.h"
-#include "nsIScrollableFrame.h"
-#include "nsContentUtils.h"
-#include "mozilla/dom/Element.h"
-#include "mozilla/Preferences.h"
-#include <algorithm>
-
-#define AUTOMATIC_IMAGE_RESIZING_PREF "browser.enable_automatic_image_resizing"
-#define CLICK_IMAGE_RESIZING_PREF "browser.enable_click_image_resizing"
-//XXX A hack needed for Firefox's site specific zoom.
-#define SITE_SPECIFIC_ZOOM "browser.zoom.siteSpecific"
+#include "MediaDocument.h"
+#include "nsIDOMEventListener.h"
+#include "nsIImageDocument.h"
 
 namespace mozilla {
 namespace dom {
- 
-class ImageDocument;
 
-class ImageListener : public MediaDocumentStreamListener
-{
-public:
-  ImageListener(ImageDocument* aDocument);
-  virtual ~ImageListener();
-
-  /* nsIRequestObserver */
-  NS_IMETHOD OnStartRequest(nsIRequest* request, nsISupports *ctxt);
-};
-
-class ImageDocument : public MediaDocument
-                    , public nsIImageDocument
-                    , public imgINotificationObserver
-                    , public nsIDOMEventListener
+class ImageDocument : public MediaDocument,
+                      public nsIImageDocument,
+                      public imgINotificationObserver,
+                      public nsIDOMEventListener
 {
 public:
   ImageDocument();
   virtual ~ImageDocument();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual nsresult Init();
@@ -97,25 +46,49 @@ public:
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ImageDocument, MediaDocument)
 
   friend class ImageListener;
 
   void DefaultCheckOverflowing() { CheckOverflowing(mResizeImageByDefault); }
 
-  virtual nsXPCClassInfo* GetClassInfo();
+  // WebIDL API
+  virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
+    MOZ_OVERRIDE;
+
+  bool ImageResizingEnabled() const
+  {
+    return true;
+  }
+  bool ImageIsOverflowing() const
+  {
+    return mImageIsOverflowing;
+  }
+  bool ImageIsResized() const
+  {
+    return mImageIsResized;
+  }
+  already_AddRefed<imgIRequest> GetImageRequest(ErrorResult& aRv);
+  void ShrinkToFit();
+  void RestoreImage();
+  void RestoreImageTo(int32_t aX, int32_t aY)
+  {
+    ScrollImageTo(aX, aY, true);
+  }
+  void ToggleImageSize();
+
 protected:
   virtual nsresult CreateSyntheticDocument();
 
   nsresult CheckOverflowing(bool changeState);
 
   void UpdateTitleAndCharset();
 
-  nsresult ScrollImageTo(int32_t aX, int32_t aY, bool restoreImage);
+  void ScrollImageTo(int32_t aX, int32_t aY, bool restoreImage);
 
   float GetRatio() {
     return std::min(mVisibleWidth / mImageWidth,
                     mVisibleHeight / mImageHeight);
   }
 
   void ResetZoomLevel();
   float GetZoomLevel();
@@ -148,704 +121,12 @@ protected:
   bool                          mShouldResize;
   bool                          mFirstResize;
   // mObservingImageLoader is true while the observer is set.
   bool                          mObservingImageLoader;
 
   float                         mOriginalZoomLevel;
 };
 
-ImageListener::ImageListener(ImageDocument* aDocument)
-  : MediaDocumentStreamListener(aDocument)
-{
-}
-
-ImageListener::~ImageListener()
-{
-}
-
-NS_IMETHODIMP
-ImageListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
-{
-  NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
-
-  ImageDocument *imgDoc = static_cast<ImageDocument*>(mDocument.get());
-  nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
-  if (!channel) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsPIDOMWindow> domWindow =
-    do_QueryInterface(imgDoc->GetScriptGlobalObject());
-  NS_ENSURE_TRUE(domWindow, NS_ERROR_UNEXPECTED);
-
-  // Do a ShouldProcess check to see whether to keep loading the image.
-  nsCOMPtr<nsIURI> channelURI;
-  channel->GetURI(getter_AddRefs(channelURI));
-
-  nsAutoCString mimeType;
-  channel->GetContentType(mimeType);
-
-  nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
-  nsCOMPtr<nsIPrincipal> channelPrincipal;
-  if (secMan) {
-    secMan->GetChannelPrincipal(channel, getter_AddRefs(channelPrincipal));
-  }
-  
-  int16_t decision = nsIContentPolicy::ACCEPT;
-  nsresult rv = NS_CheckContentProcessPolicy(nsIContentPolicy::TYPE_IMAGE,
-                                             channelURI,
-                                             channelPrincipal,
-                                             domWindow->GetFrameElementInternal(),
-                                             mimeType,
-                                             nullptr,
-                                             &decision,
-                                             nsContentUtils::GetContentPolicy(),
-                                             secMan);
-                                               
-  if (NS_FAILED(rv) || NS_CP_REJECTED(decision)) {
-    request->Cancel(NS_ERROR_CONTENT_BLOCKED);
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(imgDoc->mImageContent);
-  NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
-
-  imageLoader->AddObserver(imgDoc);
-  imgDoc->mObservingImageLoader = true;
-  imageLoader->LoadImageWithChannel(channel, getter_AddRefs(mNextStream));
-
-  return MediaDocumentStreamListener::OnStartRequest(request, ctxt);
-}
-
-ImageDocument::ImageDocument()
-  : MediaDocument(true),
-    mOriginalZoomLevel(1.0)
-{
-  // NOTE! nsDocument::operator new() zeroes out all members, so don't
-  // bother initializing members to 0.
-}
-
-ImageDocument::~ImageDocument()
-{
-}
-
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ImageDocument, MediaDocument)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageContent)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ImageDocument, MediaDocument)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageContent)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_ADDREF_INHERITED(ImageDocument, MediaDocument)
-NS_IMPL_RELEASE_INHERITED(ImageDocument, MediaDocument)
-
-DOMCI_NODE_DATA(ImageDocument, ImageDocument)
-
-NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(ImageDocument)
-  NS_HTML_DOCUMENT_INTERFACE_TABLE_BEGIN(ImageDocument)
-    NS_INTERFACE_TABLE_ENTRY(ImageDocument, nsIImageDocument)
-    NS_INTERFACE_TABLE_ENTRY(ImageDocument, imgINotificationObserver)
-    NS_INTERFACE_TABLE_ENTRY(ImageDocument, nsIDOMEventListener)
-  NS_OFFSET_AND_INTERFACE_TABLE_END
-  NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ImageDocument)
-NS_INTERFACE_MAP_END_INHERITING(MediaDocument)
-
-
-nsresult
-ImageDocument::Init()
-{
-  nsresult rv = MediaDocument::Init();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  mResizeImageByDefault = Preferences::GetBool(AUTOMATIC_IMAGE_RESIZING_PREF);
-  mClickResizingEnabled = Preferences::GetBool(CLICK_IMAGE_RESIZING_PREF);
-  mShouldResize = mResizeImageByDefault;
-  mFirstResize = true;
-
-  return NS_OK;
-}
-
-nsresult
-ImageDocument::StartDocumentLoad(const char*         aCommand,
-                                 nsIChannel*         aChannel,
-                                 nsILoadGroup*       aLoadGroup,
-                                 nsISupports*        aContainer,
-                                 nsIStreamListener** aDocListener,
-                                 bool                aReset,
-                                 nsIContentSink*     aSink)
-{
-  nsresult rv =
-    MediaDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer,
-                                     aDocListener, aReset, aSink);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  mOriginalZoomLevel =
-    Preferences::GetBool(SITE_SPECIFIC_ZOOM, false) ? 1.0 : GetZoomLevel();
-
-  NS_ASSERTION(aDocListener, "null aDocListener");
-  *aDocListener = new ImageListener(this);
-  NS_ADDREF(*aDocListener);
-
-  return NS_OK;
-}
-
-void
-ImageDocument::Destroy()
-{
-  if (mImageContent) {
-    // Remove our event listener from the image content.
-    nsCOMPtr<EventTarget> target = do_QueryInterface(mImageContent);
-    target->RemoveEventListener(NS_LITERAL_STRING("click"), this, false);
-
-    // Break reference cycle with mImageContent, if we have one
-    if (mObservingImageLoader) {
-      nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
-      if (imageLoader) {
-        // Push a null JSContext on the stack so that code that
-        // nsImageLoadingContent doesn't think it's being called by JS.  See
-        // Bug 631241
-        nsCxPusher pusher;
-        pusher.PushNull();
-        imageLoader->RemoveObserver(this);
-      }
-    }
-
-    mImageContent = nullptr;
-  }
-
-  MediaDocument::Destroy();
-}
-
-void
-ImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
-{
-  // If the script global object is changing, we need to unhook our event
-  // listeners on the window.
-  nsCOMPtr<EventTarget> target;
-  if (mScriptGlobalObject &&
-      aScriptGlobalObject != mScriptGlobalObject) {
-    target = do_QueryInterface(mScriptGlobalObject);
-    target->RemoveEventListener(NS_LITERAL_STRING("resize"), this, false);
-    target->RemoveEventListener(NS_LITERAL_STRING("keypress"), this,
-                                false);
-  }
-
-  // Set the script global object on the superclass before doing
-  // anything that might require it....
-  MediaDocument::SetScriptGlobalObject(aScriptGlobalObject);
-
-  if (aScriptGlobalObject) {
-    if (!GetRootElement()) {
-      // Create synthetic document
-#ifdef DEBUG
-      nsresult rv =
-#endif
-        CreateSyntheticDocument();
-      NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document");
-
-      target = do_QueryInterface(mImageContent);
-      target->AddEventListener(NS_LITERAL_STRING("click"), this, false);
-    }
-
-    target = do_QueryInterface(aScriptGlobalObject);
-    target->AddEventListener(NS_LITERAL_STRING("resize"), this, false);
-    target->AddEventListener(NS_LITERAL_STRING("keypress"), this, false);
-
-    if (GetReadyStateEnum() != nsIDocument::READYSTATE_COMPLETE) {
-      LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/ImageDocument.css"));
-      if (!nsContentUtils::IsChildOfSameType(this)) {
-        LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelImageDocument.css"));
-        LinkStylesheet(NS_LITERAL_STRING("chrome://global/skin/media/TopLevelImageDocument.css"));
-      }
-    }
-    BecomeInteractive();
-  }
-}
-
-void
-ImageDocument::OnPageShow(bool aPersisted,
-                          EventTarget* aDispatchStartTarget)
-{
-  if (aPersisted) {
-    mOriginalZoomLevel =
-      Preferences::GetBool(SITE_SPECIFIC_ZOOM, false) ? 1.0 : GetZoomLevel();
-  }
-  MediaDocument::OnPageShow(aPersisted, aDispatchStartTarget);
-}
-
-NS_IMETHODIMP
-ImageDocument::GetImageResizingEnabled(bool* aImageResizingEnabled)
-{
-  *aImageResizingEnabled = true;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-ImageDocument::GetImageIsOverflowing(bool* aImageIsOverflowing)
-{
-  *aImageIsOverflowing = mImageIsOverflowing;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-ImageDocument::GetImageIsResized(bool* aImageIsResized)
-{
-  *aImageIsResized = mImageIsResized;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-ImageDocument::GetImageRequest(imgIRequest** aImageRequest)
-{
-  nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
-  if (imageLoader) {
-    return imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
-                                   aImageRequest);
-  }
-
-  *aImageRequest = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-ImageDocument::ShrinkToFit()
-{
-  if (!mImageContent) {
-    return NS_OK;
-  }
-  if (GetZoomLevel() != mOriginalZoomLevel && mImageIsResized &&
-      !nsContentUtils::IsChildOfSameType(this)) {
-    return NS_OK;
-  }
-
-  // Keep image content alive while changing the attributes.
-  nsCOMPtr<nsIContent> imageContent = mImageContent;
-  nsCOMPtr<nsIDOMHTMLImageElement> image = do_QueryInterface(mImageContent);
-  image->SetWidth(std::max(1, NSToCoordFloor(GetRatio() * mImageWidth)));
-  image->SetHeight(std::max(1, NSToCoordFloor(GetRatio() * mImageHeight)));
-  
-  // The view might have been scrolled when zooming in, scroll back to the
-  // origin now that we're showing a shrunk-to-window version.
-  (void) ScrollImageTo(0, 0, false);
-
-  SetModeClass(eShrinkToFit);
-  
-  mImageIsResized = true;
-  
-  UpdateTitleAndCharset();
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-ImageDocument::RestoreImageTo(int32_t aX, int32_t aY)
-{
-  return ScrollImageTo(aX, aY, true);
-}
-
-nsresult
-ImageDocument::ScrollImageTo(int32_t aX, int32_t aY, bool restoreImage)
-{
-  float ratio = GetRatio();
-
-  if (restoreImage) {
-    RestoreImage();
-    FlushPendingNotifications(Flush_Layout);
-  }
-
-  nsIPresShell *shell = GetShell();
-  if (!shell)
-    return NS_OK;
-
-  nsIScrollableFrame* sf = shell->GetRootScrollFrameAsScrollable();
-  if (!sf)
-    return NS_OK;
-
-  nsRect portRect = sf->GetScrollPortRect();
-  sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aX/ratio) - portRect.width/2,
-                       nsPresContext::CSSPixelsToAppUnits(aY/ratio) - portRect.height/2),
-               nsIScrollableFrame::INSTANT);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-ImageDocument::RestoreImage()
-{
-  if (!mImageContent) {
-    return NS_OK;
-  }
-  // Keep image content alive while changing the attributes.
-  nsCOMPtr<nsIContent> imageContent = mImageContent;
-  imageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::width, true);
-  imageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::height, true);
-  
-  if (mImageIsOverflowing) {
-    SetModeClass(eOverflowing);
-  }
-  else {
-    SetModeClass(eNone);
-  }
-  
-  mImageIsResized = false;
-  
-  UpdateTitleAndCharset();
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-ImageDocument::ToggleImageSize()
-{
-  mShouldResize = true;
-  if (mImageIsResized) {
-    mShouldResize = false;
-    ResetZoomLevel();
-    RestoreImage();
-  }
-  else if (mImageIsOverflowing) {
-    ResetZoomLevel();
-    ShrinkToFit();
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-ImageDocument::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
-{
-  if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
-    nsCOMPtr<imgIContainer> image;
-    aRequest->GetImage(getter_AddRefs(image));
-    return OnStartContainer(aRequest, image);
-  }
-
-  nsDOMTokenList* classList = mImageContent->AsElement()->GetClassList();
-  mozilla::ErrorResult rv;
-  if (aType == imgINotificationObserver::DECODE_COMPLETE) {
-    if (mImageContent) {
-      // Update the background-color of the image only after the
-      // image has been decoded to prevent flashes of just the
-      // background-color.
-      classList->Add(NS_LITERAL_STRING("decoded"), rv);
-      NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
-    }
-  }
-
-  if (aType == imgINotificationObserver::DISCARD) {
-    // mImageContent can be null if the document is already destroyed
-    if (mImageContent) {
-      // Remove any decoded-related styling when the image is unloaded.
-      classList->Remove(NS_LITERAL_STRING("decoded"), rv);
-      NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
-    }
-  }
-
-  if (aType == imgINotificationObserver::LOAD_COMPLETE) {
-    uint32_t reqStatus;
-    aRequest->GetImageStatus(&reqStatus);
-    nsresult status =
-        reqStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
-    return OnStopRequest(aRequest, status);
-  }
-
-  return NS_OK;
-}
-
-void
-ImageDocument::SetModeClass(eModeClasses mode)
-{
-  nsDOMTokenList* classList = mImageContent->AsElement()->GetClassList();
-  mozilla::ErrorResult rv;
-
-  if (mode == eShrinkToFit) {
-    classList->Add(NS_LITERAL_STRING("shrinkToFit"), rv);
-  } else {
-    classList->Remove(NS_LITERAL_STRING("shrinkToFit"), rv);
-  }
-
-  if (mode == eOverflowing) {
-    classList->Add(NS_LITERAL_STRING("overflowing"), rv);
-  } else {
-    classList->Remove(NS_LITERAL_STRING("overflowing"), rv);
-  }
-}
-
-nsresult
-ImageDocument::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage)
-{
-  aImage->GetWidth(&mImageWidth);
-  aImage->GetHeight(&mImageHeight);
-  nsCOMPtr<nsIRunnable> runnable =
-    NS_NewRunnableMethod(this, &ImageDocument::DefaultCheckOverflowing);
-  nsContentUtils::AddScriptRunner(runnable);
-  UpdateTitleAndCharset();
-
-  return NS_OK;
-}
-
-nsresult
-ImageDocument::OnStopRequest(imgIRequest *aRequest,
-                             nsresult aStatus)
-{
-  UpdateTitleAndCharset();
-
-  // mImageContent can be null if the document is already destroyed
-  if (NS_FAILED(aStatus) && mStringBundle && mImageContent) {
-    nsAutoCString src;
-    mDocumentURI->GetSpec(src);
-    NS_ConvertUTF8toUTF16 srcString(src);
-    const PRUnichar* formatString[] = { srcString.get() };
-    nsXPIDLString errorMsg;
-    NS_NAMED_LITERAL_STRING(str, "InvalidImage");
-    mStringBundle->FormatStringFromName(str.get(), formatString, 1,
-                                        getter_Copies(errorMsg));
-
-    mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::alt, errorMsg, false);
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-ImageDocument::HandleEvent(nsIDOMEvent* aEvent)
-{
-  nsAutoString eventType;
-  aEvent->GetType(eventType);
-  if (eventType.EqualsLiteral("resize")) {
-    CheckOverflowing(false);
-  }
-  else if (eventType.EqualsLiteral("click") && mClickResizingEnabled) {
-    ResetZoomLevel();
-    mShouldResize = true;
-    if (mImageIsResized) {
-      int32_t x = 0, y = 0;
-      nsCOMPtr<nsIDOMMouseEvent> event(do_QueryInterface(aEvent));
-      if (event) {
-        event->GetClientX(&x);
-        event->GetClientY(&y);
-        int32_t left = 0, top = 0;
-        nsCOMPtr<nsIDOMHTMLElement> htmlElement =
-          do_QueryInterface(mImageContent);
-        htmlElement->GetOffsetLeft(&left);
-        htmlElement->GetOffsetTop(&top);
-        x -= left;
-        y -= top;
-      }
-      mShouldResize = false;
-      RestoreImageTo(x, y);
-    }
-    else if (mImageIsOverflowing) {
-      ShrinkToFit();
-    }
-  }
-
-  return NS_OK;
-}
-
-nsresult
-ImageDocument::CreateSyntheticDocument()
-{
-  // Synthesize an html document that refers to the image
-  nsresult rv = MediaDocument::CreateSyntheticDocument();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Add the image element
-  Element* body = GetBodyElement();
-  if (!body) {
-    NS_WARNING("no body on image document!");
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsINodeInfo> nodeInfo;
-  nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::img, nullptr,
-                                           kNameSpaceID_XHTML,
-                                           nsIDOMNode::ELEMENT_NODE);
-
-  mImageContent = NS_NewHTMLImageElement(nodeInfo.forget());
-  if (!mImageContent) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
-  NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
-
-  nsAutoCString src;
-  mDocumentURI->GetSpec(src);
-
-  // Push a null JSContext on the stack so that code that runs within
-  // the below code doesn't think it's being called by JS. See bug
-  // 604262.
-  nsCxPusher pusher;
-  pusher.PushNull();
-
-  NS_ConvertUTF8toUTF16 srcString(src);
-  // Make sure not to start the image load from here...
-  imageLoader->SetLoadingEnabled(false);
-  mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::src, srcString, false);
-  mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::alt, srcString, false);
-
-  body->AppendChildTo(mImageContent, false);
-  imageLoader->SetLoadingEnabled(true);
-
-  return NS_OK;
-}
-
-nsresult
-ImageDocument::CheckOverflowing(bool changeState)
-{
-  /* Create a scope so that the style context gets destroyed before we might
-   * call RebuildStyleData.  Also, holding onto pointers to the
-   * presentation through style resolution is potentially dangerous.
-   */
-  {
-    nsIPresShell *shell = GetShell();
-    if (!shell) {
-      return NS_OK;
-    }
-
-    nsPresContext *context = shell->GetPresContext();
-    nsRect visibleArea = context->GetVisibleArea();
-
-    mVisibleWidth = nsPresContext::AppUnitsToFloatCSSPixels(visibleArea.width);
-    mVisibleHeight = nsPresContext::AppUnitsToFloatCSSPixels(visibleArea.height);
-  }
-
-  bool imageWasOverflowing = mImageIsOverflowing;
-  mImageIsOverflowing =
-    mImageWidth > mVisibleWidth || mImageHeight > mVisibleHeight;
-  bool windowBecameBigEnough = imageWasOverflowing && !mImageIsOverflowing;
-
-  if (changeState || mShouldResize || mFirstResize ||
-      windowBecameBigEnough) {
-    if (mImageIsOverflowing && (changeState || mShouldResize)) {
-      ShrinkToFit();
-    }
-    else if (mImageIsResized || mFirstResize || windowBecameBigEnough) {
-      RestoreImage();
-    }
-  }
-  mFirstResize = false;
-
-  return NS_OK;
-}
-
-void 
-ImageDocument::UpdateTitleAndCharset()
-{
-  nsAutoCString typeStr;
-  nsCOMPtr<imgIRequest> imageRequest;
-  nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
-  if (imageLoader) {
-    imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
-                            getter_AddRefs(imageRequest));
-  }
-    
-  if (imageRequest) {
-    nsXPIDLCString mimeType;
-    imageRequest->GetMimeType(getter_Copies(mimeType));
-    ToUpperCase(mimeType);
-    nsXPIDLCString::const_iterator start, end;
-    mimeType.BeginReading(start);
-    mimeType.EndReading(end);
-    nsXPIDLCString::const_iterator iter = end;
-    if (FindInReadable(NS_LITERAL_CSTRING("IMAGE/"), start, iter) && 
-        iter != end) {
-      // strip out "X-" if any
-      if (*iter == 'X') {
-        ++iter;
-        if (iter != end && *iter == '-') {
-          ++iter;
-          if (iter == end) {
-            // looks like "IMAGE/X-" is the type??  Bail out of here.
-            mimeType.BeginReading(iter);
-          }
-        } else {
-          --iter;
-        }
-      }
-      typeStr = Substring(iter, end);
-    } else {
-      typeStr = mimeType;
-    }
-  }
-
-  nsXPIDLString status;
-  if (mImageIsResized) {
-    nsAutoString ratioStr;
-    ratioStr.AppendInt(NSToCoordFloor(GetRatio() * 100));
-
-    const PRUnichar* formatString[1] = { ratioStr.get() };
-    mStringBundle->FormatStringFromName(NS_LITERAL_STRING("ScaledImage").get(),
-                                        formatString, 1,
-                                        getter_Copies(status));
-  }
-
-  static const char* const formatNames[4] = 
-  {
-    "ImageTitleWithNeitherDimensionsNorFile",
-    "ImageTitleWithoutDimensions",
-    "ImageTitleWithDimensions",
-    "ImageTitleWithDimensionsAndFile",
-  };
-
-  MediaDocument::UpdateTitleAndCharset(typeStr, formatNames,
-                                       mImageWidth, mImageHeight, status);
-}
-
-void
-ImageDocument::ResetZoomLevel()
-{
-  nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
-  if (docShell) {
-    if (nsContentUtils::IsChildOfSameType(this)) {
-      return;
-    }
-
-    nsCOMPtr<nsIContentViewer> cv;
-    docShell->GetContentViewer(getter_AddRefs(cv));
-    nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(cv);
-    if (mdv) {
-      mdv->SetFullZoom(mOriginalZoomLevel);
-    }
-  }
-}
-
-float
-ImageDocument::GetZoomLevel()
-{
-  float zoomLevel = mOriginalZoomLevel;
-  nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
-  if (docShell) {
-    nsCOMPtr<nsIContentViewer> cv;
-    docShell->GetContentViewer(getter_AddRefs(cv));
-    nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(cv);
-    if (mdv) {
-      mdv->GetFullZoom(&zoomLevel);
-    }
-  }
-  return zoomLevel;
-}
-
 } // namespace dom
 } // namespace mozilla
 
-DOMCI_DATA(ImageDocument, mozilla::dom::ImageDocument)
-
-nsresult
-NS_NewImageDocument(nsIDocument** aResult)
-{
-  mozilla::dom::ImageDocument* doc = new mozilla::dom::ImageDocument();
-  NS_ADDREF(doc);
-
-  nsresult rv = doc->Init();
-  if (NS_FAILED(rv)) {
-    NS_RELEASE(doc);
-  }
-
-  *aResult = doc;
-
-  return rv;
-}
+#endif /* mozilla_dom_ImageDocument_h */
--- a/content/html/document/src/MediaDocument.cpp
+++ b/content/html/document/src/MediaDocument.cpp
@@ -92,18 +92,18 @@ MediaDocumentStreamListener::OnDataAvail
 const char* const MediaDocument::sFormatNames[4] = 
 {
   "MediaTitleWithNoInfo",    // eWithNoInfo
   "MediaTitleWithFile",      // eWithFile
   "",                        // eWithDim
   ""                         // eWithDimAndFile
 };
 
-MediaDocument::MediaDocument(bool aUseXPConnectToWrap)
-    : nsHTMLDocument(aUseXPConnectToWrap),
+MediaDocument::MediaDocument()
+    : nsHTMLDocument(),
       mDocumentElementInserted(false)
 {
 }
 MediaDocument::~MediaDocument()
 {
 }
 
 nsresult
--- a/content/html/document/src/MediaDocument.h
+++ b/content/html/document/src/MediaDocument.h
@@ -14,17 +14,17 @@
 #define NSMEDIADOCUMENT_PROPERTIES_URI "chrome://global/locale/layout/MediaDocument.properties"
 
 namespace mozilla {
 namespace dom {
 
 class MediaDocument : public nsHTMLDocument
 {
 public:
-  MediaDocument(bool aUseXPConnectToWrap = false);
+  MediaDocument();
   virtual ~MediaDocument();
 
   virtual nsresult Init();
 
   virtual nsresult StartDocumentLoad(const char*         aCommand,
                                      nsIChannel*         aChannel,
                                      nsILoadGroup*       aLoadGroup,
                                      nsISupports*        aContainer,
--- a/content/html/document/src/moz.build
+++ b/content/html/document/src/moz.build
@@ -5,8 +5,11 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'content'
 
 EXPORTS += [
     'nsIHTMLDocument.h',
 ]
 
+EXPORTS.mozilla.dom += [
+    'ImageDocument.h',
+]
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -192,29 +192,27 @@ NS_NewHTMLDocument(nsIDocument** aInstan
   doc->SetLoadedAsData(aLoadedAsData);
 
   return rv;
 }
 
   // NOTE! nsDocument::operator new() zeroes out all members, so don't
   // bother initializing members to 0.
 
-nsHTMLDocument::nsHTMLDocument(bool aUseXPConnectToWrap)
+nsHTMLDocument::nsHTMLDocument()
   : nsDocument("text/html")
 {
   // NOTE! nsDocument::operator new() zeroes out all members, so don't
   // bother initializing members to 0.
 
   mIsRegularHTML = true;
   mDefaultElementType = kNameSpaceID_XHTML;
   mCompatMode = eCompatibility_NavQuirks;
 
-  if (!aUseXPConnectToWrap) {
-    SetIsDOMBinding();
-  }
+  SetIsDOMBinding();
 }
 
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLDocument, nsDocument)
   NS_ASSERTION(!nsCCUncollectableMarker::InGeneration(cb, tmp->GetMarkedCCGeneration()),
                "Shouldn't traverse nsHTMLDocument!");
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImages)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplets)
@@ -255,27 +253,17 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION
   NS_OFFSET_AND_INTERFACE_TABLE_END
   NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLDocument)
 NS_INTERFACE_MAP_END_INHERITING(nsDocument)
 
 JSObject*
 nsHTMLDocument::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
-#ifdef DEBUG
-  // Don't do it yet for image documents
-  nsCOMPtr<nsIImageDocument> imgDoc = do_QueryObject(this);
-  MOZ_ASSERT(!imgDoc, "Who called SetIsDOMBinding()?");
-#endif
-
-  JS::Rooted<JSObject*> obj(aCx, HTMLDocumentBinding::Wrap(aCx, aScope, this));
-  if (obj && !PostCreateWrapper(aCx, obj)) {
-    return nullptr;
-  }
-  return obj;
+  return HTMLDocumentBinding::Wrap(aCx, aScope, this);
 }
 
 nsresult
 nsHTMLDocument::Init()
 {
   nsresult rv = nsDocument::Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -37,17 +37,17 @@ class nsICachingChannel;
 class nsHTMLDocument : public nsDocument,
                        public nsIHTMLDocument,
                        public nsIDOMHTMLDocument
 {
 public:
   using nsDocument::SetDocumentURI;
   using nsDocument::GetPlugins;
 
-  nsHTMLDocument(bool aUseXPConnectToWrap = false);
+  nsHTMLDocument();
   virtual nsresult Init();
 
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
 
   NS_IMETHOD_(nsrefcnt) AddRef(void);
   NS_IMETHOD_(nsrefcnt) Release(void);
 
   virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup);
--- a/content/media/AudioEventTimeline.h
+++ b/content/media/AudioEventTimeline.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef AudioEventTimeline_h_
 #define AudioEventTimeline_h_
 
 #include "mozilla/Assertions.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/TypedEnum.h"
+#include "mozilla/PodOperations.h"
 
 #include "nsTArray.h"
 #include "math.h"
 
 namespace mozilla {
 
 namespace dom {
 
@@ -24,35 +25,60 @@ struct AudioTimelineEvent {
     SetValue,
     LinearRamp,
     ExponentialRamp,
     SetTarget,
     SetValueCurve
   };
 
   AudioTimelineEvent(Type aType, double aTime, float aValue, double aTimeConstant = 0.0,
-                     float aDuration = 0.0, float* aCurve = nullptr, uint32_t aCurveLength = 0)
+                     float aDuration = 0.0, const float* aCurve = nullptr, uint32_t aCurveLength = 0)
     : mType(aType)
     , mTimeConstant(aTimeConstant)
     , mDuration(aDuration)
 #ifdef DEBUG
     , mTimeIsInTicks(false)
 #endif
   {
+    mTime = aTime;
     if (aType == AudioTimelineEvent::SetValueCurve) {
-      mCurve = aCurve;
-      mCurveLength = aCurveLength;
+      SetCurveParams(aCurve, aCurveLength);
     } else {
       mValue = aValue;
-      mTime = aTime;
+    }
+  }
+
+  AudioTimelineEvent(const AudioTimelineEvent& rhs)
+  {
+    PodCopy(this, &rhs, 1);
+    if (rhs.mType == AudioTimelineEvent::SetValueCurve) {
+      SetCurveParams(rhs.mCurve, rhs.mCurveLength);
+    }
+  }
+
+  ~AudioTimelineEvent()
+  {
+    if (mType == AudioTimelineEvent::SetValueCurve) {
+      delete[] mCurve;
     }
   }
 
   bool IsValid() const
   {
+    if (mType == AudioTimelineEvent::SetValueCurve) {
+      if (!mCurve || !mCurveLength) {
+        return false;
+      }
+      for (uint32_t i = 0; i < mCurveLength; ++i) {
+        if (!IsValid(mCurve[i])) {
+          return false;
+        }
+      }
+    }
+
     return IsValid(mTime) &&
            IsValid(mValue) &&
            IsValid(mTimeConstant) &&
            IsValid(mDuration);
   }
 
   template <class TimeType>
   TimeType Time() const;
@@ -60,33 +86,46 @@ struct AudioTimelineEvent {
   void SetTimeInTicks(int64_t aTimeInTicks)
   {
     mTimeInTicks = aTimeInTicks;
 #ifdef DEBUG
     mTimeIsInTicks = true;
 #endif
   }
 
+  void SetCurveParams(const float* aCurve, uint32_t aCurveLength) {
+    mCurveLength = aCurveLength;
+    if (aCurveLength) {
+      mCurve = new float[aCurveLength];
+      PodCopy(mCurve, aCurve, aCurveLength);
+    } else {
+      mCurve = nullptr;
+    }
+  }
+
   Type mType;
   union {
     float mValue;
     uint32_t mCurveLength;
   };
+  // The time for an event can either be in absolute value or in ticks.
+  // Initially the time of the event is always in absolute value.
+  // In order to convert it to ticks, call SetTimeInTicks.  Once this
+  // method has been called for an event, the time cannot be converted
+  // back to absolute value.
   union {
-    // The time for an event can either be in absolute value or in ticks.
-    // Initially the time of the event is always in absolute value.
-    // In order to convert it to ticks, call SetTimeInTicks.  Once this
-    // method has been called for an event, the time cannot be converted
-    // back to absolute value.
-    union {
-      double mTime;
-      int64_t mTimeInTicks;
-    };
-    float* mCurve;
+    double mTime;
+    int64_t mTimeInTicks;
   };
+  // mCurve contains a buffer of SetValueCurve samples.  We sample the
+  // values in the buffer depending on how far along we are in time.
+  // If we're at time T and the event has started as time T0 and has a
+  // duration of D, we sample the buffer at floor(mCurveLength*(T-T0)/D)
+  // if T<T0+D, and just take the last sample in the buffer otherwise.
+  float* mCurve;
   double mTimeConstant;
   double mDuration;
 #ifdef DEBUG
   bool mTimeIsInTicks;
 #endif
 
 private:
   static bool IsValid(double value)
@@ -168,19 +207,17 @@ public:
 
   void SetTargetAtTime(float aTarget, double aStartTime, double aTimeConstant, ErrorResult& aRv)
   {
     InsertEvent(AudioTimelineEvent(AudioTimelineEvent::SetTarget, aStartTime, aTarget, aTimeConstant), aRv);
   }
 
   void SetValueCurveAtTime(const float* aValues, uint32_t aValuesLength, double aStartTime, double aDuration, ErrorResult& aRv)
   {
-    // TODO: implement
-    // Note that we will need to copy the buffer here.
-    // InsertEvent(AudioTimelineEvent(AudioTimelineEvent::SetValueCurve, aStartTime, 0.0f, 0.0f, aDuration, aValues, aValuesLength), aRv);
+    InsertEvent(AudioTimelineEvent(AudioTimelineEvent::SetValueCurve, aStartTime, 0.0f, 0.0f, aDuration, aValues, aValuesLength), aRv);
   }
 
   void CancelScheduledValues(double aStartTime)
   {
     for (unsigned i = 0; i < mEvents.Length(); ++i) {
       if (mEvents[i].mTime >= aStartTime) {
 #ifdef DEBUG
         // Sanity check: the array should be sorted, so all of the following
@@ -209,33 +246,49 @@ public:
 
     bool bailOut = false;
     for (unsigned i = 0; !bailOut && i < mEvents.Length(); ++i) {
       switch (mEvents[i].mType) {
       case AudioTimelineEvent::SetValue:
       case AudioTimelineEvent::SetTarget:
       case AudioTimelineEvent::LinearRamp:
       case AudioTimelineEvent::ExponentialRamp:
+      case AudioTimelineEvent::SetValueCurve:
         if (aTime == mEvents[i].template Time<TimeType>()) {
           // Find the last event with the same time
           do {
             ++i;
           } while (i < mEvents.Length() &&
                    aTime == mEvents[i].template Time<TimeType>());
+
+          // SetTarget nodes can be handled no matter what their next node is (if they have one)
+          if (mEvents[i - 1].mType == AudioTimelineEvent::SetTarget) {
+            // Follow the curve, without regard to the next node
+            return ExponentialApproach(mEvents[i - 1].template Time<TimeType>(),
+                                       mValue, mEvents[i - 1].mValue,
+                                       mEvents[i - 1].mTimeConstant, aTime);
+          }
+
+          // SetValueCurve events can be handled no mattar what their next node is (if they have one)
+          if (mEvents[i - 1].mType == AudioTimelineEvent::SetValueCurve) {
+            return ExtractValueFromCurve(mEvents[i - 1].template Time<TimeType>(),
+                                         mEvents[i - 1].mCurve,
+                                         mEvents[i - 1].mCurveLength,
+                                         mEvents[i - 1].mDuration, aTime);
+          }
+
+          // For other event types
           return mEvents[i - 1].mValue;
         }
         previous = next;
         next = &mEvents[i];
         if (aTime < mEvents[i].template Time<TimeType>()) {
           bailOut = true;
         }
         break;
-      case AudioTimelineEvent::SetValueCurve:
-        // TODO: implement
-        break;
       default:
         MOZ_ASSERT(false, "unreached");
       }
     }
     // Handle the case where the time is past all of the events
     if (!bailOut) {
       previous = next;
       next = nullptr;
@@ -253,27 +306,35 @@ public:
 
     // SetTarget nodes can be handled no matter what their next node is (if they have one)
     if (previous->mType == AudioTimelineEvent::SetTarget) {
       // Follow the curve, without regard to the next node
       return ExponentialApproach(previous->template Time<TimeType>(), mValue, previous->mValue,
                                  previous->mTimeConstant, aTime);
     }
 
+    // SetValueCurve events can be handled no mattar what their next node is (if they have one)
+    if (previous->mType == AudioTimelineEvent::SetValueCurve) {
+      return ExtractValueFromCurve(previous->template Time<TimeType>(),
+                                   previous->mCurve, previous->mCurveLength,
+                                   previous->mDuration, aTime);
+    }
+
     // If the requested time is after all of the existing events
     if (!next) {
       switch (previous->mType) {
       case AudioTimelineEvent::SetValue:
       case AudioTimelineEvent::LinearRamp:
       case AudioTimelineEvent::ExponentialRamp:
         // The value will be constant after the last event
         return previous->mValue;
       case AudioTimelineEvent::SetValueCurve:
-        // TODO: implement
-        return 0.0f;
+        return ExtractValueFromCurve(previous->template Time<TimeType>(),
+                                     previous->mCurve, previous->mCurveLength,
+                                     previous->mDuration, aTime);
       case AudioTimelineEvent::SetTarget:
         MOZ_ASSERT(false, "unreached");
       }
       MOZ_ASSERT(false, "unreached");
     }
 
     // Finally, handle the case where we have both a previous and a next event
 
@@ -293,18 +354,19 @@ public:
     switch (previous->mType) {
     case AudioTimelineEvent::SetValue:
     case AudioTimelineEvent::LinearRamp:
     case AudioTimelineEvent::ExponentialRamp:
       // If the next event type is neither linear or exponential ramp, the
       // value is constant.
       return previous->mValue;
     case AudioTimelineEvent::SetValueCurve:
-      // TODO: implement
-      return 0.0f;
+      return ExtractValueFromCurve(previous->template Time<TimeType>(),
+                                   previous->mCurve, previous->mCurveLength,
+                                   previous->mDuration, aTime);
     case AudioTimelineEvent::SetTarget:
       MOZ_ASSERT(false, "unreached");
     }
 
     MOZ_ASSERT(false, "unreached");
     return 0.0f;
   }
 
@@ -324,53 +386,64 @@ public:
     return v0 * powf(v1 / v0, (t - t0) / (t1 - t0));
   }
 
   static float ExponentialApproach(double t0, double v0, float v1, double timeConstant, double t)
   {
     return v1 + (v0 - v1) * expf(-(t - t0) / timeConstant);
   }
 
-  void ConvertEventTimesToTicks(int64_t (*aConvertor)(double aTime, void* aClosure), void* aClosure)
+  static float ExtractValueFromCurve(double startTime, float* aCurve, uint32_t aCurveLength, double duration, double t)
+  {
+    double ratio = (t - startTime) / duration;
+    MOZ_ASSERT(ratio >= 0.0, "Ratio can never be negative here");
+    if (ratio >= 1.0) {
+      return aCurve[aCurveLength - 1];
+    }
+    return aCurve[uint32_t(aCurveLength * ratio)];
+  }
+
+  void ConvertEventTimesToTicks(int64_t (*aConvertor)(double aTime, void* aClosure), void* aClosure,
+                                int32_t aSampleRate)
   {
     for (unsigned i = 0; i < mEvents.Length(); ++i) {
       mEvents[i].SetTimeInTicks(aConvertor(mEvents[i].template Time<double>(), aClosure));
+      mEvents[i].mTimeConstant *= aSampleRate;
+      mEvents[i].mDuration *= aSampleRate;
     }
   }
 
 private:
   const AudioTimelineEvent* GetPreviousEvent(double aTime) const
   {
     const AudioTimelineEvent* previous = nullptr;
     const AudioTimelineEvent* next = nullptr;
 
     bool bailOut = false;
     for (unsigned i = 0; !bailOut && i < mEvents.Length(); ++i) {
       switch (mEvents[i].mType) {
       case AudioTimelineEvent::SetValue:
       case AudioTimelineEvent::SetTarget:
       case AudioTimelineEvent::LinearRamp:
       case AudioTimelineEvent::ExponentialRamp:
+      case AudioTimelineEvent::SetValueCurve:
         if (aTime == mEvents[i].mTime) {
           // Find the last event with the same time
           do {
             ++i;
           } while (i < mEvents.Length() &&
                    aTime == mEvents[i].mTime);
           return &mEvents[i - 1];
         }
         previous = next;
         next = &mEvents[i];
         if (aTime < mEvents[i].mTime) {
           bailOut = true;
         }
         break;
-      case AudioTimelineEvent::SetValueCurve:
-        // TODO: implement
-        break;
       default:
         MOZ_ASSERT(false, "unreached");
       }
     }
     // Handle the case where the time is past all of the events
     if (!bailOut) {
       previous = next;
     }
@@ -395,18 +468,18 @@ private:
         return;
       }
     }
 
     // Make sure that curve events don't fall in a range which includes other
     // events.
     if (aEvent.mType == AudioTimelineEvent::SetValueCurve) {
       for (unsigned i = 0; i < mEvents.Length(); ++i) {
-        if (mEvents[i].mTime >= aEvent.mTime &&
-            mEvents[i].mTime <= (aEvent.mTime + aEvent.mDuration)) {
+        if (mEvents[i].mTime > aEvent.mTime &&
+            mEvents[i].mTime < (aEvent.mTime + aEvent.mDuration)) {
           aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
           return;
         }
       }
     }
 
     // Make sure that invalid values are not used for exponential curves
     if (aEvent.mType == AudioTimelineEvent::ExponentialRamp) {
--- a/content/media/AudioNodeStream.cpp
+++ b/content/media/AudioNodeStream.cpp
@@ -199,18 +199,18 @@ AudioNodeStream::SetChannelMixingParamet
                                                 ChannelInterpretation aChannelInterpretation)
 {
   // Make sure that we're not clobbering any significant bits by fitting these
   // values in 16 bits.
   MOZ_ASSERT(int(aChannelCountMode) < INT16_MAX);
   MOZ_ASSERT(int(aChannelInterpretation) < INT16_MAX);
 
   mNumberOfInputChannels = aNumberOfChannels;
-  mMixingMode.mChannelCountMode = aChannelCountMode;
-  mMixingMode.mChannelInterpretation = aChannelInterpretation;
+  mChannelCountMode = aChannelCountMode;
+  mChannelInterpretation = aChannelInterpretation;
 }
 
 StreamBuffer::Track*
 AudioNodeStream::EnsureTrack()
 {
   StreamBuffer::Track* track = mBuffer.FindTrack(AUDIO_NODE_STREAM_TRACK_ID);
   if (!track) {
     nsAutoPtr<MediaSegment> segment(new AudioSegment());
@@ -261,17 +261,17 @@ AudioNodeStream::ObtainInputBlock(AudioC
       continue;
     }
 
     inputChunks.AppendElement(chunk);
     outputChannelCount =
       GetAudioChannelsSuperset(outputChannelCount, chunk->mChannelData.Length());
   }
 
-  switch (mMixingMode.mChannelCountMode) {
+  switch (mChannelCountMode) {
   case ChannelCountMode::Explicit:
     // Disregard the output channel count that we've calculated, and just use
     // mNumberOfInputChannels.
     outputChannelCount = mNumberOfInputChannels;
     break;
   case ChannelCountMode::Clamped_max:
     // Clamp the computed output channel count to mNumberOfInputChannels.
     outputChannelCount = std::min(outputChannelCount, mNumberOfInputChannels);
@@ -298,28 +298,28 @@ AudioNodeStream::ObtainInputBlock(AudioC
   // The static storage here should be 1KB, so it's fine
   nsAutoTArray<float, GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE> downmixBuffer;
 
   for (uint32_t i = 0; i < inputChunkCount; ++i) {
     AudioChunk* chunk = inputChunks[i];
     nsAutoTArray<const void*,GUESS_AUDIO_CHANNELS> channels;
     channels.AppendElements(chunk->mChannelData);
     if (channels.Length() < outputChannelCount) {
-      if (mMixingMode.mChannelInterpretation == ChannelInterpretation::Speakers) {
+      if (mChannelInterpretation == ChannelInterpretation::Speakers) {
         AudioChannelsUpMix(&channels, outputChannelCount, nullptr);
         NS_ASSERTION(outputChannelCount == channels.Length(),
                      "We called GetAudioChannelsSuperset to avoid this");
       } else {
         // Fill up the remaining channels by zeros
         for (uint32_t j = channels.Length(); j < outputChannelCount; ++j) {
           channels.AppendElement(silenceChannel);
         }
       }
     } else if (channels.Length() > outputChannelCount) {
-      if (mMixingMode.mChannelInterpretation == ChannelInterpretation::Speakers) {
+      if (mChannelInterpretation == ChannelInterpretation::Speakers) {
         nsAutoTArray<float*,GUESS_AUDIO_CHANNELS> outputChannels;
         outputChannels.SetLength(outputChannelCount);
         downmixBuffer.SetLength(outputChannelCount * WEBAUDIO_BLOCK_SIZE);
         for (uint32_t j = 0; j < outputChannelCount; ++j) {
           outputChannels[j] = &downmixBuffer[j * WEBAUDIO_BLOCK_SIZE];
         }
 
         AudioChannelsDownMix(channels, outputChannels.Elements(),
--- a/content/media/AudioNodeStream.h
+++ b/content/media/AudioNodeStream.h
@@ -50,18 +50,18 @@ public:
                   MediaStreamGraph::AudioNodeStreamKind aKind)
     : ProcessedMediaStream(nullptr),
       mEngine(aEngine),
       mKind(aKind),
       mNumberOfInputChannels(2),
       mMarkAsFinishedAfterThisBlock(false),
       mAudioParamStream(false)
   {
-    mMixingMode.mChannelCountMode = dom::ChannelCountMode::Max;
-    mMixingMode.mChannelInterpretation = dom::ChannelInterpretation::Speakers;
+    mChannelCountMode = dom::ChannelCountMode::Max;
+    mChannelInterpretation = dom::ChannelInterpretation::Speakers;
     // AudioNodes are always producing data
     mHasCurrentData = true;
     MOZ_COUNT_CTOR(AudioNodeStream);
   }
   ~AudioNodeStream();
 
   // Control API
   /**
@@ -117,20 +117,18 @@ protected:
   nsAutoPtr<AudioNodeEngine> mEngine;
   // The last block produced by this node.
   OutputChunks mLastChunks;
   // Whether this is an internal or external stream
   MediaStreamGraph::AudioNodeStreamKind mKind;
   // The number of input channels that this stream requires. 0 means don't care.
   uint32_t mNumberOfInputChannels;
   // The mixing modes
-  struct {
-    dom::ChannelCountMode mChannelCountMode : 16;
-    dom::ChannelInterpretation mChannelInterpretation : 16;
-  } mMixingMode;
+  dom::ChannelCountMode mChannelCountMode;
+  dom::ChannelInterpretation mChannelInterpretation;
   // Whether the stream should be marked as finished as soon
   // as the current time range has been computed block by block.
   bool mMarkAsFinishedAfterThisBlock;
   // Whether the stream is an AudioParamHelper stream.
   bool mAudioParamStream;
 };
 
 }
--- a/content/media/test/crashtests/crashtests.list
+++ b/content/media/test/crashtests/crashtests.list
@@ -1,11 +1,11 @@
-skip-if(Android) load 459439-1.html
+load 459439-1.html
 load 466607-1.html
-skip-if(Android) load 466945-1.html
+load 466945-1.html
 load 468763-1.html
 load 474744-1.html
 HTTP load 481136-1.html # needs to be HTTP to recognize the ogg as an audio file?
 load 493915-1.html
 skip-if(Android) load 495794-1.html
 load 492286-1.xhtml
 load 576612-1.html
 skip-if(Android||B2G) load 691096-1.html # Android sound API can't handle playing large number of sounds at once, bug 852821 for B2G
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -292,19 +292,26 @@ public:
   TrackTicks GetPosition(AudioNodeStream* aStream)
   {
     if (aStream->GetCurrentPosition() < mStart) {
       return aStream->GetCurrentPosition();
     }
     return mStart + mPosition;
   }
 
-  int32_t ComputeFinalOutSampleRate() const
+  uint32_t ComputeFinalOutSampleRate()
   {
-    return static_cast<uint32_t>(IdealAudioRate() / (mPlaybackRate * mDopplerShift));
+    if (mPlaybackRate <= 0 || mPlaybackRate != mPlaybackRate) {
+      mPlaybackRate = 1.0f;
+    }
+    if (mDopplerShift <= 0 || mDopplerShift != mDopplerShift) {
+      mDopplerShift = 1.0f;
+    }
+    return WebAudioUtils::TruncateFloatToInt<uint32_t>(IdealAudioRate() /
+                                                       (mPlaybackRate * mDopplerShift));
   }
 
   bool ShouldResample() const
   {
     return !(mPlaybackRate == 1.0 &&
              mDopplerShift == 1.0 &&
              mSampleRate == IdealAudioRate());
   }
@@ -312,19 +319,21 @@ public:
   void UpdateSampleRateIfNeeded(AudioNodeStream* aStream, uint32_t aChannels)
   {
     if (mPlaybackRateTimeline.HasSimpleValue()) {
       mPlaybackRate = mPlaybackRateTimeline.GetValue();
     } else {
       mPlaybackRate = mPlaybackRateTimeline.GetValueAtTime(aStream->GetCurrentPosition());
     }
 
-    // Make sure the playback rate if something our resampler can work with.
-    if (mPlaybackRate <= 0.0 || mPlaybackRate >= 1024) {
+    // Make sure the playback rate and the doppler shift are something
+    // our resampler can work with.
+    if (ComputeFinalOutSampleRate() == 0) {
       mPlaybackRate = 1.0;
+      mDopplerShift = 1.0;
     }
 
     uint32_t currentOutSampleRate, currentInSampleRate;
     if (ShouldResample()) {
       SpeexResamplerState* resampler = Resampler(aChannels);
       speex_resampler_get_rate(resampler, &currentInSampleRate, &currentOutSampleRate);
       uint32_t finalSampleRate = ComputeFinalOutSampleRate();
       if (currentOutSampleRate != finalSampleRate) {
@@ -414,16 +423,17 @@ AudioBufferSourceNode::AudioBufferSource
               ChannelInterpretation::Speakers)
   , mLoopStart(0.0)
   , mLoopEnd(0.0)
   , mOffset(0.0)
   , mDuration(std::numeric_limits<double>::min())
   , mPlaybackRate(new AudioParam(this, SendPlaybackRateToStream, 1.0f))
   , mLoop(false)
   , mStartCalled(false)
+  , mStopped(false)
   , mOffsetAndDurationRemembered(false)
 {
   mStream = aContext->Graph()->CreateAudioNodeStream(
       new AudioBufferSourceNodeEngine(this, aContext->Destination()),
       MediaStreamGraph::INTERNAL_STREAM);
   mStream->AddMainThreadListener(this);
 }
 
@@ -547,16 +557,41 @@ AudioBufferSourceNode::Stop(double aWhen
   ns->SetStreamTimeParameter(STOP, Context()->DestinationStream(),
                              std::max(0.0, aWhen));
 }
 
 void
 AudioBufferSourceNode::NotifyMainThreadStateChanged()
 {
   if (mStream->IsFinished()) {
+    class EndedEventDispatcher : public nsRunnable
+    {
+    public:
+      explicit EndedEventDispatcher(AudioBufferSourceNode* aNode)
+        : mNode(aNode) {}
+      NS_IMETHODIMP Run()
+      {
+        // If it's not safe to run scripts right now, schedule this to run later
+        if (!nsContentUtils::IsSafeToRunScript()) {
+          nsContentUtils::AddScriptRunner(this);
+          return NS_OK;
+        }
+
+        mNode->DispatchTrustedEvent(NS_LITERAL_STRING("ended"));
+        return NS_OK;
+      }
+    private:
+      nsRefPtr<AudioBufferSourceNode> mNode;
+    };
+    if (!mStopped) {
+      // Only dispatch the ended event once
+      NS_DispatchToMainThread(new EndedEventDispatcher(this));
+      mStopped = true;
+    }
+
     // Drop the playing reference
     // Warning: The below line might delete this.
     mPlayingRef.Drop(this);
   }
 }
 
 void
 AudioBufferSourceNode::SendPlaybackRateToStream(AudioNode* aNode)
--- a/content/media/webaudio/AudioBufferSourceNode.h
+++ b/content/media/webaudio/AudioBufferSourceNode.h
@@ -100,16 +100,18 @@ public:
   }
   void SetLoopEnd(double aEnd)
   {
     mLoopEnd = aEnd;
     SendLoopParametersToStream();
   }
   void SendDopplerShiftToStream(double aDopplerShift);
 
+  IMPL_EVENT_HANDLER(ended)
+
   virtual void NotifyMainThreadStateChanged() MOZ_OVERRIDE;
 
 private:
   friend class AudioBufferSourceNodeEngine;
   // START, OFFSET and DURATION are always set by start() (along with setting
   // mBuffer to something non-null).
   // STOP is set by stop().
   enum EngineParameters {
@@ -137,16 +139,17 @@ private:
   double mLoopEnd;
   double mOffset;
   double mDuration;
   nsRefPtr<AudioBuffer> mBuffer;
   nsRefPtr<AudioParam> mPlaybackRate;
   SelfReference<AudioBufferSourceNode> mPlayingRef; // a reference to self while playing
   bool mLoop;
   bool mStartCalled;
+  bool mStopped;
   bool mOffsetAndDurationRemembered;
 };
 
 }
 }
 
 #endif
 
--- a/content/media/webaudio/AudioParam.h
+++ b/content/media/webaudio/AudioParam.h
@@ -46,17 +46,17 @@ public:
     return mNode->Context();
   }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   // We override SetValueCurveAtTime to convert the Float32Array to the wrapper
   // object.
-  void SetValueCurveAtTime(JSContext* cx, const Float32Array& aValues, double aStartTime, double aDuration, ErrorResult& aRv)
+  void SetValueCurveAtTime(const Float32Array& aValues, double aStartTime, double aDuration, ErrorResult& aRv)
   {
     AudioParamTimeline::SetValueCurveAtTime(aValues.Data(), aValues.Length(),
                                             aStartTime, aDuration, aRv);
     mCallback(mNode);
   }
 
   // We override the rest of the mutating AudioParamTimeline methods in order to make
   // sure that the callback is called every time that this object gets mutated.
--- a/content/media/webaudio/ChannelMergerNode.cpp
+++ b/content/media/webaudio/ChannelMergerNode.cpp
@@ -41,19 +41,20 @@ public:
       return;
     }
     AllocateAudioBlock(channelCount, &aOutput[0]);
 
     // Append each channel in each input to the output
     uint32_t channelIndex = 0;
     for (uint16_t i = 0; i < InputCount(); ++i) {
       for (uint32_t j = 0; j < aInput[i].mChannelData.Length(); ++j) {
-        PodCopy(static_cast<float*>(const_cast<void*>(aOutput[0].mChannelData[channelIndex])),
-                static_cast<const float*>(aInput[i].mChannelData[j]),
-                WEBAUDIO_BLOCK_SIZE);
+        AudioBlockCopyChannelWithScale(
+            static_cast<const float*>(aInput[i].mChannelData[j]),
+            aInput[i].mVolume,
+            static_cast<float*>(const_cast<void*>(aOutput[0].mChannelData[channelIndex])));
         ++channelIndex;
       }
     }
   }
 };
 
 ChannelMergerNode::ChannelMergerNode(AudioContext* aContext,
                                      uint16_t aInputCount)
--- a/content/media/webaudio/ChannelSplitterNode.cpp
+++ b/content/media/webaudio/ChannelSplitterNode.cpp
@@ -31,19 +31,20 @@ public:
   {
     MOZ_ASSERT(aInput.Length() == 1, "Should only have one input port");
 
     aOutput.SetLength(OutputCount());
     for (uint16_t i = 0; i < OutputCount(); ++i) {
       if (i < aInput[0].mChannelData.Length()) {
         // Split out existing channels
         AllocateAudioBlock(1, &aOutput[i]);
-        PodCopy(static_cast<float*>(const_cast<void*>(aOutput[i].mChannelData[0])),
-                static_cast<const float*>(aInput[0].mChannelData[i]),
-                WEBAUDIO_BLOCK_SIZE);
+        AudioBlockCopyChannelWithScale(
+            static_cast<const float*>(aInput[0].mChannelData[i]),
+            aInput[0].mVolume,
+            static_cast<float*>(const_cast<void*>(aOutput[i].mChannelData[0])));
       } else {
         // Pad with silent channels if needed
         aOutput[i].SetNull(WEBAUDIO_BLOCK_SIZE);
       }
     }
   }
 };
 
--- a/content/media/webaudio/PannerNode.cpp
+++ b/content/media/webaudio/PannerNode.cpp
@@ -31,19 +31,19 @@ NS_IMPL_ADDREF_INHERITED(PannerNode, Aud
 NS_IMPL_RELEASE_INHERITED(PannerNode, AudioNode)
 
 class PannerNodeEngine : public AudioNodeEngine
 {
 public:
   explicit PannerNodeEngine(AudioNode* aNode)
     : AudioNodeEngine(aNode)
     // Please keep these default values consistent with PannerNode::PannerNode below.
-    , mPanningModel(PanningModelTypeValues::HRTF)
+    , mPanningModel(PanningModelType::HRTF)
     , mPanningModelFunction(&PannerNodeEngine::HRTFPanningFunction)
-    , mDistanceModel(DistanceModelTypeValues::Inverse)
+    , mDistanceModel(DistanceModelType::Inverse)
     , mDistanceModelFunction(&PannerNodeEngine::InverseGainFunction)
     , mPosition()
     , mOrientation(1., 0., 0.)
     , mVelocity()
     , mRefDistance(1.)
     , mMaxDistance(10000.)
     , mRolloffFactor(1.)
     , mConeInnerAngle(360.)
@@ -57,37 +57,34 @@ public:
   }
 
   virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam) MOZ_OVERRIDE
   {
     switch (aIndex) {
     case PannerNode::PANNING_MODEL:
       mPanningModel = PanningModelType(aParam);
       switch (mPanningModel) {
-        case PanningModelTypeValues::Equalpower:
+        case PanningModelType::Equalpower:
           mPanningModelFunction = &PannerNodeEngine::EqualPowerPanningFunction;
           break;
-        case PanningModelTypeValues::HRTF:
+        case PanningModelType::HRTF:
           mPanningModelFunction = &PannerNodeEngine::HRTFPanningFunction;
           break;
-        case PanningModelTypeValues::Soundfield:
-          mPanningModelFunction = &PannerNodeEngine::SoundfieldPanningFunction;
-          break;
       }
       break;
     case PannerNode::DISTANCE_MODEL:
       mDistanceModel = DistanceModelType(aParam);
       switch (mDistanceModel) {
-        case DistanceModelTypeValues::Inverse:
+        case DistanceModelType::Inverse:
           mDistanceModelFunction = &PannerNodeEngine::InverseGainFunction;
           break;
-        case DistanceModelTypeValues::Linear:
+        case DistanceModelType::Linear:
           mDistanceModelFunction = &PannerNodeEngine::LinearGainFunction;
           break;
-        case DistanceModelTypeValues::Exponential:
+        case DistanceModelType::Exponential:
           mDistanceModelFunction = &PannerNodeEngine::ExponentialGainFunction;
           break;
       }
       break;
     default:
       NS_ERROR("Bad PannerNodeEngine Int32Parameter");
     }
   }
@@ -139,17 +136,16 @@ public:
 
   void GainMonoToStereo(const AudioChunk& aInput, AudioChunk* aOutput,
                         float aGainL, float aGainR);
   void GainStereoToStereo(const AudioChunk& aInput, AudioChunk* aOutput,
                           float aGainL, float aGainR, double aAzimuth);
 
   void EqualPowerPanningFunction(const AudioChunk& aInput, AudioChunk* aOutput);
   void HRTFPanningFunction(const AudioChunk& aInput, AudioChunk* aOutput);
-  void SoundfieldPanningFunction(const AudioChunk& aInput, AudioChunk* aOutput);
 
   float LinearGainFunction(float aDistance);
   float InverseGainFunction(float aDistance);
   float ExponentialGainFunction(float aDistance);
 
   PanningModelType mPanningModel;
   typedef void (PannerNodeEngine::*PanningModelFunction)(const AudioChunk& aInput, AudioChunk* aOutput);
   PanningModelFunction mPanningModelFunction;
@@ -174,18 +170,18 @@ public:
 };
 
 PannerNode::PannerNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Clamped_max,
               ChannelInterpretation::Speakers)
   // Please keep these default values consistent with PannerNodeEngine::PannerNodeEngine above.
-  , mPanningModel(PanningModelTypeValues::HRTF)
-  , mDistanceModel(DistanceModelTypeValues::Inverse)
+  , mPanningModel(PanningModelType::HRTF)
+  , mDistanceModel(DistanceModelType::Inverse)
   , mPosition()
   , mOrientation(1., 0., 0.)
   , mVelocity()
   , mRefDistance(1.)
   , mMaxDistance(10000.)
   , mRolloffFactor(1.)
   , mConeInnerAngle(360.)
   , mConeOuterAngle(360.)
@@ -225,24 +221,16 @@ PannerNodeEngine::InverseGainFunction(fl
 
 float
 PannerNodeEngine::ExponentialGainFunction(float aDistance)
 {
   return pow(aDistance / mRefDistance, -mRolloffFactor);
 }
 
 void
-PannerNodeEngine::SoundfieldPanningFunction(const AudioChunk& aInput,
-                                            AudioChunk* aOutput)
-{
-  // not implemented: noop
-  *aOutput = aInput;
-}
-
-void
 PannerNodeEngine::HRTFPanningFunction(const AudioChunk& aInput,
                                       AudioChunk* aOutput)
 {
   // not implemented: noop
   *aOutput = aInput;
 }
 
 void
--- a/content/media/webaudio/WebAudioUtils.cpp
+++ b/content/media/webaudio/WebAudioUtils.cpp
@@ -48,13 +48,13 @@ WebAudioUtils::StreamPositionToDestinati
 void
 WebAudioUtils::ConvertAudioParamToTicks(AudioParamTimeline& aParam,
                                         AudioNodeStream* aSource,
                                         AudioNodeStream* aDest)
 {
   ConvertTimeToTickHelper ctth;
   ctth.mSourceStream = aSource;
   ctth.mDestinationStream = aDest;
-  aParam.ConvertEventTimesToTicks(ConvertTimeToTickHelper::Convert, &ctth);
+  aParam.ConvertEventTimesToTicks(ConvertTimeToTickHelper::Convert, &ctth, IdealAudioRate());
 }
 
 }
 }
--- a/content/media/webaudio/WebAudioUtils.h
+++ b/content/media/webaudio/WebAudioUtils.h
@@ -3,16 +3,19 @@
 /* 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/. */
 
 #ifndef WebAudioUtils_h_
 #define WebAudioUtils_h_
 
 #include <cmath>
+#include <limits>
+#include "mozilla/TypeTraits.h"
+#include "mozilla/Assertions.h"
 #include "AudioParamTimeline.h"
 #include "MediaSegment.h"
 
 namespace mozilla {
 
 class AudioNodeStream;
 
 namespace dom {
@@ -90,15 +93,109 @@ struct WebAudioUtils {
 
   /**
    * Convert a stream position into the time coordinate of the destination
    * stream.
    */
   static double StreamPositionToDestinationTime(TrackTicks aSourcePosition,
                                                 AudioNodeStream* aSource,
                                                 AudioNodeStream* aDestination);
+
+  /**
+   * Converts a floating point value to an integral type in a safe and
+   * platform agnostic way.  The following program demonstrates the kinds
+   * of ways things can go wrong depending on the CPU architecture you're
+   * compiling for:
+   *
+   * #include <stdio.h>
+   * volatile float r;
+   * int main()
+   * {
+   *   unsigned int q;
+   *   r = 1e100;
+   *   q = r;
+   *   printf("%f %d\n", r, q);
+   *   r = -1e100;
+   *   q = r;
+   *   printf("%f %d\n", r, q);
+   *   r = 1e15;
+   *   q = r;
+   *   printf("%f %x\n", r, q);
+   *   r = 0/0.;
+   *   q = r;
+   *   printf("%f %d\n", r, q);
+   * }
+   *
+   * This program, when compiled for unsigned int, generates the following
+   * results depending on the architecture:
+   *
+   * x86 and x86-64
+   * ---
+   *  inf 0
+   *  -inf 0
+   *  999999995904.000000 -727384064 d4a50000
+   *  nan 0
+   *
+   * ARM
+   * ---
+   *  inf -1
+   *  -inf 0
+   *  999999995904.000000 -1
+   *  nan 0
+   *
+   * When compiled for int, this program generates the following results:
+   *
+   * x86 and x86-64
+   * ---
+   *  inf -2147483648
+   *  -inf -2147483648
+   *  999999995904.000000 -2147483648
+   *  nan -2147483648
+   *
+   * ARM
+   * ---
+   *  inf 2147483647
+   *  -inf -2147483648
+   *  999999995904.000000 2147483647
+   *  nan 0
+   *
+   * Note that the caller is responsible to make sure that the value
+   * passed to this function is not a NaN.  This function will abort if
+   * it sees a NaN.
+   */
+  template <typename IntType, typename FloatType>
+  static IntType TruncateFloatToInt(FloatType f)
+  {
+    using namespace std;
+
+    MOZ_STATIC_ASSERT((mozilla::IsIntegral<IntType>::value == true),
+                      "IntType must be an integral type");
+    MOZ_STATIC_ASSERT((mozilla::IsFloatingPoint<FloatType>::value == true),
+                      "FloatType must be a floating point type");
+
+    if (f != f) {
+      // It is the responsibility of the caller to deal with NaN values.
+      // If we ever get to this point, we have a serious bug to fix.
+      NS_RUNTIMEABORT("We should never see a NaN here");
+    }
+
+    if (f > FloatType(numeric_limits<IntType>::max())) {
+      // If the floating point value is outside of the range of maximum
+      // integral value for this type, just clamp to the maximum value.
+      return numeric_limits<IntType>::max();
+    }
+
+    if (f < FloatType(numeric_limits<IntType>::min())) {
+      // If the floating point value is outside of the range of minimum
+      // integral value for this type, just clamp to the minimum value.
+      return numeric_limits<IntType>::min();
+    }
+
+    // Otherwise, this conversion must be well defined.
+    return IntType(f);
+  }
 };
 
 }
 }
 
 #endif
 
--- a/content/media/webaudio/compiledtest/TestAudioEventTimeline.cpp
+++ b/content/media/webaudio/compiledtest/TestAudioEventTimeline.cpp
@@ -4,16 +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/. */
 
 #include "AudioEventTimeline.h"
 #include "TestHarness.h"
 #include <sstream>
 #include <limits>
 
+using namespace mozilla;
 using namespace mozilla::dom;
 using std::numeric_limits;
 
 // Some simple testing primitives
 void ok(bool val, const char* msg)
 {
   if (val) {
     passed(msg);
@@ -85,66 +86,75 @@ typedef AudioEventTimeline<ErrorResultMo
 void TestSpecExample()
 {
   // First, run the basic tests
   Timeline timeline(10.0f);
   is(timeline.Value(), 10.0f, "Correct default value returned");
 
   ErrorResultMock rv;
 
+  float curve[] = { -1.0f, 0.0f, 1.0f };
+
   // This test is copied from the example in the Web Audio spec
   const double t0 = 0.0,
                t1 = 0.1,
                t2 = 0.2,
                t3 = 0.3,
                t4 = 0.4,
                t5 = 0.6,
-               t6 = 0.7/*,
-               t7 = 1.0*/;
+               t6 = 0.7,
+               t7 = 1.0;
   timeline.SetValueAtTime(0.2f, t0, rv);
   is(rv, NS_OK, "SetValueAtTime succeeded");
   timeline.SetValueAtTime(0.3f, t1, rv);
   is(rv, NS_OK, "SetValueAtTime succeeded");
   timeline.SetValueAtTime(0.4f, t2, rv);
   is(rv, NS_OK, "SetValueAtTime succeeded");
   timeline.LinearRampToValueAtTime(1.0f, t3, rv);
   is(rv, NS_OK, "LinearRampToValueAtTime succeeded");
   timeline.LinearRampToValueAtTime(0.15f, t4, rv);
   is(rv, NS_OK, "LinearRampToValueAtTime succeeded");
   timeline.ExponentialRampToValueAtTime(0.75f, t5, rv);
   is(rv, NS_OK, "ExponentialRampToValueAtTime succeeded");
   timeline.ExponentialRampToValueAtTime(0.05f, t6, rv);
   is(rv, NS_OK, "ExponentialRampToValueAtTime succeeded");
-  // TODO: Add the SetValueCurveAtTime test
+  timeline.SetValueCurveAtTime(curve, ArrayLength(curve), t6, t7 - t6, rv);
+  is(rv, NS_OK, "SetValueCurveAtTime succeeded");
 
   is(timeline.GetValueAtTime(0.0), 0.2f, "Correct value");
   is(timeline.GetValueAtTime(0.05), 0.2f, "Correct value");
   is(timeline.GetValueAtTime(0.1), 0.3f, "Correct value");
   is(timeline.GetValueAtTime(0.15), 0.3f, "Correct value");
   is(timeline.GetValueAtTime(0.2), 0.4f, "Correct value");
   is(timeline.GetValueAtTime(0.25), (0.4f + 1.0f) / 2, "Correct value");
   is(timeline.GetValueAtTime(0.3), 1.0f, "Correct value");
   is(timeline.GetValueAtTime(0.35), (1.0f + 0.15f) / 2, "Correct value");
   is(timeline.GetValueAtTime(0.4), 0.15f, "Correct value");
   is(timeline.GetValueAtTime(0.45), (0.15f * powf(0.75f / 0.15f, 0.05f / 0.2f)), "Correct value");
   is(timeline.GetValueAtTime(0.5), (0.15f * powf(0.75f / 0.15f, 0.5f)), "Correct value");
   is(timeline.GetValueAtTime(0.55), (0.15f * powf(0.75f / 0.15f, 0.15f / 0.2f)), "Correct value");
   is(timeline.GetValueAtTime(0.6), 0.75f, "Correct value");
   is(timeline.GetValueAtTime(0.65), (0.75f * powf(0.05 / 0.75f, 0.5f)), "Correct value");
-  is(timeline.GetValueAtTime(0.7), 0.05f, "Correct value");
-  is(timeline.GetValueAtTime(1.0), 0.05f, "Correct value");
+  is(timeline.GetValueAtTime(0.7), -1.0f, "Correct value");
+  is(timeline.GetValueAtTime(0.9), 0.0f, "Correct value");
+  is(timeline.GetValueAtTime(1.0), 1.0f, "Correct value");
 }
 
 void TestInvalidEvents()
 {
   MOZ_STATIC_ASSERT(numeric_limits<float>::has_quiet_NaN, "Platform must have a quiet NaN");
   const float NaN = numeric_limits<float>::quiet_NaN();
   const float Infinity = numeric_limits<float>::infinity();
   Timeline timeline(10.0f);
 
+  float curve[] = { -1.0f, 0.0f, 1.0f };
+  float badCurve1[] = { -1.0f, NaN, 1.0f };
+  float badCurve2[] = { -1.0f, Infinity, 1.0f };
+  float badCurve3[] = { -1.0f, -Infinity, 1.0f };
+
   ErrorResultMock rv;
 
   timeline.SetValueAtTime(NaN, 0.1, rv);
   is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
   timeline.SetValueAtTime(Infinity, 0.1, rv);
   is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
   timeline.SetValueAtTime(-Infinity, 0.1, rv);
   is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
@@ -169,17 +179,36 @@ void TestInvalidEvents()
   timeline.SetTargetAtTime(-Infinity, 0.4, 1.0, rv);
   is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
   timeline.SetTargetAtTime(0.4f, NaN, 1.0, rv);
   is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
   timeline.SetTargetAtTime(0.4f, Infinity, 1.0, rv);
   is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
   timeline.SetTargetAtTime(0.4f, -Infinity, 1.0, rv);
   is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
-  // TODO: Test SetValueCurveAtTime
+  timeline.SetValueCurveAtTime(nullptr, 0, 1.0, 1.0, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetValueCurveAtTime(badCurve1, ArrayLength(badCurve1), 1.0, 1.0, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetValueCurveAtTime(badCurve2, ArrayLength(badCurve2), 1.0, 1.0, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetValueCurveAtTime(badCurve3, ArrayLength(badCurve3), 1.0, 1.0, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetValueCurveAtTime(curve, ArrayLength(curve), NaN, 1.0, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetValueCurveAtTime(curve, ArrayLength(curve), Infinity, 1.0, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetValueCurveAtTime(curve, ArrayLength(curve), -Infinity, 1.0, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, NaN, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, Infinity, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
+  timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, -Infinity, rv);
+  is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
 }
 
 void TestEventReplacement()
 {
   Timeline timeline(10.0f);
 
   ErrorResultMock rv;
 
--- a/content/media/webaudio/test/Makefile.in
+++ b/content/media/webaudio/test/Makefile.in
@@ -15,34 +15,39 @@ MOCHITEST_FILES := \
   test_bug808374.html \
   test_bug827541.html \
   test_bug839753.html \
   test_bug845960.html \
   test_bug856771.html \
   test_bug866570.html \
   test_bug866737.html \
   test_bug867089.html \
+  test_bug867174.html \
   test_bug867203.html \
   test_analyserNode.html \
   test_AudioBuffer.html \
   test_AudioContext.html \
   test_AudioListener.html \
   test_AudioParam.html \
   test_audioParamExponentialRamp.html \
   test_audioParamLinearRamp.html \
+  test_audioParamSetCurveAtTime.html \
+  test_audioParamSetTargetAtTime.html \
   test_audioBufferSourceNode.html \
   test_audioBufferSourceNodeLazyLoopParam.html \
   test_audioBufferSourceNodeLoop.html \
   test_audioBufferSourceNodeLoopStartEnd.html \
   test_audioBufferSourceNodeLoopStartEndSame.html \
   test_audioBufferSourceNodeNullBuffer.html \
   test_badConnect.html \
   test_biquadFilterNode.html \
   test_channelMergerNode.html \
+  test_channelMergerNodeWithVolume.html \
   test_channelSplitterNode.html \
+  test_channelSplitterNodeWithVolume.html \
   test_currentTime.html \
   test_delayNode.html \
   test_delayNodeWithGain.html \
   test_dynamicsCompressorNode.html \
   test_gainNode.html \
   test_mediaDecoding.html \
   test_mixingRules.html \
   test_nodeToParamConnection.html \
--- a/content/media/webaudio/test/test_audioBufferSourceNode.html
+++ b/content/media/webaudio/test/test_audioBufferSourceNode.html
@@ -17,16 +17,29 @@ addLoadEvent(function() {
   var context = new AudioContext();
   var buffer = context.createBuffer(1, 2048, context.sampleRate);
   for (var i = 0; i < 2048; ++i) {
     buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
   }
 
   var source = context.createBufferSource();
 
+  var eventsReceived = 0;
+  function eventReceived() {
+    if (++eventsReceived == 2) {
+      SpecialPowers.clearUserPref("media.webaudio.enabled");
+      SimpleTest.finish();
+    }
+  }
+
+  source.onended = function(e) {
+    is(e.target, source, "Correct target for the ended event");
+    eventReceived();
+  };
+
   var sp = context.createScriptProcessor(2048);
   source.start(0);
   source.buffer = buffer;
   source.connect(sp);
   sp.connect(context.destination);
   sp.onaudioprocess = function(e) {
     compareBuffers(e.inputBuffer.getChannelData(0), buffer.getChannelData(0));
     compareBuffers(e.inputBuffer.getChannelData(1), buffer.getChannelData(0));
@@ -35,18 +48,17 @@ addLoadEvent(function() {
     sp.onaudioprocess = function(e) {
       var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
       compareBuffers(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
       compareBuffers(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
 
       sp.onaudioprocess = null;
       sp.disconnect(context.destination);
 
-      SpecialPowers.clearUserPref("media.webaudio.enabled");
-      SimpleTest.finish();
+      eventReceived();
     };
   };
 });
 
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_audioParamSetCurveAtTime.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test AudioParam.linearRampToValue</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context = new AudioContext();
+
+  var T0 = 0;
+  var duration = 1024 / context.sampleRate;
+
+  var sourceBuffer = context.createBuffer(1, 2048, context.sampleRate);
+  for (var i = 0; i < 2048; ++i) {
+    sourceBuffer.getChannelData(0)[i] = 1;
+  }
+  var curve = new Float32Array(100);
+  for (var i = 0; i < 100; ++i) {
+    curve[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
+  }
+  var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
+  for (var i = 0; i < 2048; ++i) {
+    var t = i / context.sampleRate;
+    expectedBuffer.getChannelData(0)[i] = curve[Math.min(99, Math.floor(100 * Math.min(1.0, (t - T0) / duration)))];
+  }
+
+  var destination = context.destination;
+
+  var source = context.createBufferSource();
+  source.buffer = sourceBuffer;
+
+  var gain = context.createGain();
+  gain.gain.setValueCurveAtTime(curve, T0, duration);
+
+  var sp = context.createScriptProcessor(2048, 1);
+  source.connect(gain);
+  gain.connect(sp);
+  sp.connect(destination);
+
+  source.start(0);
+  sp.onaudioprocess = function(e) {
+    is(e.inputBuffer.numberOfChannels, 1, "Correct input channel count");
+    compareBuffers(e.inputBuffer.getChannelData(0), expectedBuffer.getChannelData(0));
+
+    sp.onaudioprocess = null;
+
+    SpecialPowers.clearUserPref("media.webaudio.enabled");
+    SimpleTest.finish();
+  };
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_audioParamSetTargetAtTime.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test AudioParam.setTargetAtTime</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context = new AudioContext();
+
+  var V0 = 0.1;
+  var V1 = 0.9;
+  var T0 = 0;
+  var T1 = 2048 / context.sampleRate;
+  var TimeConstant = 10;
+
+  var sourceBuffer = context.createBuffer(1, 2048, context.sampleRate);
+  for (var i = 0; i < 2048; ++i) {
+    sourceBuffer.getChannelData(0)[i] = 1;
+  }
+  var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
+  for (var i = 0; i < 2048; ++i) {
+    var t = i / context.sampleRate;
+    expectedBuffer.getChannelData(0)[i] = V1 + (V0 - V1) * Math.exp(-(t - T0) / TimeConstant);
+  }
+
+  var destination = context.destination;
+
+  var source = context.createBufferSource();
+  source.buffer = sourceBuffer;
+
+  var gain = context.createGain();
+  gain.gain.value = V0;
+  gain.gain.setTargetAtTime(V1, T0, TimeConstant);
+
+  var sp = context.createScriptProcessor(2048, 1);
+  source.connect(gain);
+  gain.connect(sp);
+  sp.connect(destination);
+
+  source.start(0);
+  sp.onaudioprocess = function(e) {
+    is(e.inputBuffer.numberOfChannels, 1, "Correct input channel count");
+    compareBuffers(e.inputBuffer.getChannelData(0), expectedBuffer.getChannelData(0));
+
+    sp.onaudioprocess = null;
+
+    SpecialPowers.clearUserPref("media.webaudio.enabled");
+    SimpleTest.finish();
+  };
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_bug867174.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Crashtest for bug 867174</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  var ctx = new AudioContext();
+
+  var source = ctx.createBufferSource();
+  var buffer = ctx.createBuffer(2, 2048, 8000);
+  source.playbackRate.setTargetValueAtTime(0, 2, 3);
+  var sp = ctx.createScriptProcessor();
+  source.connect(sp);
+  sp.connect(ctx.destination);
+  source.start(0);
+
+  sp.onaudioprocess = function(e) {
+    // Now set the buffer
+    source.buffer = buffer;
+
+    ok(true, "We did not crash.");
+    sp.onaudioprocess = null;
+    SpecialPowers.clearUserPref("media.webaudio.enabled");
+    SimpleTest.finish();
+  };
+});
+
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_channelMergerNodeWithVolume.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test ChannelMergerNode</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context = new AudioContext();
+  var buffers = [];
+  var expectedBuffers = [];
+  for (var j = 0; j < 4; ++j) {
+    var buffer = context.createBuffer(2, 2048, context.sampleRate);
+    var expectedBuffer = context.createBuffer(2, 2048, context.sampleRate);
+    for (var i = 0; i < 2048; ++i) {
+      buffer.getChannelData(0)[i] = Math.sin(440 * 2 * (j + 1) * Math.PI * i / context.sampleRate);
+      expectedBuffer.getChannelData(0)[i] = buffer.getChannelData(0)[i] / 2;
+      // Second channel is silent
+    }
+    buffers.push(buffer);
+    expectedBuffers.push(expectedBuffer);
+  }
+  var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
+
+  var destination = context.destination;
+
+  var merger = context.createChannelMerger();
+  is(merger.channelCount, 2, "merger node has 2 input channels by default");
+  is(merger.channelCountMode, "max", "Correct channelCountMode for the merger node");
+  is(merger.channelInterpretation, "speakers", "Correct channelCountInterpretation for the merger node");
+
+  for (var i = 0; i < 4; ++i) {
+    var source = context.createBufferSource();
+    source.buffer = buffers[i];
+    var gain = context.createGain();
+    gain.gain.value = 0.5;
+    source.connect(gain);
+    gain.connect(merger, 0, i);
+    source.start(0);
+  }
+
+  var sp = context.createScriptProcessor(2048, 8);
+  merger.connect(sp);
+  sp.connect(destination);
+
+  sp.onaudioprocess = function(e) {
+    is(e.inputBuffer.numberOfChannels, 8, "Correct input channel count");
+    for (var i = 0; i < 4; ++i) {
+      compareBuffers(e.inputBuffer.getChannelData(i * 2), expectedBuffers[i].getChannelData(0));
+      compareBuffers(e.inputBuffer.getChannelData(i * 2 + 1), emptyBuffer.getChannelData(0));
+    }
+
+    sp.onaudioprocess = null;
+
+    SpecialPowers.clearUserPref("media.webaudio.enabled");
+    SimpleTest.finish();
+  };
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_channelSplitterNodeWithVolume.html
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test ChannelSplitterNode</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context = new AudioContext();
+  var buffer = context.createBuffer(4, 2048, context.sampleRate);
+  var expectedBuffer = context.createBuffer(4, 2048, context.sampleRate);
+  for (var j = 0; j < 4; ++j) {
+    for (var i = 0; i < 2048; ++i) {
+      buffer.getChannelData(j)[i] = Math.sin(440 * 2 * (j + 1) * Math.PI * i / context.sampleRate);
+      expectedBuffer.getChannelData(j)[i] = buffer.getChannelData(j)[i] / 2;
+    }
+  }
+  var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
+
+  var destination = context.destination;
+
+  var source = context.createBufferSource();
+
+  var splitter = context.createChannelSplitter();
+  is(splitter.channelCount, 2, "splitter node has 2 input channels by default");
+  is(splitter.channelCountMode, "max", "Correct channelCountMode for the splitter node");
+  is(splitter.channelInterpretation, "speakers", "Correct channelCountInterpretation for the splitter node");
+
+  source.buffer = buffer;
+  var gain = context.createGain();
+  gain.gain.value = 0.5;
+  source.connect(gain);
+  gain.connect(splitter);
+
+  var channelsSeen = 0;
+  function createHandler(i) {
+    return function(e) {
+      is(e.inputBuffer.numberOfChannels, 1, "Correct input channel count");
+      if (i < 4) {
+        compareBuffers(e.inputBuffer.getChannelData(0), expectedBuffer.getChannelData(i));
+      } else {
+        compareBuffers(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
+      }
+      e.target.onaudioprocess = null;
+      ++channelsSeen;
+
+      if (channelsSeen == 6) {
+        SpecialPowers.clearUserPref("media.webaudio.enabled");
+        SimpleTest.finish();
+      }
+    };
+  }
+
+  for (var i = 0; i < 6; ++i) {
+    var sp = context.createScriptProcessor(2048, 1);
+    splitter.connect(sp, i);
+    sp.onaudioprocess = createHandler(i);
+    sp.connect(destination);
+  }
+
+  source.start(0);
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/svg/document/src/SVGDocument.cpp
+++ b/content/svg/document/src/SVGDocument.cpp
@@ -99,21 +99,17 @@ SVGDocument::Clone(nsINodeInfo *aNodeInf
   NS_ENSURE_SUCCESS(rv, rv);
 
   return CallQueryInterface(clone.get(), aResult);
 }
 
 JSObject*
 SVGDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
-  JS::Rooted<JSObject*> obj(aCx, SVGDocumentBinding::Wrap(aCx, aScope, this));
-  if (obj && !PostCreateWrapper(aCx, obj)) {
-    return nullptr;
-  }
-  return obj;
+  return SVGDocumentBinding::Wrap(aCx, aScope, this);
 }
 
 } // namespace dom
 } // namespace mozilla
 
 ////////////////////////////////////////////////////////////////////////
 // Exported creation functions
 
--- a/content/xml/document/src/XMLDocument.cpp
+++ b/content/xml/document/src/XMLDocument.cpp
@@ -624,17 +624,13 @@ XMLDocument::Clone(nsINodeInfo *aNodeInf
   clone->mAsync = mAsync;
 
   return CallQueryInterface(clone.get(), aResult);
 }
 
 JSObject*
 XMLDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
-  JS::Rooted<JSObject*> obj(aCx, XMLDocumentBinding::Wrap(aCx, aScope, this));
-  if (obj && !PostCreateWrapper(aCx, obj)) {
-    return nullptr;
-  }
-  return obj;
+  return XMLDocumentBinding::Wrap(aCx, aScope, this);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/xslt/src/base/txDouble.cpp
+++ b/content/xslt/src/base/txDouble.cpp
@@ -174,17 +174,17 @@ void txDouble::toString(double aValue, n
     else {
         // trailing zeros, total length given by intDigits
         length = intDigits;
     }
     if (aValue < 0)
         ++length;
     // grow the string
     uint32_t oldlength = aDest.Length();
-    if (!EnsureStringLength(aDest, oldlength + length))
+    if (!aDest.SetLength(oldlength + length, mozilla::fallible_t()))
         return; // out of memory
     nsAString::iterator dest;
     aDest.BeginWriting(dest).advance(int32_t(oldlength));
     if (aValue < 0) {
         *dest = '-'; ++dest;
     }
     int i;
     // leading zeros
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -4757,17 +4757,13 @@ XULDocument::GetBoxObjectFor(nsIDOMEleme
     nsCOMPtr<Element> el = do_QueryInterface(aElement);
     *aResult = GetBoxObjectFor(el, rv).get();
     return rv.ErrorCode();
 }
 
 JSObject*
 XULDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
-  JS::Rooted<JSObject*> obj(aCx, XULDocumentBinding::Wrap(aCx, aScope, this));
-  if (obj && !PostCreateWrapper(aCx, obj)) {
-    return nullptr;
-  }
-  return obj;
+  return XULDocumentBinding::Wrap(aCx, aScope, this);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4489,17 +4489,17 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, 
     nsCString errorPageUrl("about:");
     errorPageUrl.AppendASCII(aErrorPage);
     errorPageUrl.AppendLiteral("?e=");
 
     errorPageUrl.AppendASCII(escapedError.get());
     errorPageUrl.AppendLiteral("&u=");
     errorPageUrl.AppendASCII(escapedUrl.get());
     if (!escapedCSSClass.IsEmpty()) {
-        errorPageUrl.AppendASCII("&s=");
+        errorPageUrl.AppendLiteral("&s=");
         errorPageUrl.AppendASCII(escapedCSSClass.get());
     }
     errorPageUrl.AppendLiteral("&c=");
     errorPageUrl.AppendASCII(escapedCharset.get());
     errorPageUrl.AppendLiteral("&d=");
     errorPageUrl.AppendASCII(escapedDescription.get());
 
     nsCOMPtr<nsIURI> errorPageURI;
--- a/dom/base/DOMRequest.cpp
+++ b/dom/base/DOMRequest.cpp
@@ -82,20 +82,20 @@ DOMRequest::WrapObject(JSContext* aCx, J
 NS_IMPL_EVENT_HANDLER(DOMRequest, success)
 NS_IMPL_EVENT_HANDLER(DOMRequest, error)
 
 NS_IMETHODIMP
 DOMRequest::GetReadyState(nsAString& aReadyState)
 {
   DOMRequestReadyState readyState = ReadyState();
   switch (readyState) {
-    case DOMRequestReadyStateValues::Pending:
+    case DOMRequestReadyState::Pending:
       aReadyState.AssignLiteral("pending");
       break;
-    case DOMRequestReadyStateValues::Done:
+    case DOMRequestReadyState::Done:
       aReadyState.AssignLiteral("done");
       break;
     default:
       MOZ_NOT_REACHED("Unrecognized readyState.");
   }
 
   return NS_OK;
 }
--- a/dom/base/DOMRequest.h
+++ b/dom/base/DOMRequest.h
@@ -42,18 +42,18 @@ public:
   }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   // WebIDL Interface
   DOMRequestReadyState ReadyState() const
   {
-    return mDone ? DOMRequestReadyStateValues::Done
-                 : DOMRequestReadyStateValues::Pending;
+    return mDone ? DOMRequestReadyState::Done
+                 : DOMRequestReadyState::Pending;
   }
 
   JS::Value Result(JSContext* = nullptr) const
   {
     NS_ASSERTION(mDone || mResult == JSVAL_VOID,
                "Result should be undefined when pending");
     return mResult;
   }
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -216,18 +216,16 @@
 #include "nsIDOMSVGAnimatedNumber.h"
 #include "nsIDOMSVGAnimatedRect.h"
 #include "nsIDOMSVGAnimatedString.h"
 #include "nsIDOMTimeEvent.h"
 #include "nsIDOMSVGLength.h"
 #include "nsIDOMSVGNumber.h"
 #include "nsIDOMSVGRect.h"
 
-#include "nsIImageDocument.h"
-
 // Storage includes
 #include "DOMStorage.h"
 
 // Device Storage
 #include "nsIDOMDeviceStorage.h"
 
 // Drag and drop
 #include "nsIDOMDataTransfer.h"
@@ -657,19 +655,16 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(CSSRect, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // DOM Chrome Window class.
   NS_DEFINE_CLASSINFO_DATA(ChromeWindow, nsWindowSH,
                            DEFAULT_SCRIPTABLE_FLAGS |
                            WINDOW_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(ImageDocument, nsHTMLDocumentSH,
-                           DOCUMENT_SCRIPTABLE_FLAGS)
-
 #ifdef MOZ_XUL
   NS_DEFINE_CLASSINFO_DATA(XULTemplateBuilder, nsDOMGenericSH,
                            DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(XULTreeBuilder, nsDOMGenericSH,
                            DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
@@ -1878,22 +1873,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeWindow, nsIDOMWindow)
     DOM_CLASSINFO_WINDOW_MAP_ENTRIES(true)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMChromeWindow)
 #ifdef MOZ_WEBSPEECH
     DOM_CLASSINFO_MAP_ENTRY(nsISpeechSynthesisGetter)
 #endif
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(ImageDocument, nsIImageDocument)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument)
-    DOM_CLASSINFO_MAP_ENTRY(nsIImageDocument)
-    DOM_CLASSINFO_DOCUMENT_MAP_ENTRIES
-  DOM_CLASSINFO_MAP_END
-
 #ifdef MOZ_XUL
   DOM_CLASSINFO_MAP_BEGIN(XULTemplateBuilder, nsIXULTemplateBuilder)
     DOM_CLASSINFO_MAP_ENTRY(nsIXULTemplateBuilder)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(XULTreeBuilder, nsIXULTreeBuilder)
     DOM_CLASSINFO_MAP_ENTRY(nsIXULTreeBuilder)
     DOM_CLASSINFO_MAP_ENTRY(nsIXULTemplateBuilder)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -77,18 +77,16 @@ DOMCI_CLASS(CRMFObject)
 DOMCI_CLASS(Crypto)
 
 // Rect object used by getComputedStyle
 DOMCI_CLASS(CSSRect)
 
 // DOM Chrome Window class, almost identical to Window
 DOMCI_CLASS(ChromeWindow)
 
-DOMCI_CLASS(ImageDocument)
-
 #ifdef MOZ_XUL
 DOMCI_CLASS(XULTemplateBuilder)
 DOMCI_CLASS(XULTreeBuilder)
 #endif
 
 // DOMStringList object
 DOMCI_CLASS(DOMStringList)
 
--- a/dom/base/nsDOMJSUtils.h
+++ b/dom/base/nsDOMJSUtils.h
@@ -24,32 +24,16 @@ GetScriptContextFromJSContext(JSContext 
     do_QueryInterface(static_cast<nsISupports *>
                                  (::JS_GetContextPrivate(cx)));
 
   // This will return a pointer to something that's about to be
   // released, but that's ok here.
   return scx;
 }
 
-inline nsIScriptContextPrincipal*
-GetScriptContextPrincipalFromJSContext(JSContext *cx)
-{
-  if (!(::JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)) {
-    return nullptr;
-  }
-
-  nsCOMPtr<nsIScriptContextPrincipal> scx =
-    do_QueryInterface(static_cast<nsISupports *>
-                                 (::JS_GetContextPrivate(cx)));
-
-  // This will return a pointer to something that's about to be
-  // released, but that's ok here.
-  return scx;
-}
-
 // A factory function for turning a JS::Value argv into an nsIArray
 // but also supports an effecient way of extracting the original argv.
 // Bug 312003 describes why this must be "void *", but argv will be cast to
 // JS::Value* and the args are found at:
 //    ((JS::Value*)aArgv)[0], ..., ((JS::Value*)aArgv)[aArgc - 1]
 // The resulting object will take a copy of the array, and ensure each
 // element is rooted.
 // Optionally, aArgv may be NULL, in which case the array is allocated and
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -24,44 +24,29 @@ class nsIVariant;
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
 class nsIScriptObjectPrincipal;
 class nsIDOMWindow;
 class nsIURI;
 
 typedef void (*nsScriptTerminationFunc)(nsISupports* aRef);
 
-#define NS_ISCRIPTCONTEXTPRINCIPAL_IID \
-  { 0xd012cdb3, 0x8f1e, 0x4440, \
-    { 0x8c, 0xbd, 0x32, 0x7f, 0x98, 0x1d, 0x37, 0xb4 } }
-
-class nsIScriptContextPrincipal : public nsISupports
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTCONTEXTPRINCIPAL_IID)
-
-  virtual nsIScriptObjectPrincipal* GetObjectPrincipal() = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal,
-                              NS_ISCRIPTCONTEXTPRINCIPAL_IID)
-
 #define NS_ISCRIPTCONTEXT_IID \
-{ 0x5eb84406, 0x118f, 0x4eb5, \
- { 0xab, 0xd5, 0xdd, 0xc9, 0x14, 0xfe, 0xfe, 0xe4 } }
+{ 0x821c5be9, 0xbf9e, 0x4041, \
+  { 0x9f, 0xf2, 0x1f, 0xca, 0x39, 0xf7, 0x89, 0xf3 } }
 
 /* This MUST match JSVERSION_DEFAULT.  This version stuff if we don't
    know what language we have is a little silly... */
 #define SCRIPTVERSION_DEFAULT JSVERSION_DEFAULT
 
 /**
  * It is used by the application to initialize a runtime and run scripts.
  * A script runtime would implement this interface.
  */
-class nsIScriptContext : public nsIScriptContextPrincipal
+class nsIScriptContext : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTCONTEXT_IID)
 
   /**
    * Compile and execute a script.
    *
    * @param aScript a string representing the script to be executed
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -968,17 +968,17 @@ static const char js_pccounts_chrome_str
 static const char js_jit_hardening_str[]      = JS_OPTIONS_DOT_STR "jit_hardening";
 static const char js_memlog_option_str[]      = JS_OPTIONS_DOT_STR "mem.log";
 static const char js_memnotify_option_str[]   = JS_OPTIONS_DOT_STR "mem.notify";
 static const char js_disable_explicit_compartment_gc[] =
   JS_OPTIONS_DOT_STR "mem.disable_explicit_compartment_gc";
 static const char js_baselinejit_content_str[] = JS_OPTIONS_DOT_STR "baselinejit.content";
 static const char js_baselinejit_chrome_str[]  = JS_OPTIONS_DOT_STR "baselinejit.chrome";
 static const char js_ion_content_str[]        = JS_OPTIONS_DOT_STR "ion.content";
-static const char js_asmjs_content_str[]      = JS_OPTIONS_DOT_STR "experimental_asmjs";
+static const char js_asmjs_content_str[]      = JS_OPTIONS_DOT_STR "asmjs";
 static const char js_ion_parallel_compilation_str[] = JS_OPTIONS_DOT_STR "ion.parallel_compilation";
 
 int
 nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
 {
   nsJSContext *context = reinterpret_cast<nsJSContext *>(data);
   uint32_t oldDefaultJSOptions = context->mDefaultJSOptions;
   uint32_t newDefaultJSOptions = oldDefaultJSOptions;
@@ -1224,17 +1224,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSContext, tmp->GetCCRefcnt())
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobalObjectRef)
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mContext");
   nsContentUtils::XPConnect()->NoteJSContext(tmp->mContext, cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext)
   NS_INTERFACE_MAP_ENTRY(nsIScriptContext)
-  NS_INTERFACE_MAP_ENTRY(nsIScriptContextPrincipal)
   NS_INTERFACE_MAP_ENTRY(nsIXPCScriptNotify)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptContext)
 NS_INTERFACE_MAP_END
 
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSContext)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSContext)
 
@@ -1327,23 +1326,16 @@ nsJSContext::EvaluateString(const nsAStr
   ScriptEvaluated(true);
 
   // Wrap the return value into whatever compartment mContext was in.
   if (aRetValue && !JS_WrapValue(mContext, aRetValue))
     return NS_ERROR_OUT_OF_MEMORY;
   return NS_OK;
 }
 
-nsIScriptObjectPrincipal*
-nsJSContext::GetObjectPrincipal()
-{
-  nsCOMPtr<nsIScriptObjectPrincipal> prin = do_QueryInterface(GetGlobalObject());
-  return prin;
-}
-
 nsresult
 nsJSContext::CompileScript(const PRUnichar* aText,
                            int32_t aTextLength,
                            nsIPrincipal *aPrincipal,
                            const char *aURL,
                            uint32_t aLineNo,
                            uint32_t aVersion,
                            JS::MutableHandle<JSScript*> aScriptObject,
@@ -2544,35 +2536,42 @@ nsJSContext::ShrinkGCBuffersNow()
 {
   PROFILER_LABEL("GC", "ShrinkGCBuffersNow");
 
   KillShrinkGCBuffersTimer();
 
   JS::ShrinkGCBuffers(nsJSRuntime::sRuntime);
 }
 
-// Return true if any JSContext has a "global object" with a gray
-// parent. The intent is to look for JS Object windows. We don't merge
+// Return true if there exists a JSContext with a default global whose current
+// inner is gray. The intent is to look for JS Object windows. We don't merge
 // system compartments, so we don't use them to trigger merging CCs.
 static bool
-AnyGrayGlobalParent()
+AnyGrayCurrentContentInnerWindows()
 {
   if (!nsJSRuntime::sRuntime) {
     return false;
   }
   JSContext *iter = nullptr;
   JSContext *cx;
   while ((cx = JS_ContextIterator(nsJSRuntime::sRuntime, &iter))) {
-    if (JSObject *global = JS_GetGlobalObject(cx)) {
-      if (JSObject *parent = js::GetObjectParent(global)) {
-        if (JS::GCThingIsMarkedGray(parent) &&
-            !js::IsSystemCompartment(js::GetObjectCompartment(parent))) {
-          return true;
-        }
-      }
+    // Skip anything without an nsIScriptContext, as well as any scx whose
+    // NativeGlobal() is not an outer window (this happens with XUL Prototype
+    // compilation scopes, for example, which we're not interested in).
+    nsIScriptContext *scx = GetScriptContextFromJSContext(cx);
+    JS::RootedObject global(cx, scx ? scx->GetNativeGlobal() : nullptr);
+    if (!global || !js::GetObjectParent(global)) {
+      continue;
+    }
+    // Grab the inner from the outer.
+    global = JS_ObjectToInnerObject(cx, global);
+    MOZ_ASSERT(!js::GetObjectParent(global));
+    if (JS::GCThingIsMarkedGray(global) &&
+        !js::IsSystemCompartment(js::GetObjectCompartment(global))) {
+      return true;
     }
   }
   return false;
 }
 
 static bool
 DoMergingCC(bool aForced)
 {
@@ -2593,17 +2592,17 @@ DoMergingCC(bool aForced)
   }
 
   if (sUnmergedNeeded > 0) {
     sUnmergedNeeded--;
     sMergedInARow = 0;
     return false;
   }
 
-  if (!aForced && AnyGrayGlobalParent()) {
+  if (!aForced && AnyGrayCurrentContentInnerWindows()) {
     sMergedInARow++;
     return true;
   } else {
     sMergedInARow = 0;
     return false;
   }
 
 }
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -39,18 +39,16 @@ public:
   nsJSContext(JSRuntime* aRuntime, bool aGCOnDestruction,
               nsIScriptGlobalObject* aGlobalObject);
   virtual ~nsJSContext();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSContext,
                                                          nsIScriptContext)
 
-  virtual ns