Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Thu, 02 Aug 2012 13:47:20 -0700
changeset 113492 3da9a96f6c3fd6fbe0003249b12a59dd2749153c
parent 113491 1c42952f712b93b3ae046c8627b76d272bc57fcc (current diff)
parent 107206 0f66a7ecf8de7a71dd9847e2664e93258a8a38db (diff)
child 113493 fa872ef28a96e3ea4d0514b74ddb760f9df5529d
push id239
push userakeybl@mozilla.com
push dateThu, 03 Jan 2013 21:54:43 +0000
treeherdermozilla-release@3a7b66445659 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
accessible/src/base/TextAttrs.cpp
accessible/src/base/TextAttrs.h
accessible/src/base/nsAccUtils.cpp
accessible/src/base/nsAccUtils.h
accessible/src/base/nsAccessNode.cpp
accessible/src/base/nsAccessNode.h
accessible/src/base/nsCoreUtils.cpp
accessible/src/base/nsCoreUtils.h
accessible/src/generic/Accessible.h
accessible/src/generic/ApplicationAccessible.cpp
accessible/src/generic/DocAccessible.h
accessible/src/html/HTMLTableAccessible.cpp
accessible/src/xul/XULTreeGridAccessible.cpp
browser/app/profile/firefox.js
browser/base/content/browser.xul
build/mobile/devicemanagerSUT.py
content/base/public/nsIFrameMessageManager.idl
content/base/src/Makefile.in
content/base/src/nsBlobProtocolHandler.cpp
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsFrameMessageManager.h
content/base/src/nsInProcessTabChildGlobal.cpp
content/base/test/Makefile.in
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
content/canvas/test/test_canvas.html
content/html/content/public/nsHTMLMediaElement.h
content/html/content/src/nsHTMLMediaElement.cpp
dom/Makefile.in
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/base/nsGlobalWindow.cpp
dom/base/nsJSEnvironment.cpp
dom/bindings/Codegen.py
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBEvents.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBObjectStore.h
dom/indexedDB/IndexedDatabaseManager.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/Makefile.in
dom/ipc/PBrowser.ipdl
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/plugins/base/PluginPRLibrary.h
dom/plugins/base/nsJSNPRuntime.cpp
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsPluginNativeWindowGtk2.cpp
dom/plugins/ipc/PluginInstanceChild.cpp
dom/plugins/ipc/PluginInstanceChild.h
dom/plugins/ipc/PluginLibrary.h
dom/plugins/ipc/PluginModuleChild.cpp
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
dom/wifi/WifiWorker.js
dom/workers/File.cpp
dom/workers/WorkerPrivate.cpp
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderEGL.cpp
gfx/layers/d3d10/CanvasLayerD3D10.cpp
gfx/layers/d3d10/LayerManagerD3D10.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxQtPlatform.cpp
gfx/thebes/gfxQtPlatform.h
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
js/ipc/ObjectWrapperParent.cpp
js/src/builtin/Eval.cpp
js/src/ctypes/Library.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/gc/Root.h
js/src/jsapi-tests/testBug604087.cpp
js/src/jsapi-tests/testConservativeGC.cpp
js/src/jsapi-tests/testDebugger.cpp
js/src/jsapi-tests/testProfileStrings.cpp
js/src/jsapi-tests/testVersion.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsiter.cpp
js/src/jsmath.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsopcode.tbl
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jspubtd.h
js/src/jsreflect.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jsutil.h
js/src/jsweakmap.cpp
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/ScopeObject.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCQuickStubs.h
js/xpconnect/src/XPCVariant.cpp
js/xpconnect/src/qsgen.py
layout/build/nsLayoutModule.cpp
layout/generic/nsColumnSetFrame.cpp
layout/inspector/src/inCSSValueSearch.cpp
layout/reftests/bugs/reftest.list
layout/reftests/ogg-video/reftest.list
layout/reftests/svg/reftest.list
layout/reftests/webm-video/reftest.list
layout/style/nsCSSParser.cpp
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsCSSRules.cpp
layout/style/nsCSSRules.h
layout/style/nsCSSScanner.cpp
layout/style/nsCSSScanner.h
layout/style/test/Makefile.in
layout/tools/reftest/reftest.js
mobile/android/base/FloatUtils.java
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/LauncherShortcuts.java.in
mobile/android/base/Makefile.in
modules/libpref/src/init/all.js
mozglue/android/nsGeckoUtils.cpp
storage/src/mozStorageStatementRow.cpp
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJNI.cpp
widget/android/nsWindow.cpp
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
widget/cocoa/nsNativeThemeCocoa.mm
widget/gtk2/nsWindow.cpp
widget/qt/mozqwidget.cpp
widget/qt/nsWindow.cpp
xpcom/io/nsLocalFileCommon.cpp
--- a/accessible/src/base/Logging.cpp
+++ b/accessible/src/base/Logging.cpp
@@ -14,16 +14,17 @@
 
 #include "nsDocShellLoadTypes.h"
 #include "nsIChannel.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsISelectionPrivate.h"
 #include "nsTraceRefcntImpl.h"
 #include "nsIWebProgress.h"
 #include "prenv.h"
+#include "nsIDocShellTreeItem.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Logging helpers
 
 static PRUint32 sModules = 0;
--- a/accessible/src/base/TextAttrs.cpp
+++ b/accessible/src/base/TextAttrs.cpp
@@ -203,16 +203,19 @@ TextAttrsMgr::LangTextAttr::
   mIsRootDefined =  !mRootNativeValue.IsEmpty();
 
   if (aElm) {
     nsCoreUtils::GetLanguageFor(aElm, mRootContent, mNativeValue);
     mIsDefined = !mNativeValue.IsEmpty();
   }
 }
 
+TextAttrsMgr::LangTextAttr::
+  ~LangTextAttr() {}
+
 bool
 TextAttrsMgr::LangTextAttr::
   GetValueFor(Accessible* aAccessible, nsString* aValue)
 {
   nsCoreUtils::GetLanguageFor(aAccessible->GetContent(), mRootContent, *aValue);
   return !aValue->IsEmpty();
 }
 
--- a/accessible/src/base/TextAttrs.h
+++ b/accessible/src/base/TextAttrs.h
@@ -1,22 +1,26 @@
 /* -*- 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 nsTextAttrs_h_
 #define nsTextAttrs_h_
 
-#include "nsIContent.h"
-#include "nsIFrame.h"
-#include "nsIPersistentProperties2.h"
+#include "nsCOMPtr.h"
+#include "nsColor.h"
 #include "nsStyleConsts.h"
 
 class HyperTextAccessible;
+class nsIFrame;
+class nsIPersistentProperties;
+class nsIContent;
+class Accessible;
+class nsDeviceContext;
 
 namespace mozilla {
 namespace a11y {
 
 /**
  * Used to expose text attributes for the hyper text accessible (see
  * HyperTextAccessible class).
  *
@@ -188,17 +192,17 @@ protected:
   /**
    * Class is used for the work with 'language' text attribute.
    */
   class LangTextAttr : public TTextAttr<nsString>
   {
   public:
     LangTextAttr(HyperTextAccessible* aRoot, nsIContent* aRootElm,
                  nsIContent* aElm);
-    virtual ~LangTextAttr() { }
+    virtual ~LangTextAttr();
 
   protected:
 
     // TextAttr
     virtual bool GetValueFor(Accessible* aAccessible, nsString* aValue);
     virtual void ExposeValue(nsIPersistentProperties* aAttributes,
                              const nsString& aValue);
 
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -10,16 +10,17 @@
 #include "nsARIAMap.h"
 #include "nsCoreUtils.h"
 #include "DocAccessible.h"
 #include "HyperTextAccessible.h"
 #include "nsIAccessibleTypes.h"
 #include "Role.h"
 #include "States.h"
 #include "TextLeafAccessible.h"
+#include "nsIMutableArray.h"
 
 #include "nsIDOMXULContainerElement.h"
 #include "nsIDOMXULSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsComponentManagerUtils.h"
 
 namespace dom = mozilla::dom;
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -11,16 +11,17 @@
 #include "nsIAccessibleText.h"
 #include "nsIAccessibleTable.h"
 
 #include "nsAccessibilityService.h"
 #include "nsCoreUtils.h"
 
 #include "mozilla/dom/Element.h"
 #include "nsIDocShell.h"
+#include "nsIDocShellTreeItem.h"
 #include "nsIDOMNode.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIPresShell.h"
 #include "nsPoint.h"
 
 class nsAccessNode;
 class Accessible;
 class HyperTextAccessible;
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -143,16 +143,28 @@ nsAccessNode::RootAccessible() const
 }
 
 nsIFrame*
 nsAccessNode::GetFrame() const
 {
   return mContent ? mContent->GetPrimaryFrame() : nullptr;
 }
 
+nsINode*
+nsAccessNode::GetNode() const
+{
+  return mContent;
+}
+
+nsIDocument*
+nsAccessNode::GetDocumentNode() const
+{
+  return mContent ? mContent->OwnerDoc() : nullptr;
+}
+
 bool
 nsAccessNode::IsPrimaryForNode() const
 {
   return true;
 }
 
 void
 nsAccessNode::Language(nsAString& aLanguage)
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -6,28 +6,23 @@
 /* For documentation of the accessibility architecture, 
  * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
  */
 
 #ifndef _nsAccessNode_H_
 #define _nsAccessNode_H_
 
 #include "nsIAccessibleTypes.h"
-
+#include "nsINode.h"
 #include "a11yGeneric.h"
 
-#include "nsIContent.h"
-#include "nsIDOMNode.h"
-#include "nsINameSpaceManager.h"
-#include "nsIStringBundle.h"
-#include "nsWeakReference.h"
-
 class nsAccessNode;
 class DocAccessible;
 class nsIAccessibleDocument;
+class nsIContent;
 
 namespace mozilla {
 namespace a11y {
 class ApplicationAccessible;
 class RootAccessible;
 }
 }
 
@@ -70,20 +65,19 @@ public:
 
   /**
    * Return frame for the given access node object.
    */
   virtual nsIFrame* GetFrame() const;
   /**
    * Return DOM node associated with the accessible.
    */
-  virtual nsINode* GetNode() const { return mContent; }
+  virtual nsINode* GetNode() const;
   nsIContent* GetContent() const { return mContent; }
-  virtual nsIDocument* GetDocumentNode() const
-    { return mContent ? mContent->OwnerDoc() : nullptr; }
+  virtual nsIDocument* GetDocumentNode() const;
 
   /**
    * Return node type information of DOM node associated with the accessible.
    */
   bool IsContent() const
   {
     return GetNode() && GetNode()->IsNodeOfType(nsINode::eCONTENT);
   }
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -29,16 +29,20 @@
 #include "nsGUIEvent.h"
 #include "nsIView.h"
 #include "nsLayoutUtils.h"
 
 #include "nsComponentManagerUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "mozilla/dom/Element.h"
 
+#include "nsITreeBoxObject.h"
+#include "nsIDocShellTreeItem.h"
+#include "nsITreeColumns.h"
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsCoreUtils
 ////////////////////////////////////////////////////////////////////////////////
 
 bool
 nsCoreUtils::HasClickListener(nsIContent *aContent)
 {
   NS_ENSURE_TRUE(aContent, false);
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -2,31 +2,31 @@
 /* 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 nsCoreUtils_h_
 #define nsCoreUtils_h_
 
 
-#include "nsIDOMNode.h"
 #include "nsIContent.h"
 #include "nsIBoxObject.h"
-#include "nsITreeBoxObject.h"
-#include "nsITreeColumns.h"
+#include "nsIPresShell.h"
 
-#include "nsIFrame.h"
-#include "nsIDocShellTreeItem.h"
-#include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIDOMDOMStringList.h"
-#include "nsIMutableArray.h"
 #include "nsPoint.h"
 #include "nsTArray.h"
 
 class nsRange;
+class nsIDOMNode;
+class nsIFrame;
+class nsIDocShellTreeItem;
+class nsITreeColumn;
+class nsITreeBoxObject;
+class nsIWidget;
 
 /**
  * Core utils.
  */
 class nsCoreUtils
 {
 public:
   /**
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -9,18 +9,18 @@
 #include "mozilla/a11y/Role.h"
 #include "mozilla/a11y/States.h"
 #include "nsAccessNodeWrap.h"
 
 #include "nsIAccessible.h"
 #include "nsIAccessibleHyperLink.h"
 #include "nsIAccessibleSelectable.h"
 #include "nsIAccessibleValue.h"
-#include "nsIAccessibleRole.h"
 #include "nsIAccessibleStates.h"
+#include "nsIContent.h"
 
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 #include "nsRefPtrHashtable.h"
 
 class AccEvent;
 class AccGroupInfo;
 class EmbeddedObjCollector;
--- a/accessible/src/generic/ApplicationAccessible.cpp
+++ b/accessible/src/generic/ApplicationAccessible.cpp
@@ -14,16 +14,17 @@
 #include "States.h"
 
 #include "nsIComponentManager.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMWindow.h"
 #include "nsIWindowMediator.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/Services.h"
+#include "nsIStringBundle.h"
 
 using namespace mozilla::a11y;
 
 ApplicationAccessible::ApplicationAccessible() :
   AccessibleWrap(nullptr, nullptr)
 {
   mFlags |= eApplicationAccessible;
 }
--- a/accessible/src/generic/DocAccessible.h
+++ b/accessible/src/generic/DocAccessible.h
@@ -17,17 +17,16 @@
 #include "nsDataHashtable.h"
 #include "nsIDocument.h"
 #include "nsIDocumentObserver.h"
 #include "nsIEditor.h"
 #include "nsIObserver.h"
 #include "nsIScrollPositionListener.h"
 #include "nsITimer.h"
 #include "nsIWeakReference.h"
-#include "nsCOMArray.h"
 #include "nsIDocShellTreeNode.h"
 
 template<class Class, class Arg>
 class TNotification;
 class NotificationController;
 
 class nsIScrollableView;
 class nsAccessiblePivot;
--- a/accessible/src/html/HTMLTableAccessible.cpp
+++ b/accessible/src/html/HTMLTableAccessible.cpp
@@ -9,16 +9,17 @@
 #include "nsAccessibilityService.h"
 #include "nsAccTreeWalker.h"
 #include "nsAccUtils.h"
 #include "DocAccessible.h"
 #include "nsTextEquivUtils.h"
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
+#include "nsIMutableArray.h"
 
 #include "nsIAccessibleRelation.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMRange.h"
 #include "nsISelectionPrivate.h"
 #include "nsINameSpaceManager.h"
 #include "nsIDOMNodeList.h"
--- a/accessible/src/xul/XULListboxAccessible.cpp
+++ b/accessible/src/xul/XULListboxAccessible.cpp
@@ -15,16 +15,17 @@
 #include "nsComponentManagerUtils.h"
 #include "nsIAutoCompleteInput.h"
 #include "nsIAutoCompletePopup.h"
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMXULPopupElement.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
+#include "nsIMutableArray.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULColumAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULColumAccessible::
--- a/accessible/src/xul/XULTreeGridAccessible.cpp
+++ b/accessible/src/xul/XULTreeGridAccessible.cpp
@@ -9,16 +9,17 @@
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "DocAccessible.h"
 #include "nsEventShell.h"
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
 
+#include "nsIMutableArray.h"
 #include "nsITreeSelection.h"
 #include "nsComponentManagerUtils.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeGridAccessible
 ////////////////////////////////////////////////////////////////////////////////
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -60,24 +60,17 @@ SettingsListener.observe('audio.volume.m
 // =================== Languages ====================
 SettingsListener.observe('language.current', 'en-US', function(value) {
   Services.prefs.setCharPref('intl.accept_languages', value);
 });
 
 
 // =================== RIL ====================
 (function RILSettingsToPrefs() {
-  ['ril.data.enabled', 'ril.data.roaming.enabled'].forEach(function(key) {
-    SettingsListener.observe(key, false, function(value) {
-      Services.prefs.setBoolPref(key, value);
-    });
-  });
-
-  let strPrefs = ['ril.data.apn', 'ril.data.user', 'ril.data.passwd',
-                  'ril.data.mmsc', 'ril.data.mmsproxy'];
+  let strPrefs = ['ril.data.mmsc', 'ril.data.mmsproxy'];
   strPrefs.forEach(function(key) {
     SettingsListener.observe(key, "", function(value) {
       Services.prefs.setCharPref(key, value);
     });
   });
 
   ['ril.data.mmsport'].forEach(function(key) {
     SettingsListener.observe(key, null, function(value) {
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -44,24 +44,23 @@ XPCOMUtils.defineLazyGetter(this, 'Debug
   return DebuggerServer;
 });
 
 function getContentWindow() {
   return shell.contentBrowser.contentWindow;
 }
 
 // FIXME Bug 707625
-// until we have a proper security model, add some rights to
-// the pre-installed web applications
+// Please don't add more permissions here.
 // XXX never grant 'content-camera' to non-gaia apps
 function addPermissions(urls) {
   let permissions = [
     'indexedDB-unlimited', 'webapps-manage', 'offline-app', 'pin-app',
     'websettings-read', 'websettings-readwrite',
-    'content-camera', 'webcontacts-manage', 'wifi-manage', 'desktop-notification',
+    'content-camera', 'wifi-manage', 'desktop-notification',
     'geolocation', 'device-storage', 'alarms'
   ];
 
   urls.forEach(function(url) {
     url = url.trim();
     if (url) {
       let uri = Services.io.newURI(url, null, null);
       let allow = Ci.nsIPermissionManager.ALLOW_ACTION;
new file mode 100644
--- /dev/null
+++ b/b2g/config/mozconfigs/ics_armv7a_gecko/debug
@@ -0,0 +1,20 @@
+mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-b2g
+
+mk_add_options MOZ_MAKE_FLAGS="-j8"
+
+ac_add_options --enable-application=b2g
+ac_add_options --enable-b2g-camera
+
+ac_add_options --target=arm-android-eabi
+ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
+export TOOLCHAIN_HOST=linux-x86
+export GONK_PRODUCT=generic
+ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-"
+ac_add_options --disable-elf-hack
+ac_add_options --enable-debug-symbols
+ac_add_options --enable-debug
+#ac_add_options --with-ccache
+ac_add_options --enable-marionette
+
+# Enable dump() from JS.
+export CXXFLAGS="-DMOZ_ENABLE_JS_DUMP -include $topsrcdir/gonk-toolchain/gonk-misc/Unicode.h -include $topsrcdir/gonk-toolchain/system/vold/ResponseCode.h"
new file mode 100644
--- /dev/null
+++ b/b2g/config/mozconfigs/ics_armv7a_gecko/nightly
@@ -0,0 +1,20 @@
+mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-b2g
+
+mk_add_options MOZ_MAKE_FLAGS="-j8"
+
+ac_add_options --enable-application=b2g
+ac_add_options --enable-b2g-camera
+
+ac_add_options --target=arm-android-eabi
+ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
+export TOOLCHAIN_HOST=linux-x86
+export GONK_PRODUCT=generic
+ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-"
+ac_add_options --disable-elf-hack
+ac_add_options --enable-debug-symbols
+ac_add_options --enable-profiling
+#ac_add_options --with-ccache
+ac_add_options --enable-marionette
+
+# Enable dump() from JS.
+export CXXFLAGS="-DMOZ_ENABLE_JS_DUMP -include $topsrcdir/gonk-toolchain/gonk-misc/Unicode.h -include $topsrcdir/gonk-toolchain/system/vold/ResponseCode.h"
new file mode 100644
--- /dev/null
+++ b/b2g/config/tooltool-manifests/ics.manifest
@@ -0,0 +1,14 @@
+[
+{
+"size": 195, 
+"digest": "209d6875524e6f81c158fe7d8c543683747cb186a53ddb729c6437273404f69468d4c91bfd74a26448ad2a726da1a9b48e6243602cbe60b5d0e0f97cdb29e2cc", 
+"algorithm": "sha512", 
+"filename": "setup.sh"
+}, 
+{
+"size": 62014571, 
+"digest": "68327ed36d8a53615fd66a300d5c022517f2f3ea0199b9d95f80683bbf1d0a154266700c8bde235467cc707c4c37341cd3f5e9816bb2c4b66efc96f9e08c92df", 
+"algorithm": "sha512", 
+"filename": "gonk-toolchain-4.tar.bz2"
+}
+]
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -710,46 +710,32 @@ pref("gecko.handlerService.schemes.ircs.
 pref("gecko.handlerService.schemes.ircs.2.uriTemplate", "chrome://browser-region/locale/region.properties");
 pref("gecko.handlerService.schemes.ircs.3.name", "chrome://browser-region/locale/region.properties");
 pref("gecko.handlerService.schemes.ircs.3.uriTemplate", "chrome://browser-region/locale/region.properties");
 
 // By default, we don't want protocol/content handlers to be registered from a different host, see bug 402287
 pref("gecko.handlerService.allowRegisterFromDifferentHost", false);
 
 #ifdef MOZ_SAFE_BROWSING
-// Safe browsing does nothing unless this pref is set
 pref("browser.safebrowsing.enabled", true);
-
-// Prevent loading of pages identified as malware
 pref("browser.safebrowsing.malware.enabled", true);
-
-// Debug logging to error console
 pref("browser.safebrowsing.debug", false);
 
-// Non-enhanced mode (local url lists) URL list to check for updates
-pref("browser.safebrowsing.provider.0.updateURL", "http://safebrowsing.clients.google.com/safebrowsing/downloads?client={moz:client}&appver={moz:version}&pver=2.2");
-
-pref("browser.safebrowsing.dataProvider", 0);
-
-// Does the provider name need to be localizable?
-pref("browser.safebrowsing.provider.0.name", "Google");
-pref("browser.safebrowsing.provider.0.keyURL", "https://sb-ssl.google.com/safebrowsing/newkey?client={moz:client}&appver={moz:version}&pver=2.2");
-pref("browser.safebrowsing.provider.0.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/report?");
-pref("browser.safebrowsing.provider.0.gethashURL", "http://safebrowsing.clients.google.com/safebrowsing/gethash?client={moz:client}&appver={moz:version}&pver=2.2");
+pref("browser.safebrowsing.updateURL", "http://safebrowsing.clients.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
+pref("browser.safebrowsing.keyURL", "https://sb-ssl.google.com/safebrowsing/newkey?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
+pref("browser.safebrowsing.gethashURL", "http://safebrowsing.clients.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
+pref("browser.safebrowsing.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/report?");
+pref("browser.safebrowsing.reportGenericURL", "http://%LOCALE%.phish-generic.mozilla.com/?hl=%LOCALE%");
+pref("browser.safebrowsing.reportErrorURL", "http://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%");
+pref("browser.safebrowsing.reportPhishURL", "http://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%");
+pref("browser.safebrowsing.reportMalwareURL", "http://%LOCALE%.malware-report.mozilla.com/?hl=%LOCALE%");
+pref("browser.safebrowsing.reportMalwareErrorURL", "http://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%");
 
-// HTML report pages
-pref("browser.safebrowsing.provider.0.reportGenericURL", "http://{moz:locale}.phish-generic.mozilla.com/?hl={moz:locale}");
-pref("browser.safebrowsing.provider.0.reportErrorURL", "http://{moz:locale}.phish-error.mozilla.com/?hl={moz:locale}");
-pref("browser.safebrowsing.provider.0.reportPhishURL", "http://{moz:locale}.phish-report.mozilla.com/?hl={moz:locale}");
-pref("browser.safebrowsing.provider.0.reportMalwareURL", "http://{moz:locale}.malware-report.mozilla.com/?hl={moz:locale}");
-pref("browser.safebrowsing.provider.0.reportMalwareErrorURL", "http://{moz:locale}.malware-error.mozilla.com/?hl={moz:locale}");
-
-// FAQ URLs
 pref("browser.safebrowsing.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/phishing-protection/");
-pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/geolocation/");
+pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
 
 // Name of the about: page contributed by safebrowsing to handle display of error
 // pages on phishing/malware hits.  (bug 399233)
 pref("urlclassifier.alternate_error_page", "blocked");
 
 // The number of random entries to send with a gethash request.
 pref("urlclassifier.gethashnoise", 4);
 
@@ -761,21 +747,19 @@ pref("urlclassifier.gethashtables", "goo
 // the database.
 pref("urlclassifier.confirm-age", 2700);
 
 // Maximum size of the sqlite3 cache during an update, in bytes
 pref("urlclassifier.updatecachemax", 41943040);
 
 // Maximum size of the sqlite3 cache for lookups, in bytes
 pref("urlclassifier.lookupcachemax", 1048576);
+#endif
 
-// URL for checking the reason for a malware warning.
-pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
-
-#endif
+pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/geolocation/");
 
 pref("browser.EULA.version", 3);
 pref("browser.rights.version", 3);
 pref("browser.rights.3.shown", false);
 
 #ifdef DEBUG
 // Don't show the about:rights notification in debug builds.
 pref("browser.rights.override", true);
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1051,17 +1051,17 @@
         <label id="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/>
         <image id="sidebar-throbber"/>
         <toolbarbutton class="tabs-closebutton" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="toggleSidebar();"/>
       </sidebarheader>
       <browser id="sidebar" flex="1" autoscroll="false" disablehistory="true"
                 style="min-width: 14em; width: 18em; max-width: 36em;"/>
     </vbox>
 
-    <splitter id="sidebar-splitter" class="chromeclass-extrachrome" hidden="true"/>
+    <splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
     <vbox id="appcontent" flex="1">
       <tabbrowser id="content" disablehistory="true"
                   flex="1" contenttooltip="aHTMLTooltip"
                   tabcontainer="tabbrowser-tabs"
                   contentcontextmenu="contentAreaContextMenu"
                   autocompletepopup="PopupAutoComplete"
                   onclick="contentAreaClick(event, false);"/>
       <statuspanel id="statusbar-display" inactive="true"/>
@@ -1070,17 +1070,17 @@
     <vbox id="devtools-sidebar-box" hidden="true"
           style="min-width: 18em; width: 22em; max-width: 42em;" persist="width">
       <toolbar id="devtools-sidebar-toolbar"
                class="devtools-toolbar"
                nowindowdrag="true"/>
       <deck id="devtools-sidebar-deck" flex="1"/>
     </vbox>
     <splitter id="social-sidebar-splitter"
-              class="chromeclass-extrachrome"
+              class="chromeclass-extrachrome sidebar-splitter"
               observes="socialSidebarBroadcaster"/>
     <vbox id="social-sidebar-box"
           class="chromeclass-extrachrome"
           observes="socialSidebarBroadcaster">
       <browser id="social-sidebar-browser"
                type="content"
                flex="1"
                style="min-width: 14em; width: 18em; max-width: 36em;"/>
--- a/browser/base/content/test/newtab/browser_newtab_drag_drop.js
+++ b/browser/base/content/test/newtab/browser_newtab_drag_drop.js
@@ -3,16 +3,18 @@
 
 /*
  * These tests make sure that dragging and dropping sites works as expected.
  * Sites contained in the grid need to shift around to indicate the result
  * of the drag-and-drop operation. If the grid is full and we're dragging
  * a new site into it another one gets pushed out.
  */
 function runTests() {
+  requestLongerTimeout(2);
+
   // test a simple drag-and-drop scenario
   yield setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8");
 
   yield simulateDrop(1, 0);
--- a/browser/components/safebrowsing/Makefile.in
+++ b/browser/components/safebrowsing/Makefile.in
@@ -1,24 +1,27 @@
-#
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
 DEPTH     = ../../..
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 TEST_DIRS += content/test
 
+# Normally the "client ID" sent in updates is appinfo.name, but for
+# official Firefox releases from Mozilla we use a special identifier.
 ifdef MOZILLA_OFFICIAL
-DEFINES += -DOFFICIAL_BUILD=1
+ifdef MOZ_PHOENIX
+DEFINES += -DUSE_HISTORIC_SAFEBROWSING_ID=1
+endif
 endif
 
 EXTRA_PP_JS_MODULES = \
   SafeBrowsing.jsm \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/components/safebrowsing/SafeBrowsing.jsm
+++ b/browser/components/safebrowsing/SafeBrowsing.jsm
@@ -29,50 +29,39 @@ var SafeBrowsing = {
     if (this.initialized) {
       log("Already initialized");
       return;
     }
 
     Services.prefs.addObserver("browser.safebrowsing", this.readPrefs, false);
     this.readPrefs();
 
-    this.initProviderURLs();
-
-    // Initialize the list manager
+    // Register our two types of tables, and add custom Mozilla entries
     let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
                       getService(Ci.nsIUrlListManager);
-
-    listManager.setUpdateUrl(this.updateURL);
-    // setKeyUrl has the side effect of fetching a key from the server.
-    // This shouldn't happen if anti-phishing/anti-malware is disabled.
-    if (this.phishingEnabled || this.malwareEnabled)
-      listManager.setKeyUrl(this.keyURL);
-    listManager.setGethashUrl(this.gethashURL);
-
-    // Register our two types of tables
     listManager.registerTable(phishingList, false);
     listManager.registerTable(malwareList, false);
     this.addMozEntries();
 
     this.controlUpdateChecking();
     this.initialized = true;
 
     log("init() finished");
   },
 
 
   initialized:     false,
   phishingEnabled: false,
   malwareEnabled:  false,
 
-  provName:              null,
   updateURL:             null,
   keyURL:                null,
+  gethashURL:            null,
+
   reportURL:             null,
-  gethashURL:            null,
   reportGenericURL:      null,
   reportErrorURL:        null,
   reportPhishURL:        null,
   reportMalwareURL:      null,
   reportMalwareErrorURL: null,
 
 
   getReportURL: function(kind) {
@@ -81,86 +70,62 @@ var SafeBrowsing = {
 
 
   readPrefs: function() {
     log("reading prefs");
 
     debug = Services.prefs.getBoolPref("browser.safebrowsing.debug");
     this.phishingEnabled = Services.prefs.getBoolPref("browser.safebrowsing.enabled");
     this.malwareEnabled  = Services.prefs.getBoolPref("browser.safebrowsing.malware.enabled");
+    this.updateProviderURLs();
 
     // XXX The listManager backend gets confused if this is called before the
     // lists are registered. So only call it here when a pref changes, and not
     // when doing initialization. I expect to refactor this later, so pardon the hack.
     if (this.initialized)
       this.controlUpdateChecking();
   },
 
 
-  initProviderURLs: function() {
-    log("initializing provider URLs");
+  updateProviderURLs: function() {
+#ifdef USE_HISTORIC_SAFEBROWSING_ID
+    let clientID = "navclient-auto-ffox";
+#else
+    let clientID = Services.appinfo.name;
+#endif
 
-    // XXX remove this as obsolete?
-    let provID = Services.prefs.getIntPref("browser.safebrowsing.dataProvider");
-    if (provID != 0) {
-      Cu.reportError("unknown safebrowsing provider ID " + provID);
-      return;
-    }
-
-    let basePref = "browser.safebrowsing.provider.0.";
-    this.provName = Services.prefs.getCharPref(basePref + "name");
-
-    // Urls used to get data from a provider
-    this.updateURL  = this.getUrlPref(basePref + "updateURL");
-    this.keyURL     = this.getUrlPref(basePref + "keyURL");
-    this.reportURL  = this.getUrlPref(basePref + "reportURL");
-    this.gethashURL = this.getUrlPref(basePref + "gethashURL");
+    log("initializing safe browsing URLs");
+    let basePref = "browser.safebrowsing.";
 
     // Urls to HTML report pages
-    this.reportGenericURL      = this.getUrlPref(basePref + "reportGenericURL");
-    this.reportErrorURL        = this.getUrlPref(basePref + "reportErrorURL");
-    this.reportPhishURL        = this.getUrlPref(basePref + "reportPhishURL");
-    this.reportMalwareURL      = this.getUrlPref(basePref + "reportMalwareURL")
-    this.reportMalwareErrorURL = this.getUrlPref(basePref + "reportMalwareErrorURL")
-  },
-
+    this.reportURL             = Services.urlFormatter.formatURLPref(basePref + "reportURL");
+    this.reportGenericURL      = Services.urlFormatter.formatURLPref(basePref + "reportGenericURL");
+    this.reportErrorURL        = Services.urlFormatter.formatURLPref(basePref + "reportErrorURL");
+    this.reportPhishURL        = Services.urlFormatter.formatURLPref(basePref + "reportPhishURL");
+    this.reportMalwareURL      = Services.urlFormatter.formatURLPref(basePref + "reportMalwareURL");
+    this.reportMalwareErrorURL = Services.urlFormatter.formatURLPref(basePref + "reportMalwareErrorURL");
 
-  getUrlPref: function(prefName) {
-    let MOZ_OFFICIAL_BUILD = false;
-#ifdef OFFICIAL_BUILD
-    MOZ_OFFICIAL_BUILD = true;
-#endif
-
-    let url = Services.prefs.getCharPref(prefName);
-
-    let clientName = MOZ_OFFICIAL_BUILD ? "navclient-auto-ffox" : Services.appinfo.name;
-    let clientVersion = Services.appinfo.version;
+    // Urls used to update DB
+    this.updateURL  = Services.urlFormatter.formatURLPref(basePref + "updateURL");
+    this.keyURL     = Services.urlFormatter.formatURLPref(basePref + "keyURL");
+    this.gethashURL = Services.urlFormatter.formatURLPref(basePref + "gethashURL");
 
-    // Parameter substitution
-    // XXX: we should instead use nsIURLFormatter here.
-    url = url.replace(/\{moz:locale\}/g,  this.getLocale());
-    url = url.replace(/\{moz:client\}/g,  clientName);
-    url = url.replace(/\{moz:buildid\}/g, Services.appinfo.appBuildID);
-    url = url.replace(/\{moz:version\}/g, clientVersion);
+    this.updateURL  = this.updateURL.replace("SAFEBROWSING_ID", clientID);
+    this.keyURL     = this.keyURL.replace("SAFEBROWSING_ID", clientID);
+    this.gethashURL = this.gethashURL.replace("SAFEBROWSING_ID", clientID);
 
-    log(prefName, "is", url);
-    return url;
-  },
+    let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
+                      getService(Ci.nsIUrlListManager);
 
-
-  getLocale: function() {
-    const localePref = "general.useragent.locale";
-
-    let locale = Services.prefs.getCharPref(localePref);
-    try {
-      // Dumb. This API only works if pref is localized or has a user value.
-      locale = Services.prefs.getComplexValue(localePref, Ci.nsIPrefLocalizedString).data;
-    } catch (e) { }
-
-    return locale;
+    listManager.setUpdateUrl(this.updateURL);
+    // XXX Bug 779317 - setKeyUrl has the side effect of fetching a key from the server.
+    // This shouldn't happen if anti-phishing/anti-malware is disabled.
+    if (this.phishingEnabled || this.malwareEnabled)
+      listManager.setKeyUrl(this.keyURL);
+    listManager.setGethashUrl(this.gethashURL);
   },
 
 
   controlUpdateChecking: function() {
     log("phishingEnabled:", this.phishingEnabled, "malwareEnabled:", this.malwareEnabled);
 
     let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
                       getService(Ci.nsIUrlListManager);
@@ -174,17 +139,17 @@ var SafeBrowsing = {
       listManager.enableUpdate(malwareList);
     else
       listManager.disableUpdate(malwareList);
   },
 
 
   addMozEntries: function() {
     // Add test entries to the DB.
-    // XXX this should really just be done by DB itself for all moz apps.
+    // XXX bug 779008 - this could be done by DB itself?
     const phishURL   = "mozilla.org/firefox/its-a-trap.html";
     const malwareURL = "mozilla.org/firefox/its-an-attack.html";
 
     let update = "n:1000\ni:test-malware-simple\nad:1\n" +
                  "a:1:32:" + malwareURL.length + "\n" +
                  malwareURL;
     update += "n:1000\ni:test-phish-simple\nad:1\n" +
               "a:1:32:" + phishURL.length + "\n" +
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -2820,113 +2820,91 @@ let SessionStoreInternal = {
     // set smoothScroll back to the original value
     tabstrip.smoothScroll = smoothScroll;
 
     this._sendRestoreCompletedNotifications();
   },
 
   /**
    * Sets the tabs restoring order with the following priority:
-   * Selected tab, pinned tabs, visible tabs, unhidden tabs and hidden tabs.
+   * Selected tab, pinned tabs, optimized visible tabs, other visible tabs and
+   * hidden tabs.
    * @param aTabBrowser
    *        Tab browser object
    * @param aTabs
    *        Array of tab references
    * @param aTabData
    *        Array of tab data
    * @param aSelectedTab
-   *        Index of selected tab
+   *        Index of selected tab (1 is first tab, 0 no selected tab)
    */
   _setTabsRestoringOrder : function ssi__setTabsRestoringOrder(
     aTabBrowser, aTabs, aTabData, aSelectedTab) {
-    // Temporally store the pinned tabs before moving the hidden tabs and
-    // optimizing the visible tabs. In case the selected tab is a pinned tab,
-    // the index is also stored.
-    let pinnedTabs = aTabData.filter(function (aData) aData.pinned).length;
-    let pinnedTabsArray = [];
-    let pinnedTabsDataArray = [];
-    let pinnedSelectedTab = null;
-    if (pinnedTabs && aTabs.length > 1) {
+
+    // Store the selected tab. Need to substract one to get the index in aTabs.
+    let selectedTab;
+    if (aSelectedTab > 0 && aTabs[aSelectedTab - 1]) {
+      selectedTab = aTabs[aSelectedTab - 1];
+    }
+
+    // Store the pinned tabs and hidden tabs.
+    let pinnedTabs = [];
+    let pinnedTabsData = [];
+    let hiddenTabs = [];
+    let hiddenTabsData = [];
+    if (aTabs.length > 1) {
       for (let t = aTabs.length - 1; t >= 0; t--) {
         if (aTabData[t].pinned) {
-          pinnedTabsArray.unshift(aTabs.splice(t, 1)[0]);
-          pinnedTabsDataArray.unshift(aTabData.splice(t, 1)[0]);
-          if (aSelectedTab) {
-            if (aSelectedTab > (t + 1))
-              --aSelectedTab;
-            else if (aSelectedTab == (t + 1)) {
-              aSelectedTab = null;
-              pinnedSelectedTab = 1;
-            }
-          } else if (pinnedSelectedTab) 
-            ++pinnedSelectedTab;
+          pinnedTabs.unshift(aTabs.splice(t, 1)[0]);
+          pinnedTabsData.unshift(aTabData.splice(t, 1)[0]);
+        } else if (aTabData[t].hidden) {
+          hiddenTabs.unshift(aTabs.splice(t, 1)[0]);
+          hiddenTabsData.unshift(aTabData.splice(t, 1)[0]);
         }
       }
     }
 
-    // Without the pinned tabs, we move the hidden tabs to the end of the list
-    // and optimize the visible tabs. 
-    let unhiddenTabs = aTabData.filter(function (aData) !aData.hidden).length;
-    if (unhiddenTabs && aTabs.length > 1) {
-      // Load hidden tabs last, by pushing them to the end of the list.
-      for (let t = 0, tabsToReorder = aTabs.length - unhiddenTabs; tabsToReorder > 0; ) {
-        if (aTabData[t].hidden) {
-          aTabs = aTabs.concat(aTabs.splice(t, 1));
-          aTabData = aTabData.concat(aTabData.splice(t, 1));
-          if (aSelectedTab && aSelectedTab > t)
-            --aSelectedTab;
-          --tabsToReorder;
-          continue;
+    // Optimize the visible tabs only if there is a selected tab.
+    if (selectedTab) {
+      let selectedTabIndex = aTabs.indexOf(selectedTab);
+      if (selectedTabIndex > 0) {
+        let scrollSize = aTabBrowser.tabContainer.mTabstrip.scrollClientSize;
+        let tabWidth = aTabs[0].getBoundingClientRect().width;
+        let maxVisibleTabs = Math.ceil(scrollSize / tabWidth);
+        if (maxVisibleTabs < aTabs.length) {
+          let firstVisibleTab = 0;
+          let nonVisibleTabsCount = aTabs.length - maxVisibleTabs;
+          if (nonVisibleTabsCount >= selectedTabIndex) {
+            // Selected tab is leftmost since we scroll to it when possible.
+            firstVisibleTab = selectedTabIndex;
+          } else {
+            // Selected tab is rightmost or no more room to scroll right.
+            firstVisibleTab = nonVisibleTabsCount;
+          }
+          aTabs = aTabs.splice(firstVisibleTab, maxVisibleTabs).concat(aTabs);
+          aTabData =
+            aTabData.splice(firstVisibleTab, maxVisibleTabs).concat(aTabData);
         }
-        ++t;
-      }
-
-      // Determine if we can optimize & load visible tabs first
-      let maxVisibleTabs = Math.ceil(aTabBrowser.tabContainer.mTabstrip.scrollClientSize /
-                                     aTabs[unhiddenTabs - 1].getBoundingClientRect().width);
-
-      // Make sure we restore visible tabs first, if there are enough
-      if (aSelectedTab && maxVisibleTabs < unhiddenTabs && aSelectedTab > 1) {
-        let firstVisibleTab = 0;
-        if (unhiddenTabs - maxVisibleTabs > aSelectedTab) {
-          // aSelectedTab is leftmost since we scroll to it when possible
-          firstVisibleTab = aSelectedTab - 1;
-        } else {
-          // aSelectedTab is rightmost or no more room to scroll right
-          firstVisibleTab = unhiddenTabs - maxVisibleTabs;
-        }
-        aTabs = aTabs.splice(firstVisibleTab, maxVisibleTabs).concat(aTabs);
-        aTabData = aTabData.splice(firstVisibleTab, maxVisibleTabs).concat(aTabData);
-        aSelectedTab -= firstVisibleTab;
       }
     }
 
-    // Load the pinned tabs at the beginning of the list and restore the
-    // selected tab index.
-    if (pinnedTabsArray) {
-      // Restore the selected tab index.
-      if (pinnedSelectedTab) {
-        aSelectedTab = pinnedSelectedTab;
-      } else {
-        aSelectedTab += pinnedTabsArray.length;
+    // Merge the stored tabs in order.
+    aTabs = pinnedTabs.concat(aTabs, hiddenTabs);
+    aTabData = pinnedTabsData.concat(aTabData, hiddenTabsData);
+
+    // Load the selected tab to the first position and select it.
+    if (selectedTab) {
+      let selectedTabIndex = aTabs.indexOf(selectedTab);
+      if (selectedTabIndex > 0) {
+        aTabs = aTabs.splice(selectedTabIndex, 1).concat(aTabs);
+        aTabData = aTabData.splice(selectedTabIndex, 1).concat(aTabData);
       }
-      // Load the pinned tabs at the beginning of the list.
-      for (let t = pinnedTabsArray.length - 1; t >= 0; t--) {
-        aTabs.unshift(pinnedTabsArray.splice(t, 1)[0]);
-        aTabData.unshift(pinnedTabsDataArray.splice(t, 1)[0]);
-      }
+      aTabBrowser.selectedTab = selectedTab;
     }
 
-    // Load the selected tab to the first position.
-    if (aSelectedTab-- && aTabs[aSelectedTab]) {
-      aTabs.unshift(aTabs.splice(aSelectedTab, 1)[0]);
-      aTabData.unshift(aTabData.splice(aSelectedTab, 1)[0]);
-      aTabBrowser.selectedTab = aTabs[0];
-    }
-    
     return [aTabs, aTabData];
   },
   
   /**
    * Manage history restoration for a window
    * @param aWindow
    *        Window to restore the tabs into
    * @param aTabs
--- a/browser/components/tabview/test/browser_tabview_bug595601.js
+++ b/browser/components/tabview/test/browser_tabview_bug595601.js
@@ -15,17 +15,17 @@ let state = {windows:[{tabs:[
   {entries:[{url:"http://example.com#3"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#3\",\"groupID\":2}"}},
   {entries:[{url:"http://example.com#4"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#4\",\"groupID\":2}"}},
 
   // second group
   {entries:[{url:"http://example.com#5"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#5\",\"groupID\":1}"}},
   {entries:[{url:"http://example.com#6"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#6\",\"groupID\":1}"}},
   {entries:[{url:"http://example.com#7"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#7\",\"groupID\":1}"}},
   {entries:[{url:"http://example.com#8"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#8\",\"groupID\":1}"}}
-],selected:5,extData:{
+],selected:4,extData:{
   "tabview-groups":"{\"nextID\":8,\"activeGroupId\":1}","tabview-group":"{\"1\":{\"bounds\":{\"left\":15,\"top\":10,\"width\":415,\"height\":367},\"userSize\":{\"x\":415,\"y\":367},\"title\":\"\",\"id\":1},\"2\":{\"bounds\":{\"left\":286,\"top\":488,\"width\":418,\"height\":313},\"title\":\"\",\"id\":2}}",
   "tabview-ui":"{\"pageBounds\":{\"left\":0,\"top\":0,\"width\":940,\"height\":1075}}"
 }}]};
 
 function test() {
   waitForExplicitFinish();
 
   Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", false);
--- a/browser/config/tooltool-manifests/linux32/clang.manifest
+++ b/browser/config/tooltool-manifests/linux32/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r160364"
+"clang_version": "r161022"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 65680370,
-"digest": "5d343ea80cb0ace0f2a1683466015679dfacd0ae5584a89f001710c6d665f9fbd757edef5b1bd440f234553f9dbad06c8d1eed74b71a3d11e04e7f4e2c929628",
+"size": 65670083,
+"digest": "681a8f14d9e44e4220ac69f8c545406a40962472ee8fb342b619e04e1a316ddc8802f29f39765cbc06603cc9d4774ac5c2e2d320bf3ec6bc0c7502a5abdd080e",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r160364"
+"clang_version": "r161022"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 61020656,
-"digest": "822dc6f076309b1e45ef0ea77f88b9f5b73c8f1d0bb9c52147a2f99c4bdb67272442c9e89ab88bdadc94e2dead5e5cafc5ccea8211f42919b5ff9242bf2844d5",
+"size": 61189616,
+"digest": "ec5d4787a11f5feff8ecfa2ec91f313cc7a6968ef419c74c25200ed7df92362d566142d405269ee2f0a14d291a834d39cd5dca826d819d6599426470e80bd2c8",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx32/clang.manifest
+++ b/browser/config/tooltool-manifests/macosx32/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r160364"
+"clang_version": "r161022"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 54422251,
-"digest": "8208645d24ac87975a091ff66a90c20589ff8945936ed9b16ca81976c59bf1166ed9f79709698d435480774fba8ed9f9f178dc189305c86162acac8fda19830e",
+"size": 54405078,
+"digest": "940f02ee8e4a760f52d6fe9cd1dc8dec01abc61b8086d46b4aa7d7292cf7c353a2cec1c9687491ade756ba2654b9e93986123155cb931bd18431fbbfdef671a9",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx32/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx32/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r160364"
+"clang_version": "r161022"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 54422251,
-"digest": "8208645d24ac87975a091ff66a90c20589ff8945936ed9b16ca81976c59bf1166ed9f79709698d435480774fba8ed9f9f178dc189305c86162acac8fda19830e",
+"size": 54405078,
+"digest": "940f02ee8e4a760f52d6fe9cd1dc8dec01abc61b8086d46b4aa7d7292cf7c353a2cec1c9687491ade756ba2654b9e93986123155cb931bd18431fbbfdef671a9",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx64/clang.manifest
+++ b/browser/config/tooltool-manifests/macosx64/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r160364"
+"clang_version": "r161022"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 54422251,
-"digest": "8208645d24ac87975a091ff66a90c20589ff8945936ed9b16ca81976c59bf1166ed9f79709698d435480774fba8ed9f9f178dc189305c86162acac8fda19830e",
+"size": 54405078,
+"digest": "940f02ee8e4a760f52d6fe9cd1dc8dec01abc61b8086d46b4aa7d7292cf7c353a2cec1c9687491ade756ba2654b9e93986123155cb931bd18431fbbfdef671a9",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx64/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r160364"
+"clang_version": "r161022"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 54422251,
-"digest": "8208645d24ac87975a091ff66a90c20589ff8945936ed9b16ca81976c59bf1166ed9f79709698d435480774fba8ed9f9f178dc189305c86162acac8fda19830e",
+"size": 54405078,
+"digest": "940f02ee8e4a760f52d6fe9cd1dc8dec01abc61b8086d46b4aa7d7292cf7c353a2cec1c9687491ade756ba2654b9e93986123155cb931bd18431fbbfdef671a9",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -6,16 +6,17 @@
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 const FRAME_STEP_CACHE_DURATION = 100; // ms
 const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
+const SCRIPTS_URL_MAX_LENGTH = 64; // chars
 const SYNTAX_HIGHLIGHT_MAX_FILE_SIZE = 1048576; // 1 MB in bytes
 
 Cu.import("resource:///modules/source-editor.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import('resource://gre/modules/Services.jsm');
@@ -430,16 +431,17 @@ StackFrames.prototype = {
    *        The response packet.
    */
   _onPaused: function SF__onPaused(aEvent, aPacket) {
     // In case the pause was caused by an exception, store the exception value.
     if (aPacket.why.type == "exception") {
       this.exception = aPacket.why.exception;
     }
     this.activeThread.fillFrames(this.pageSize);
+    DebuggerView.editor.focus();
   },
 
   /**
    * Handler for the thread client's resumed notification.
    */
   _onResume: function SF__onResume() {
     DebuggerView.editor.setDebugLocation(-1);
   },
@@ -1083,17 +1085,22 @@ SourceScripts.prototype = {
    *        The script url.
    * @param string aHref
    *        The content location href to be used. If unspecified, it will
    *        default to the script url prepath.
    * @return string
    *         The simplified label.
    */
   getScriptLabel: function SS_getScriptLabel(aUrl, aHref) {
-    return this._labelsCache[aUrl] || (this._labelsCache[aUrl] = this._trimUrl(aUrl));
+    let label = this._trimUrl(aUrl);
+    if (label.length > SCRIPTS_URL_MAX_LENGTH) {
+      let ellipsis = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString);
+      label = label.substring(0, SCRIPTS_URL_MAX_LENGTH) + ellipsis.data;
+    }
+    return this._labelsCache[aUrl] || (this._labelsCache[aUrl] = label);
   },
 
   /**
    * Clears the labels cache, populated by SS_getScriptLabel.
    * This should be done every time the content location changes.
    */
   _clearLabelsCache: function SS__clearLabelsCache() {
     this._labelsCache = {};
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -76,16 +76,17 @@ let DebuggerView = {
   },
 
   /**
    * The load event handler for the source editor. This method does post-load
    * editor initialization.
    */
   _onEditorLoad: function DV__onEditorLoad() {
     DebuggerController.Breakpoints.initialize();
+    this.editor.focus();
   },
 
   /**
    * Sets the close button hidden or visible. It's hidden by default.
    * @param boolean aVisibleFlag
    */
   showCloseButton: function DV_showCloseButton(aVisibleFlag) {
     document.getElementById("close").setAttribute("hidden", !aVisibleFlag);
@@ -521,16 +522,32 @@ ScriptsView.prototype = {
       let offset = editor.findNext(true);
       if (offset > -1) {
         editor.setSelection(offset, offset + token.length)
       }
     }
   },
 
   /**
+   * Called when the scripts filter key sequence was pressed.
+   */
+  _onSearch: function DVS__onSearch() {
+    this._searchbox.focus();
+    this._searchbox.value = "";
+  },
+
+  /**
+   * Called when the scripts token filter key sequence was pressed.
+   */
+  _onTokenSearch: function DVS__onTokenSearch() {
+    this._searchbox.focus();
+    this._searchbox.value = "#";
+  },
+
+  /**
    * The cached scripts container and search box.
    */
   _scripts: null,
   _searchbox: null,
 
   /**
    * Initialization function, called when the debugger is initialized.
    */
@@ -561,20 +578,20 @@ ScriptsView.prototype = {
 
 /**
  * Functions handling the html stackframes UI.
  */
 function StackFramesView() {
   this._onFramesScroll = this._onFramesScroll.bind(this);
   this._onPauseExceptionsClick = this._onPauseExceptionsClick.bind(this);
   this._onCloseButtonClick = this._onCloseButtonClick.bind(this);
-  this._onResumeButtonClick = this._onResumeButtonClick.bind(this);
-  this._onStepOverClick = this._onStepOverClick.bind(this);
-  this._onStepInClick = this._onStepInClick.bind(this);
-  this._onStepOutClick = this._onStepOutClick.bind(this);
+  this._onResume = this._onResume.bind(this);
+  this._onStepOver = this._onStepOver.bind(this);
+  this._onStepIn = this._onStepIn.bind(this);
+  this._onStepOut = this._onStepOut.bind(this);
 }
 
 StackFramesView.prototype = {
 
   /**
    * Sets the current frames state based on the debugger active thread state.
    *
    * @param string aState
@@ -772,43 +789,49 @@ StackFramesView.prototype = {
   _onPauseExceptionsClick: function DVF__onPauseExceptionsClick() {
     let option = document.getElementById("pause-exceptions");
     DebuggerController.StackFrames.updatePauseOnExceptions(option.checked);
   },
 
   /**
    * Listener handling the pause/resume button click event.
    */
-  _onResumeButtonClick: function DVF__onResumeButtonClick() {
+  _onResume: function DVF__onResume(e) {
     if (DebuggerController.activeThread.paused) {
       DebuggerController.activeThread.resume();
     } else {
       DebuggerController.activeThread.interrupt();
     }
   },
 
   /**
    * Listener handling the step over button click event.
    */
-  _onStepOverClick: function DVF__onStepOverClick() {
-    DebuggerController.activeThread.stepOver();
+  _onStepOver: function DVF__onStepOver(e) {
+    if (DebuggerController.activeThread.paused) {
+      DebuggerController.activeThread.stepOver();
+    }
   },
 
   /**
    * Listener handling the step in button click event.
    */
-  _onStepInClick: function DVF__onStepInClick() {
-    DebuggerController.activeThread.stepIn();
+  _onStepIn: function DVF__onStepIn(e) {
+    if (DebuggerController.activeThread.paused) {
+      DebuggerController.activeThread.stepIn();
+    }
   },
 
   /**
    * Listener handling the step out button click event.
    */
-  _onStepOutClick: function DVF__onStepOutClick() {
-    DebuggerController.activeThread.stepOut();
+  _onStepOut: function DVF__onStepOut(e) {
+    if (DebuggerController.activeThread.paused) {
+      DebuggerController.activeThread.stepOut();
+    }
   },
 
   /**
    * Specifies if the active thread has more frames which need to be loaded.
    */
   _dirty: false,
 
   /**
@@ -825,23 +848,21 @@ StackFramesView.prototype = {
     let resume = document.getElementById("resume");
     let stepOver = document.getElementById("step-over");
     let stepIn = document.getElementById("step-in");
     let stepOut = document.getElementById("step-out");
     let frames = document.getElementById("stackframes");
 
     close.addEventListener("click", this._onCloseButtonClick, false);
     pauseOnExceptions.checked = DebuggerController.StackFrames.pauseOnExceptions;
-    pauseOnExceptions.addEventListener("click",
-                                        this._onPauseExceptionsClick,
-                                        false);
-    resume.addEventListener("click", this._onResumeButtonClick, false);
-    stepOver.addEventListener("click", this._onStepOverClick, false);
-    stepIn.addEventListener("click", this._onStepInClick, false);
-    stepOut.addEventListener("click", this._onStepOutClick, false);
+    pauseOnExceptions.addEventListener("click", this._onPauseExceptionsClick, false);
+    resume.addEventListener("click", this._onResume, false);
+    stepOver.addEventListener("click", this._onStepOver, false);
+    stepIn.addEventListener("click", this._onStepIn, false);
+    stepOut.addEventListener("click", this._onStepOut, false);
     frames.addEventListener("click", this._onFramesClick, false);
     frames.addEventListener("scroll", this._onFramesScroll, false);
     window.addEventListener("resize", this._onFramesScroll, false);
 
     this._frames = frames;
     this.emptyText();
   },
 
@@ -853,23 +874,21 @@ StackFramesView.prototype = {
     let pauseOnExceptions = document.getElementById("pause-exceptions");
     let resume = document.getElementById("resume");
     let stepOver = document.getElementById("step-over");
     let stepIn = document.getElementById("step-in");
     let stepOut = document.getElementById("step-out");
     let frames = this._frames;
 
     close.removeEventListener("click", this._onCloseButtonClick, false);
-    pauseOnExceptions.removeEventListener("click",
-                                          this._onPauseExceptionsClick,
-                                          false);
-    resume.removeEventListener("click", this._onResumeButtonClick, false);
-    stepOver.removeEventListener("click", this._onStepOverClick, false);
-    stepIn.removeEventListener("click", this._onStepInClick, false);
-    stepOut.removeEventListener("click", this._onStepOutClick, false);
+    pauseOnExceptions.removeEventListener("click", this._onPauseExceptionsClick, false);
+    resume.removeEventListener("click", this._onResume, false);
+    stepOver.removeEventListener("click", this._onStepOver, false);
+    stepIn.removeEventListener("click", this._onStepIn, false);
+    stepOut.removeEventListener("click", this._onStepOut, false);
     frames.removeEventListener("click", this._onFramesClick, false);
     frames.removeEventListener("scroll", this._onFramesScroll, false);
     window.removeEventListener("resize", this._onFramesScroll, false);
 
     this.empty();
     this._frames = null;
   }
 };
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -32,16 +32,32 @@
       <menuseparator/>
       <menuitem id="se-cMenu-gotoLine"/>
     </menupopup>
   </popupset>
 
   <commandset id="editMenuCommands"/>
   <commandset id="sourceEditorCommands"/>
   <keyset id="sourceEditorKeys"/>
+  <keyset id="scriptSearchKeys">
+    <key key="P" modifiers="access shift"
+         oncommand="DebuggerView.Scripts._onSearch()"/>
+    <key key="T" modifiers="access shift"
+         oncommand="DebuggerView.Scripts._onTokenSearch()"/>
+  </keyset>
+  <keyset id="threadStateKeys">
+    <key keycode="VK_F6"
+         oncommand="DebuggerView.StackFrames._onResume()"/>
+    <key keycode="VK_F7"
+         oncommand="DebuggerView.StackFrames._onStepOver()"/>
+    <key keycode="VK_F8"
+         oncommand="DebuggerView.StackFrames._onStepIn()"/>
+    <key keycode="VK_F8" modifiers="shift"
+         oncommand="DebuggerView.StackFrames._onStepOut()"/>
+  </keyset>
 
   <vbox id="body" flex="1">
     <toolbar id="dbg-toolbar" class="devtools-toolbar">
 #ifdef XP_MACOSX
       <toolbarbutton id="close"
                      tooltiptext="&debuggerUI.closeButton.tooltip;"
                      class="devtools-closebutton"/>
 #endif
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
@@ -35,16 +35,19 @@ function testScriptLabelShortening() {
     let vs = gDebugger.DebuggerView.Scripts;
     let ss = gDebugger.DebuggerController.SourceScripts;
     vs.empty();
     vs._scripts.removeEventListener("select", vs._onScriptsChange, false);
 
     is(ss.trimUrlQuery("a/b/c.d?test=1&random=4#reference"), "a/b/c.d",
       "Trimming the url query isn't done properly.");
 
+    let ellipsis = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString);
+    let nanana = new Array(20).join(NaN);
+
     let urls = [
       { href: "http://some.address.com/random/", leaf: "subrandom/" },
       { href: "http://some.address.com/random/", leaf: "suprandom/?a=1" },
       { href: "http://some.address.com/random/", leaf: "?a=1" },
       { href: "https://another.address.org/random/subrandom/", leaf: "page.html" },
 
       { href: "ftp://interesting.address.org/random/", leaf: "script.js" },
       { href: "ftp://interesting.address.com/random/", leaf: "script.js" },
@@ -57,17 +60,19 @@ function testScriptLabelShortening() {
       { href: "ftp://interesting.address.com/random/x/y/", leaf: "script.js?a=2&b=3&c=4", dupe: true },
 
       { href: "file://random/", leaf: "script_t1.js&a=1&b=2&c=3" },
       { href: "file://random/", leaf: "script_t2_1.js#id" },
       { href: "file://random/", leaf: "script_t2_2.js?a" },
       { href: "file://random/", leaf: "script_t2_3.js&b" },
       { href: "resource://random/", leaf: "script_t3_1.js#id?a=1&b=2" },
       { href: "resource://random/", leaf: "script_t3_2.js?a=1&b=2#id" },
-      { href: "resource://random/", leaf: "script_t3_3.js&a=1&b=2#id" }
+      { href: "resource://random/", leaf: "script_t3_3.js&a=1&b=2#id" },
+
+      { href: nanana, leaf: "Batman!" + "{trim me, now and forevermore}" }
     ];
 
     urls.forEach(function(url) {
       executeSoon(function() {
         let loc = url.href + url.leaf;
         vs.addScript(ss.getScriptLabel(loc, url.href), { url: loc }, true);
       });
     });
@@ -116,16 +121,19 @@ function testScriptLabelShortening() {
         "Script (11) label is incorrect.");
       ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t3_1.js"),
         "Script (12) label is incorrect.");
       ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t3_2.js"),
         "Script (13) label is incorrect.");
       ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t3_3.js"),
         "Script (14) label is incorrect.");
 
+      ok(gDebugger.DebuggerView.Scripts.containsLabel(nanana + "Batman!" + ellipsis),
+        "Script (15) label is incorrect.");
+
       is(vs._scripts.itemCount, urls.filter(function(url) !url.dupe).length,
         "Didn't get the correct number of scripts in the list.");
 
       closeDebuggerAndFinish();
     });
   });
 }
 
--- a/browser/installer/windows/nsis/maintenanceservice_installer.nsi
+++ b/browser/installer/windows/nsis/maintenanceservice_installer.nsi
@@ -192,16 +192,17 @@ Section "MaintenanceService"
   ; this value to determine if we should show the service update pref.
   ; Since the Maintenance service can be installed either x86 or x64,
   ; always use the 64-bit registry for checking if an attempt was made.
   ${If} ${RunningX64}
     SetRegView 64
   ${EndIf}
   WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Attempted" 1
   WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Installed" 1
+  DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "FFPrefetchDisabled"
 
   ; Included here for debug purposes only.  
   ; These keys are used to bypass the installation dir is a valid installation
   ; check from the service so that tests can be run.
   ; WriteRegStr HKLM "${FallbackKey}\0" "name" "Mozilla Corporation"
   ; WriteRegStr HKLM "${FallbackKey}\0" "issuer" "Thawte Code Signing CA - G2"
   ${If} ${RunningX64}
     SetRegView lastused
@@ -243,13 +244,14 @@ Section "Uninstall"
   RMDir /REBOOTOK "$INSTDIR"
 
   DeleteRegKey HKLM "${MaintUninstallKey}"
 
   ${If} ${RunningX64}
     SetRegView 64
   ${EndIf}
   DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "Installed"
+  DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "FFPrefetchDisabled"
   DeleteRegKey HKLM "${FallbackKey}\"
   ${If} ${RunningX64}
     SetRegView lastused
   ${EndIf}
 SectionEnd
--- a/browser/themes/gnomestripe/devtools/debugger.css
+++ b/browser/themes/gnomestripe/devtools/debugger.css
@@ -12,17 +12,16 @@
  * Debugger content
  */
 
 #dbg-content {
   padding: 0;
 }
 
 #scripts {
-  max-width: 350px;
   min-width: 150px;
 }
 
 /**
  * Lists and headers
  */
 
 .list-item {
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -1646,22 +1646,32 @@ sidebarheader {
   text-shadow: none;
 }
 
 #sidebar-box {
   -moz-appearance: dialog;
   -moz-appearance: none;
 }
 
-#sidebar-splitter {
+.sidebar-splitter {
   -moz-border-start: none;
   -moz-border-end: 1px solid #404040;
   min-width: 1px;
-  width: 1px;
+  width: 3px;
   background-image: none !important;
+  background-color: transparent;
+  -moz-margin-start: -3px;
+  position: relative;
+}
+
+#appcontent ~ .sidebar-splitter {
+  -moz-border-start: 1px solid #404040;
+  -moz-border-end: none;
+  -moz-margin-start: 0;
+  -moz-margin-end: -3px;
 }
 
 #sidebar-title {
   color: #535f6d;
   font-weight: bold;
 }
 
 #sidebar-throbber[loading="true"] {
--- a/browser/themes/pinstripe/devtools/debugger.css
+++ b/browser/themes/pinstripe/devtools/debugger.css
@@ -14,17 +14,16 @@
  * Debugger content
  */
 
 #dbg-content {
   padding: 0;
 }
 
 #scripts {
-  max-width: 350px;
   min-width: 150px;
 }
 
 /**
  * Lists and headers
  */
 
 .list-item {
--- a/browser/themes/winstripe/browser-aero.css
+++ b/browser/themes/winstripe/browser-aero.css
@@ -84,26 +84,33 @@
     border-color: hsla(210,54%,20%,.35) hsla(210,54%,20%,.37) hsla(210,54%,20%,.4);
   }
 
   #navigator-toolbox[tabsontop=true] #urlbar:not(:-moz-lwtheme)[focused],
   #navigator-toolbox[tabsontop=true] .searchbar-textbox:not(:-moz-lwtheme)[focused] {
     border-color: hsla(206,100%,60%,.65) hsla(206,100%,55%,.65) hsla(206,100%,50%,.65);
   }
 
-  #sidebar-splitter {
+  .sidebar-splitter {
     border: 0;
     -moz-border-end: 1px solid #A9B7C9;
     min-width: 0;
     width: 3px;
     background-color: transparent;
     -moz-margin-start: -3px;
     position: relative;
   }
 
+  #appcontent ~ .sidebar-splitter {
+    -moz-border-start: 1px solid #A9B7C9;
+    -moz-border-end: none;
+    -moz-margin-start: 0;
+    -moz-margin-end: -3px;
+  }
+
   .menu-accel,
   .menu-iconic-accel {
     color: graytext;
   }
 }
 
 @media (-moz-windows-compositor) {
   /* These should be hidden w/ glass enabled. Windows draws its own buttons. */
--- a/browser/themes/winstripe/devtools/debugger.css
+++ b/browser/themes/winstripe/devtools/debugger.css
@@ -12,17 +12,16 @@
  * Debugger content
  */
 
 #dbg-content {
   padding: 0;
 }
 
 #scripts {
-  max-width: 350px;
   min-width: 150px;
 }
 
 /**
  * This hardcoded width likely due to a toolkit Windows specific bug.
  * See http://hg.mozilla.org/mozilla-central/annotate/f38d6df93cad/toolkit/themes/winstripe/global/textbox-aero.css#l7
  */
 #scripts-search {
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -412,19 +412,19 @@ user_pref("geo.wifi.uri", "http://%(serv
 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.provider.0.gethashURL", "http://%(server)s/safebrowsing-dummy/gethash");
-user_pref("browser.safebrowsing.provider.0.keyURL", "http://%(server)s/safebrowsing-dummy/newkey");
-user_pref("browser.safebrowsing.provider.0.updateURL", "http://%(server)s/safebrowsing-dummy/update");
+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");
 // 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
--- a/build/mobile/b2gautomation.py
+++ b/build/mobile/b2gautomation.py
@@ -206,18 +206,21 @@ class B2GRemoteAutomation(Automation):
                                           'tcp:%s' % self.marionette.port,
                                           'tcp:%s' % self.marionette.port])
 
         # start a marionette session
         session = self.marionette.start_session()
         if 'b2g' not in session:
             raise Exception("bad session value %s returned by start_session" % session)
 
-        # start the tests by navigating to the mochitest url
-        self.marionette.execute_script("window.location.href='%s';" % self.testURL)
+        # Start the tests by navigating to the mochitest url, by setting it
+        # as the 'src' attribute to the homescreen mozbrowser element
+        # provided by B2G's shell.js.
+        self.marionette.set_context("chrome")
+        self.marionette.execute_script("document.getElementById('homescreen').src='%s';" % self.testURL)
 
         return instance
 
     # be careful here as this inner class doesn't have access to outer class members
     class B2GInstance(object):
         """Represents a B2G instance running on a device, and exposes
            some process-like methods/properties that are expected by the
            automation.
--- a/build/mobile/devicemanager.py
+++ b/build/mobile/devicemanager.py
@@ -50,26 +50,26 @@ class DeviceManager:
   @abstractmethod
   def pushFile(self, localname, destname):
     """
     external function
     returns:
     success: True
     failure: False
     """
-    
+
   @abstractmethod
   def mkDir(self, name):
     """
     external function
     returns:
     success: directory name
     failure: None
     """
-    
+
   def mkDirs(self, filename):
     """
     make directory structure on the device
     WARNING: does not create last part of the path
     external function
     returns:
     success: directory structure that we created
     failure: None
@@ -80,17 +80,17 @@ class DeviceManager:
         if (part == parts[-1]): break
         if (part != ""):
             name += '/' + part
             if (not self.dirExists(name)):
                 if (self.mkDir(name) == None):
                     print "failed making directory: " + str(name)
                     return None
     return name
-    
+
   @abstractmethod
   def pushDir(self, localDir, remoteDir):
     """
     push localDir from host to remoteDir on the device
     external function
     returns:
     success: remoteDir
     failure: None
@@ -99,57 +99,57 @@ class DeviceManager:
   @abstractmethod
   def dirExists(self, dirname):
     """
     external function
     returns:
     success: True
     failure: False
     """
-    
+
   @abstractmethod
   def fileExists(self, filepath):
     """
     Because we always have / style paths we make this a lot easier with some
     assumptions
     external function
     returns:
     success: True
     failure: False
     """
-    
+
   @abstractmethod
   def listFiles(self, rootdir):
     """
     list files on the device, requires cd to directory first
     external function
     returns:
     success: array of filenames, ['file1', 'file2', ...]
     failure: None
     """
-  
+
   @abstractmethod
   def removeFile(self, filename):
     """
     external function
     returns:
     success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
     failure: None
     """
-    
+
   @abstractmethod
   def removeDir(self, remoteDir):
     """
     does a recursive delete of directory on the device: rm -Rf remoteDir
     external function
     returns:
     success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
     failure: None
     """
-    
+
   @abstractmethod
   def getProcessList(self):
     """
     external function
     returns:
     success: array of process tuples
     failure: None
     """
@@ -177,134 +177,134 @@ class DeviceManager:
   def processExist(self, appname):
     """
     iterates process list and returns pid if exists, otherwise None
     external function
     returns:
     success: pid
     failure: None
     """
-    
+
     pid = None
 
     #filter out extra spaces
     parts = filter(lambda x: x != '', appname.split(' '))
     appname = ' '.join(parts)
 
     #filter out the quoted env string if it exists
     #ex: '"name=value;name2=value2;etc=..." process args' -> 'process args'
     parts = appname.split('"')
     if (len(parts) > 2):
       appname = ' '.join(parts[2:]).strip()
-  
+
     pieces = appname.split(' ')
     parts = pieces[0].split('/')
     app = parts[-1]
 
     procList = self.getProcessList()
     if (procList == []):
       return None
-      
+
     for proc in procList:
       procName = proc[1].split('/')[-1]
       if (procName == app):
         pid = proc[0]
         break
     return pid
 
 
   @abstractmethod
   def killProcess(self, appname, forceKill=False):
     """
     external function
     returns:
     success: True
     failure: False
     """
-    
+
   @abstractmethod
   def catFile(self, remoteFile):
     """
     external function
     returns:
     success: filecontents
     failure: None
     """
-    
+
   @abstractmethod
   def pullFile(self, remoteFile):
     """
     external function
     returns:
     success: output of pullfile, string
     failure: None
     """
-    
+
   @abstractmethod
   def getFile(self, remoteFile, localFile = ''):
     """
     copy file from device (remoteFile) to host (localFile)
     external function
     returns:
     success: output of pullfile, string
     failure: None
     """
-    
+
   @abstractmethod
   def getDirectory(self, remoteDir, localDir, checkDir=True):
     """
     copy directory structure from device (remoteDir) to host (localDir)
     external function
     checkDir exists so that we don't create local directories if the
     remote directory doesn't exist but also so that we don't call isDir
     twice when recursing.
     returns:
     success: list of files, string
     failure: None
     """
-    
+
   @abstractmethod
   def isDir(self, remotePath):
     """
     external function
     returns:
     success: True
     failure: False
     Throws a FileError exception when null (invalid dir/filename)
     """
-    
+
   @abstractmethod
   def validateFile(self, remoteFile, localFile):
     """
     true/false check if the two files have the same md5 sum
     external function
     returns:
     success: True
     failure: False
     """
-    
+
   @abstractmethod
   def getRemoteHash(self, filename):
     """
     return the md5 sum of a remote file
     internal function
     returns:
     success: MD5 hash for given filename
     failure: None
     """
-    
+
   def getLocalHash(self, filename):
     """
     return the md5 sum of a file on the host
     internal function
     returns:
     success: MD5 hash for given filename
     failure: None
     """
-    
+
     file = open(filename, 'rb')
     if (file == None):
       return None
 
     try:
       mdsum = hashlib.md5()
     except:
       return None
@@ -357,17 +357,17 @@ class DeviceManager:
     """
     Gets the directory location on the device for a specific test type
     Type is one of: xpcshell|reftest|mochitest
     external function
     returns:
     success: path for test root
     failure: None
     """
-    
+
     devroot = self.getDeviceRoot()
     if (devroot == None):
       return None
 
     if (re.search('xpcshell', type, re.I)):
       self.testRoot = devroot + '/xpcshell'
     elif (re.search('?(i)reftest', type)):
       self.testRoot = devroot + '/reftest'
@@ -376,64 +376,64 @@ class DeviceManager:
     return self.testRoot
 
   def signal(self, processID, signalType, signalAction):
     """
     Sends a specific process ID a signal code and action.
     For Example: SIGINT and SIGDFL to process x
     """
     #currently not implemented in device agent - todo
-    
+
     pass
 
   def getReturnCode(self, processID):
     """Get a return code from process ending -- needs support on device-agent"""
     # TODO: make this real
-    
+
     return 0
 
   @abstractmethod
-  def unpackFile(self, filename):
+  def unpackFile(self, file_path, dest_dir=None):
     """
     external function
     returns:
     success: output of unzip command
     failure: None
     """
-    
+
   @abstractmethod
   def reboot(self, ipAddr=None, port=30000):
     """
     external function
     returns:
     success: status from test agent
     failure: None
     """
-    
+
   def validateDir(self, localDir, remoteDir):
     """
     validate localDir from host to remoteDir on the device
     external function
     returns:
     success: True
     failure: False
     """
-    
+
     if (self.debug >= 2): print "validating directory: " + localDir + " to " + remoteDir
     for root, dirs, files in os.walk(localDir):
       parts = root.split(localDir)
       for file in files:
         remoteRoot = remoteDir + '/' + parts[1]
         remoteRoot = remoteRoot.replace('/', '/')
         if (parts[1] == ""): remoteRoot = remoteDir
         remoteName = remoteRoot + '/' + file
         if (self.validateFile(remoteName, os.path.join(root, file)) <> True):
             return False
     return True
-    
+
   @abstractmethod
   def getInfo(self, directive=None):
     """
     Returns information about the device:
     Directive indicates the information you want to get, your choices are:
     os - name of the os
     id - unique id of the device
     uptime - uptime of the device
@@ -443,17 +443,17 @@ class DeviceManager:
     process - list of running processes (same as ps)
     disk - total, free, available bytes on disk
     power - power status (charge, battery temp)
     all - all of them - or call it with no parameters to get all the information
     returns:
     success: dict of info strings by directive name
     failure: None
     """
-    
+
   @abstractmethod
   def installApp(self, appBundlePath, destPath=None):
     """
     external function
     returns:
     success: output from agent for inst command
     failure: None
     """
@@ -461,42 +461,42 @@ class DeviceManager:
   @abstractmethod
   def uninstallAppAndReboot(self, appName, installPath=None):
     """
     external function
     returns:
     success: True
     failure: None
     """
-    
+
   @abstractmethod
   def updateApp(self, appBundlePath, processName=None,
                 destPath=None, ipAddr=None, port=30000):
     """
     external function
     returns:
     success: text status from command or callback server
     failure: None
     """
-  
+
   @abstractmethod
   def getCurrentTime(self):
     """
     external function
     returns:
     success: time in ms
     failure: None
     """
 
   def recordLogcat(self):
     """
     external function
     returns:
     success: file is created in <testroot>/logcat.log
-    failure: 
+    failure:
     """
     #TODO: spawn this off in a separate thread/process so we can collect all the logcat information
 
     # Right now this is just clearing the logcat so we can only see what happens after this call.
     buf = StringIO.StringIO()
     self.shell(['/system/bin/logcat', '-c'], buf)
 
   def getLogcat(self):
@@ -585,24 +585,24 @@ class NetworkTools:
         seed = int(seed)
       maxportnum = seed + 5000 # We will try at most 5000 ports to find an open one
       while not connected:
         try:
           s.bind((ip, seed))
           connected = True
           s.close()
           break
-        except:          
+        except:
           if seed > maxportnum:
             print "Could not find open port after checking 5000 ports"
           raise
         seed += 1
     except:
       print "Socket error trying to find open port"
-        
+
     return seed
 
 def _pop_last_line(file):
   '''
   Utility function to get the last line from a file (shared between ADB and
   SUT device managers). Function also removes it from the file. Intended to
   strip off the return code from a shell command.
   '''
--- a/build/mobile/devicemanagerSUT.py
+++ b/build/mobile/devicemanagerSUT.py
@@ -4,16 +4,17 @@
 
 import select
 import socket
 import SocketServer
 import time, datetime
 import os
 import re
 import hashlib
+import posixpath
 import subprocess
 from threading import Thread
 import traceback
 import sys
 import StringIO
 from devicemanager import DeviceManager, DMError, FileError, NetworkTools, _pop_last_line
 import errno
 
@@ -25,17 +26,17 @@ class AgentError(Exception):
     self.fatal = fatal
 
   def __str__(self):
     return self.msg
 
 class DeviceManagerSUT(DeviceManager):
   host = ''
   port = 0
-  debug = 2 
+  debug = 2
   retries = 0
   tempRoot = os.getcwd()
   base_prompt = '$>'
   base_prompt_re = '\$\>'
   prompt_sep = '\x00'
   prompt_regex = '.*(' + base_prompt_re + prompt_sep + ')'
   agentErrorRE = re.compile('^##AGENT-WARNING##\ ?(.*)')
 
@@ -304,29 +305,29 @@ class DeviceManagerSUT(DeviceManager):
       if (self.debug >= 3): print "files are validated"
       return True
 
     if self.mkDirs(destname) == None:
       print "unable to make dirs: " + destname
       return False
 
     if (self.debug >= 3): print "sending: push " + destname
-    
+
     filesize = os.path.getsize(localname)
     f = open(localname, 'rb')
     data = f.read()
     f.close()
 
     try:
       retVal = self.runCmds([{ 'cmd': 'push ' + destname + ' ' + str(filesize),
                                'data': data }])
     except AgentError, e:
       print "error pushing file: %s" % e.msg
       return False
-  
+
     if (self.debug >= 3): print "push returned: " + str(retVal)
 
     validated = False
     if (retVal):
       retline = retVal.strip()
       if (retline == None):
         # Then we failed to get back a hash from agent, try manual validation
         validated = self.validateFile(destname, localname)
@@ -340,17 +341,17 @@ class DeviceManagerSUT(DeviceManager):
       validated = self.validateFile(destname, localname)
 
     if (validated):
       if (self.debug >= 3): print "Push File Validated!"
       return True
     else:
       if (self.debug >= 2): print "Push File Failed to Validate!"
       return False
-  
+
   # external function
   # returns:
   #  success: directory name
   #  failure: None
   def mkDir(self, name):
     if (self.dirExists(name)):
       return name
     else:
@@ -444,17 +445,17 @@ class DeviceManagerSUT(DeviceManager):
   def removeFile(self, filename):
     if (self.debug>= 2): print "removing file: " + filename
     try:
       retVal = self.runCmds([{ 'cmd': 'rm ' + filename }])
     except AgentError:
       return None
 
     return retVal
-  
+
   # does a recursive delete of directory on the device: rm -Rf remoteDir
   # external function
   # returns:
   #  success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
   #  failure: None
   def removeDir(self, remoteDir):
     try:
       retVal = self.runCmds([{ 'cmd': 'rmdr ' + remoteDir }])
@@ -476,17 +477,17 @@ class DeviceManagerSUT(DeviceManager):
     files = []
     for line in data.splitlines():
       if line:
         pidproc = line.strip().split()
         if (len(pidproc) == 2):
           files += [[pidproc[0], pidproc[1]]]
         elif (len(pidproc) == 3):
           #android returns <userID> <procID> <procName>
-          files += [[pidproc[1], pidproc[2], pidproc[0]]]     
+          files += [[pidproc[1], pidproc[2], pidproc[0]]]
     return files
 
   # external function
   # DEPRECATED: Use shell() or launchApplication() for new code
   # returns:
   #  success: pid
   #  failure: None
   def fireProcess(self, appname, failIfRunning=False):
@@ -495,17 +496,17 @@ class DeviceManagerSUT(DeviceManager):
       return None
 
     if (self.debug >= 2): print "FIRE PROC: '" + appname + "'"
 
     if (self.processExist(appname) != None):
       print "WARNING: process %s appears to be running already\n" % appname
       if (failIfRunning):
         return None
-    
+
     try:
       data = self.runCmds([{ 'cmd': 'exec ' + appname }])
     except AgentError:
       return None
 
     # wait up to 30 seconds for process to start up
     timeslept = 0
     while (timeslept <= 30):
@@ -530,18 +531,18 @@ class DeviceManagerSUT(DeviceManager):
 
     cmdline = subprocess.list2cmdline(cmd)
     if (outputFile == "process.txt" or outputFile == None):
       outputFile = self.getDeviceRoot();
       if outputFile is None:
         return None
       outputFile += "/process.txt"
       cmdline += " > " + outputFile
-    
-    # Prepend our env to the command 
+
+    # Prepend our env to the command
     cmdline = '%s %s' % (self.formatEnvString(env), cmdline)
 
     if self.fireProcess(cmdline, failIfRunning) is None:
       return None
     return outputFile
 
   # external function
   # returns:
@@ -588,27 +589,27 @@ class DeviceManagerSUT(DeviceManager):
   def pullFile(self, remoteFile):
     """Returns contents of remoteFile using the "pull" command.
     The "pull" command is different from other commands in that DeviceManager
     has to read a certain number of bytes instead of just reading to the
     next prompt.  This is more robust than the "cat" command, which will be
     confused if the prompt string exists within the file being catted.
     However it means we can't use the response-handling logic in sendCMD().
     """
-    
+
     def err(error_msg):
         err_str = 'error returned from pull: %s' % error_msg
         print err_str
         self._sock = None
-        raise FileError(err_str) 
+        raise FileError(err_str)
 
     # FIXME: We could possibly move these socket-reading functions up to
     # the class level if we wanted to refactor sendCMD().  For now they are
     # only used to pull files.
-    
+
     def uread(to_recv, error_msg):
       """ unbuffered read """
       try:
         data = self._sock.recv(to_recv)
         if not data:
           err(error_msg)
           return None
         return data
@@ -633,17 +634,17 @@ class DeviceManagerSUT(DeviceManager):
         data = uread(to_recv, error_msg)
         if data == None:
           return None
         buffer += data
       return buffer
 
     prompt = self.base_prompt + self.prompt_sep
     buffer = ''
-    
+
     # expected return value:
     # <filename>,<filesize>\n<filedata>
     # or, if error,
     # <filename>,-1\n<error message>
     try:
       data = self.runCmds([{ 'cmd': 'pull ' + remoteFile }])
     except AgentError:
       return None
@@ -688,22 +689,22 @@ class DeviceManagerSUT(DeviceManager):
   # copy file from device (remoteFile) to host (localFile)
   # external function
   # returns:
   #  success: output of pullfile, string
   #  failure: None
   def getFile(self, remoteFile, localFile = ''):
     if localFile == '':
       localFile = os.path.join(self.tempRoot, "temp.txt")
-  
+
     try:
       retVal = self.pullFile(remoteFile)
     except:
       return None
-      
+
     if (retVal is None):
       return None
 
     fhandle = open(localFile, 'wb')
     fhandle.write(retVal)
     fhandle.close()
     if not self.validateFile(remoteFile, localFile):
       print 'failed to validate file when downloading %s!' % remoteFile
@@ -722,17 +723,17 @@ class DeviceManagerSUT(DeviceManager):
     if (self.debug >= 2): print "getting files in '" + remoteDir + "'"
     if checkDir:
       try:
         is_dir = self.isDir(remoteDir)
       except FileError:
         return None
       if not is_dir:
         return None
-        
+
     filelist = self.listFiles(remoteDir)
     if (self.debug >= 3): print filelist
     if not os.path.exists(localDir):
       os.makedirs(localDir)
 
     for f in filelist:
       if f == '.' or f == '..':
         continue
@@ -748,31 +749,31 @@ class DeviceManagerSUT(DeviceManager):
           print 'failed to get directory "%s"' % remotePath
           return None
       else:
         # It's sometimes acceptable to have getFile() return None, such as
         # when the agent encounters broken symlinks.
         # FIXME: This should be improved so we know when a file transfer really
         # failed.
         if self.getFile(remotePath, localPath) == None:
-          print 'failed to get file "%s"; continuing anyway...' % remotePath 
+          print 'failed to get file "%s"; continuing anyway...' % remotePath
     return filelist
 
   # external function
   # returns:
   #  success: True
   #  failure: False
   #  Throws a FileError exception when null (invalid dir/filename)
   def isDir(self, remotePath):
     try:
       data = self.runCmds([{ 'cmd': 'isdir ' + remotePath }])
     except AgentError:
       # normally there should be no error here; a nonexistent file/directory will
       # return the string "<filename>: No such file or directory".
-      # However, I've seen AGENT-WARNING returned before. 
+      # However, I've seen AGENT-WARNING returned before.
       return False
 
     retVal = data.strip()
     if not retVal:
       raise FileError('isdir returned null')
     return retVal == 'TRUE'
 
   # true/false check if the two files have the same md5 sum
@@ -786,34 +787,34 @@ class DeviceManagerSUT(DeviceManager):
 
     if (remoteHash == None):
       return False
 
     if (remoteHash == localHash):
       return True
 
     return False
-  
+
   # return the md5 sum of a remote file
   # internal function
   # returns:
   #  success: MD5 hash for given filename
   #  failure: None
   def getRemoteHash(self, filename):
     try:
       data = self.runCmds([{ 'cmd': 'hash ' + filename }])
     except AgentError:
       return None
 
     retVal = None
     if data:
       retVal = data.strip()
     if (self.debug >= 3): print "remote hash returned: '" + retVal + "'"
     return retVal
-    
+
   # Gets the device root for the testing area on the device
   # For all devices we will use / type slashes and depend on the device-agent
   # to sort those out.  The agent will return us the device location where we
   # should store things, we will then create our /tests structure relative to
   # that returned path.
   # Structure on the device is as follows:
   # /tests
   #       /<fennec>|<firefox>  --> approot
@@ -851,49 +852,44 @@ class DeviceManagerSUT(DeviceManager):
       return None
 
     return data.strip()
 
   # external function
   # returns:
   #  success: output of unzip command
   #  failure: None
-  def unpackFile(self, filename):
+  def unpackFile(self, file_path, dest_dir=None):
     devroot = self.getDeviceRoot()
     if (devroot == None):
       return None
 
-    dir = ''
-    parts = filename.split('/')
-    if (len(parts) > 1):
-      if self.fileExists(filename):
-        dir = '/'.join(parts[:-1])
-    elif self.fileExists('/' + filename):
-      dir = '/' + filename
-    elif self.fileExists(devroot + '/' + filename):
-      dir = devroot + '/' + filename
-    else:
-      return None
+    # if no dest_dir is passed in just set it to file_path's folder
+    if not dest_dir:
+      dest_dir = posixpath.dirname(file_path)
+
+    if dest_dir[-1] != '/':
+      dest_dir += '/'
 
     try:
-      data = self.runCmds([{ 'cmd': 'cd ' + dir }, { 'cmd': 'unzp ' + filename }])
+      data = self.runCmds([{ 'cmd': 'unzp %s %s' % (file_path, dest_dir)}])
     except AgentError:
       return None
 
     return data
 
   # external function
   # returns:
   #  success: status from test agent
   #  failure: None
   def reboot(self, ipAddr=None, port=30000):
-    cmd = 'rebt'   
+    cmd = 'rebt'
 
     if (self.debug > 3): print "INFO: sending rebt command"
-    callbacksvrstatus = None    
+    callbacksvrstatus = None
 
     if (ipAddr is not None):
     #create update.info file:
       try:
         destname = '/data/data/com.mozilla.SUTAgentAndroid/files/update.info'
         data = "%s,%s\rrebooting\r" % (ipAddr, port)
         self.runCmds([{ 'cmd': 'push %s %s' % (destname, len(data)),
                         'data': data }])
@@ -947,17 +943,17 @@ class DeviceManagerSUT(DeviceManager):
       if (data is None):
         continue
       data = collapseSpaces.sub(' ', data)
       result[d] = data.split('\n')
 
     # Get rid of any 0 length members of the arrays
     for k, v in result.iteritems():
       result[k] = filter(lambda x: x != '', result[k])
-    
+
     # Format the process output
     if 'process' in result:
       proclist = []
       for l in result['process']:
         if l:
           proclist.append(l.split('\t'))
       result['process'] = proclist
 
@@ -1077,44 +1073,16 @@ class DeviceManagerSUT(DeviceManager):
 
     return data.strip()
 
   """
     Connect the ipaddress and port for a callback ping.  Defaults to current IP address
     And ports starting at 30000.
     NOTE: the detection for current IP address only works on Linux!
   """
-  # external function
-  # returns:
-  #  success: output of unzip command
-  #  failure: None
-  def unpackFile(self, filename):
-    devroot = self.getDeviceRoot()
-    if (devroot == None):
-      return None
-
-    dir = ''
-    parts = filename.split('/')
-    if (len(parts) > 1):
-      if self.fileExists(filename):
-        dir = '/'.join(parts[:-1])
-    elif self.fileExists('/' + filename):
-      dir = '/' + filename
-    elif self.fileExists(devroot + '/' + filename):
-      dir = devroot + '/' + filename
-    else:
-      return None
-
-    try:
-      data = self.runCmds(['cd ' + dir, 'unzp ' + filename])
-    except AgentError:
-      return None
-
-    return data
-
   def getCallbackIpAndPort(self, aIp, aPort):
     ip = aIp
     nettools = NetworkTools()
     if (ip == None):
       ip = nettools.getLanIp()
     if (aPort != None):
       port = nettools.findOpenPort(ip, aPort)
     else:
@@ -1204,17 +1172,17 @@ class callbackServer():
     if (debuglevel >= 1): print "DEBUG: gCallbackData is: %s on port: %s" % (gCallbackData, port)
     gCallbackData = ''
     self.ip = ip
     self.port = port
     self.connected = False
     self.debug = debuglevel
     if (self.debug >= 3): print "Creating server with " + str(ip) + ":" + str(port)
     self.server = myServer((ip, port), self.myhandler)
-    self.server_thread = Thread(target=self.server.serve_forever) 
+    self.server_thread = Thread(target=self.server.serve_forever)
     self.server_thread.setDaemon(True)
     self.server_thread.start()
 
   def disconnect(self, step = 60, timeout = 600):
     t = 0
     if (self.debug >= 3): print "Calling disconnect on callback server"
     while t < timeout:
       if (gCallbackData):
@@ -1237,9 +1205,9 @@ class callbackServer():
     return gCallbackData
 
   class myhandler(SocketServer.BaseRequestHandler):
     def handle(self):
       global gCallbackData
       gCallbackData = self.request.recv(1024)
       #print "Callback Handler got data: " + str(gCallbackData)
       self.request.send("OK")
-  
+
--- a/build/unix/build-clang/build-clang.py
+++ b/build/unix/build-clang/build-clang.py
@@ -1,14 +1,14 @@
 #!/usr/bin/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/.
 
-llvm_revision = "160364"
+llvm_revision = "161022"
 moz_version = "moz0"
 
 ##############################################
 
 import os
 import os.path
 import shutil
 import tarfile
@@ -81,16 +81,18 @@ def build_one_stage_aux(stage_dir, is_st
                       "--prefix=%s" % inst_dir,
                       "--with-gcc-toolchain=/tools/gcc-4.5-0moz3"]
     if is_stage_one:
         configure_opts.append("--with-optimize-option=-O0")
 
     build_package(llvm_source_dir, build_dir, configure_opts)
 
 isDarwin = platform.system() == "Darwin"
+if isDarwin:
+    os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.7'
 
 if not os.path.exists(source_dir):
     os.makedirs(source_dir)
     svn_co("http://llvm.org/svn/llvm-project/llvm/trunk",
            llvm_source_dir, llvm_revision)
     svn_co("http://llvm.org/svn/llvm-project/cfe/trunk",
            clang_source_dir, llvm_revision)
     svn_co("http://llvm.org/svn/llvm-project/compiler-rt/trunk",
--- a/content/base/public/nsIFrameMessageManager.idl
+++ b/content/base/public/nsIFrameMessageManager.idl
@@ -12,25 +12,29 @@ interface nsIContent;
 [scriptable, function, uuid(938fcb95-3d63-46be-aa72-94d08fd3b418)]
 interface nsIFrameMessageListener : nsISupports
 {
   /**
    * This is for JS only.
    * receiveMessage is called with one parameter, which has the following
    * properties:
    *   {
+   *     target:  %the target of the message. Either an element owning
+   *               the message manager, or message manager itself if no
+   *               element owns it%
    *     name:    %message name%,
    *     sync:    %true or false%.
-   *     json:    %json object or null%,
+   *     json:    %structured clone of the sent message data%,
+   *     json:    %same as .data, deprecated%,
    *     objects: %array of handles or null, always null if sync is false%
    *   }
    * @note objects property isn't implemented yet.
    *
    * if the message is synchronous, possible return value is sent back
-   * as JSON.
+   * as JSON (will be changed to use structured clones).
    *
    * When the listener is called, 'this' value is the target of the message.
    */
   void receiveMessage();
 };
 
 [scriptable, builtinclass, uuid(9be42627-a5db-456f-8de2-9097da45a8c3)]
 interface nsIFrameMessageManager : nsISupports
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -123,16 +123,17 @@ CPPSRCS		= \
 		nsWebSocket.cpp \
 		nsXHTMLContentSerializer.cpp \
 		nsXMLContentSerializer.cpp \
 		nsXMLHttpRequest.cpp \
 		nsXMLNameSpaceMap.cpp \
 		FragmentOrElement.cpp \
 		Link.cpp \
 		nsBlobProtocolHandler.cpp \
+		nsBlobURI.cpp \
 		nsFrameMessageManager.cpp \
 		nsInProcessTabChildGlobal.cpp \
 		ThirdPartyUtil.cpp \
 		nsEventSource.cpp \
 		FileIOObject.cpp \
 		nsDOMMutationObserver.cpp \
 		$(NULL)
 
--- a/content/base/src/nsBlobProtocolHandler.cpp
+++ b/content/base/src/nsBlobProtocolHandler.cpp
@@ -1,26 +1,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/. */
 
 #include "nsBlobProtocolHandler.h"
-#include "nsSimpleURI.h"
+#include "nsBlobURI.h"
 #include "nsDOMError.h"
-#include "nsCOMPtr.h"
 #include "nsClassHashtable.h"
 #include "nsNetUtil.h"
-#include "nsIURIWithPrincipal.h"
 #include "nsIPrincipal.h"
 #include "nsIDOMFile.h"
-#include "nsISerializable.h"
-#include "nsIClassInfo.h"
-#include "nsIObjectInputStream.h"
-#include "nsIObjectOutputStream.h"
-#include "nsIProgrammingLanguage.h"
 
 // -----------------------------------------------------------------------
 // Hash table
 struct FileDataInfo
 {
   nsCOMPtr<nsIDOMBlob> mFile;
   nsCOMPtr<nsIPrincipal> mPrincipal;
 };
@@ -85,243 +78,16 @@ GetFileDataInfo(const nsACString& aUri)
   }
   
   FileDataInfo* res;
   gFileDataTable->Get(aUri, &res);
   return res;
 }
 
 // -----------------------------------------------------------------------
-// Uri
-
-#define NS_BLOBURI_CID \
-{ 0xf5475c51, 0x59a7, 0x4757, \
-  { 0xb3, 0xd9, 0xe2, 0x11, 0xa9, 0x41, 0x08, 0x72 } }
-
-static NS_DEFINE_CID(kBLOBURICID, NS_BLOBURI_CID);
-
-class nsBlobURI : public nsSimpleURI,
-                      public nsIURIWithPrincipal
-{
-public:
-  nsBlobURI(nsIPrincipal* aPrincipal) :
-      nsSimpleURI(), mPrincipal(aPrincipal)
-  {}
-  virtual ~nsBlobURI() {}
-
-  // For use only from deserialization
-  nsBlobURI() : nsSimpleURI() {}
-
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIURIWITHPRINCIPAL
-  NS_DECL_NSISERIALIZABLE
-  NS_DECL_NSICLASSINFO
-
-  // Override CloneInternal() and EqualsInternal()
-  virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
-                                 nsIURI** aClone);
-  virtual nsresult EqualsInternal(nsIURI* aOther,
-                                  RefHandlingEnum aRefHandlingMode,
-                                  bool* aResult);
-
-  // Override StartClone to hand back a nsBlobURI
-  virtual nsSimpleURI* StartClone(RefHandlingEnum /* unused */)
-  { return new nsBlobURI(); }
-
-  nsCOMPtr<nsIPrincipal> mPrincipal;
-};
-
-static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
-                     NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
-
-NS_IMPL_ADDREF_INHERITED(nsBlobURI, nsSimpleURI)
-NS_IMPL_RELEASE_INHERITED(nsBlobURI, nsSimpleURI)
-
-NS_INTERFACE_MAP_BEGIN(nsBlobURI)
-  NS_INTERFACE_MAP_ENTRY(nsIURIWithPrincipal)
-  if (aIID.Equals(kBLOBURICID))
-    foundInterface = static_cast<nsIURI*>(this);
-  else if (aIID.Equals(kThisSimpleURIImplementationCID)) {
-    // Need to return explicitly here, because if we just set foundInterface
-    // to null the NS_INTERFACE_MAP_END_INHERITING will end up calling into
-    // nsSimplURI::QueryInterface and finding something for this CID.
-    *aInstancePtr = nullptr;
-    return NS_NOINTERFACE;
-  }
-  else
-NS_INTERFACE_MAP_END_INHERITING(nsSimpleURI)
-
-// nsIURIWithPrincipal methods:
-
-NS_IMETHODIMP
-nsBlobURI::GetPrincipal(nsIPrincipal** aPrincipal)
-{
-  NS_IF_ADDREF(*aPrincipal = mPrincipal);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsBlobURI::GetPrincipalUri(nsIURI** aUri)
-{
-  if (mPrincipal) {
-    mPrincipal->GetURI(aUri);
-  }
-  else {
-    *aUri = nullptr;
-  }
-
-  return NS_OK;
-}
-
-// nsISerializable methods:
-
-NS_IMETHODIMP
-nsBlobURI::Read(nsIObjectInputStream* aStream)
-{
-  nsresult rv = nsSimpleURI::Read(aStream);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_ReadOptionalObject(aStream, true, getter_AddRefs(mPrincipal));
-}
-
-NS_IMETHODIMP
-nsBlobURI::Write(nsIObjectOutputStream* aStream)
-{
-  nsresult rv = nsSimpleURI::Write(aStream);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_WriteOptionalCompoundObject(aStream, mPrincipal,
-                                        NS_GET_IID(nsIPrincipal),
-                                        true);
-}
-
-// nsIURI methods:
-nsresult
-nsBlobURI::CloneInternal(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
-                             nsIURI** aClone)
-{
-  nsCOMPtr<nsIURI> simpleClone;
-  nsresult rv =
-    nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-#ifdef DEBUG
-  nsRefPtr<nsBlobURI> uriCheck;
-  rv = simpleClone->QueryInterface(kBLOBURICID, getter_AddRefs(uriCheck));
-  NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) && uriCheck,
-		    "Unexpected!");
-#endif
-
-  nsBlobURI* blobURI = static_cast<nsBlobURI*>(simpleClone.get());
-
-  blobURI->mPrincipal = mPrincipal;
-
-  simpleClone.forget(aClone);
-  return NS_OK;
-}
-
-/* virtual */ nsresult
-nsBlobURI::EqualsInternal(nsIURI* aOther,
-                              nsSimpleURI::RefHandlingEnum aRefHandlingMode,
-                              bool* aResult)
-{
-  if (!aOther) {
-    *aResult = false;
-    return NS_OK;
-  }
-  
-  nsRefPtr<nsBlobURI> otherBlobUri;
-  aOther->QueryInterface(kBLOBURICID, getter_AddRefs(otherBlobUri));
-  if (!otherBlobUri) {
-    *aResult = false;
-    return NS_OK;
-  }
-
-  // Compare the member data that our base class knows about.
-  if (!nsSimpleURI::EqualsInternal(otherBlobUri, aRefHandlingMode)) {
-    *aResult = false;
-    return NS_OK;
-   }
-
-  // Compare the piece of additional member data that we add to base class.
-  if (mPrincipal && otherBlobUri->mPrincipal) {
-    // Both of us have mPrincipals. Compare them.
-    return mPrincipal->Equals(otherBlobUri->mPrincipal, aResult);
-  }
-  // else, at least one of us lacks a principal; only equal if *both* lack it.
-  *aResult = (!mPrincipal && !otherBlobUri->mPrincipal);
-  return NS_OK;
-}
-
-// nsIClassInfo methods:
-NS_IMETHODIMP 
-nsBlobURI::GetInterfaces(PRUint32 *count, nsIID * **array)
-{
-  *count = 0;
-  *array = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP 
-nsBlobURI::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
-{
-  *_retval = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP 
-nsBlobURI::GetContractID(char * *aContractID)
-{
-  // Make sure to modify any subclasses as needed if this ever
-  // changes.
-  *aContractID = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP 
-nsBlobURI::GetClassDescription(char * *aClassDescription)
-{
-  *aClassDescription = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP 
-nsBlobURI::GetClassID(nsCID * *aClassID)
-{
-  // Make sure to modify any subclasses as needed if this ever
-  // changes to not call the virtual GetClassIDNoAlloc.
-  *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
-  NS_ENSURE_TRUE(*aClassID, NS_ERROR_OUT_OF_MEMORY);
-
-  return GetClassIDNoAlloc(*aClassID);
-}
-
-NS_IMETHODIMP 
-nsBlobURI::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
-{
-  *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
-  return NS_OK;
-}
-
-NS_IMETHODIMP 
-nsBlobURI::GetFlags(PRUint32 *aFlags)
-{
-  *aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
-  return NS_OK;
-}
-
-NS_IMETHODIMP 
-nsBlobURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
-{
-  *aClassIDNoAlloc = kBLOBURICID;
-  return NS_OK;
-}
-
-// -----------------------------------------------------------------------
 // Protocol handler
 
 NS_IMPL_ISUPPORTS1(nsBlobProtocolHandler, nsIProtocolHandler)
 
 NS_IMETHODIMP
 nsBlobProtocolHandler::GetScheme(nsACString &result)
 {
   result.AssignLiteral(BLOBURI_SCHEME);
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsBlobURI.cpp
@@ -0,0 +1,199 @@
+/* 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 "nsBlobURI.h"
+
+#include "nsAutoPtr.h"
+#include "nsIObjectInputStream.h"
+#include "nsIObjectOutputStream.h"
+#include "nsIProgrammingLanguage.h"
+
+static NS_DEFINE_CID(kBLOBURICID, NS_BLOBURI_CID);
+
+static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
+                     NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
+
+NS_IMPL_ADDREF_INHERITED(nsBlobURI, nsSimpleURI)
+NS_IMPL_RELEASE_INHERITED(nsBlobURI, nsSimpleURI)
+
+NS_INTERFACE_MAP_BEGIN(nsBlobURI)
+  NS_INTERFACE_MAP_ENTRY(nsIURIWithPrincipal)
+  if (aIID.Equals(kBLOBURICID))
+    foundInterface = static_cast<nsIURI*>(this);
+  else if (aIID.Equals(kThisSimpleURIImplementationCID)) {
+    // Need to return explicitly here, because if we just set foundInterface
+    // to null the NS_INTERFACE_MAP_END_INHERITING will end up calling into
+    // nsSimplURI::QueryInterface and finding something for this CID.
+    *aInstancePtr = nullptr;
+    return NS_NOINTERFACE;
+  }
+  else
+NS_INTERFACE_MAP_END_INHERITING(nsSimpleURI)
+
+// nsIURIWithPrincipal methods:
+
+NS_IMETHODIMP
+nsBlobURI::GetPrincipal(nsIPrincipal** aPrincipal)
+{
+  NS_IF_ADDREF(*aPrincipal = mPrincipal);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBlobURI::GetPrincipalUri(nsIURI** aUri)
+{
+  if (mPrincipal) {
+    mPrincipal->GetURI(aUri);
+  }
+  else {
+    *aUri = nullptr;
+  }
+
+  return NS_OK;
+}
+
+// nsISerializable methods:
+
+NS_IMETHODIMP
+nsBlobURI::Read(nsIObjectInputStream* aStream)
+{
+  nsresult rv = nsSimpleURI::Read(aStream);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_ReadOptionalObject(aStream, true, getter_AddRefs(mPrincipal));
+}
+
+NS_IMETHODIMP
+nsBlobURI::Write(nsIObjectOutputStream* aStream)
+{
+  nsresult rv = nsSimpleURI::Write(aStream);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_WriteOptionalCompoundObject(aStream, mPrincipal,
+                                        NS_GET_IID(nsIPrincipal),
+                                        true);
+}
+
+// nsIURI methods:
+nsresult
+nsBlobURI::CloneInternal(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
+                             nsIURI** aClone)
+{
+  nsCOMPtr<nsIURI> simpleClone;
+  nsresult rv =
+    nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+#ifdef DEBUG
+  nsRefPtr<nsBlobURI> uriCheck;
+  rv = simpleClone->QueryInterface(kBLOBURICID, getter_AddRefs(uriCheck));
+  NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) && uriCheck,
+		    "Unexpected!");
+#endif
+
+  nsBlobURI* blobURI = static_cast<nsBlobURI*>(simpleClone.get());
+
+  blobURI->mPrincipal = mPrincipal;
+
+  simpleClone.forget(aClone);
+  return NS_OK;
+}
+
+/* virtual */ nsresult
+nsBlobURI::EqualsInternal(nsIURI* aOther,
+                              nsSimpleURI::RefHandlingEnum aRefHandlingMode,
+                              bool* aResult)
+{
+  if (!aOther) {
+    *aResult = false;
+    return NS_OK;
+  }
+  
+  nsRefPtr<nsBlobURI> otherBlobUri;
+  aOther->QueryInterface(kBLOBURICID, getter_AddRefs(otherBlobUri));
+  if (!otherBlobUri) {
+    *aResult = false;
+    return NS_OK;
+  }
+
+  // Compare the member data that our base class knows about.
+  if (!nsSimpleURI::EqualsInternal(otherBlobUri, aRefHandlingMode)) {
+    *aResult = false;
+    return NS_OK;
+   }
+
+  // Compare the piece of additional member data that we add to base class.
+  if (mPrincipal && otherBlobUri->mPrincipal) {
+    // Both of us have mPrincipals. Compare them.
+    return mPrincipal->Equals(otherBlobUri->mPrincipal, aResult);
+  }
+  // else, at least one of us lacks a principal; only equal if *both* lack it.
+  *aResult = (!mPrincipal && !otherBlobUri->mPrincipal);
+  return NS_OK;
+}
+
+// nsIClassInfo methods:
+NS_IMETHODIMP 
+nsBlobURI::GetInterfaces(PRUint32 *count, nsIID * **array)
+{
+  *count = 0;
+  *array = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP 
+nsBlobURI::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
+{
+  *_retval = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP 
+nsBlobURI::GetContractID(char * *aContractID)
+{
+  // Make sure to modify any subclasses as needed if this ever
+  // changes.
+  *aContractID = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP 
+nsBlobURI::GetClassDescription(char * *aClassDescription)
+{
+  *aClassDescription = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP 
+nsBlobURI::GetClassID(nsCID * *aClassID)
+{
+  // Make sure to modify any subclasses as needed if this ever
+  // changes to not call the virtual GetClassIDNoAlloc.
+  *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
+  NS_ENSURE_TRUE(*aClassID, NS_ERROR_OUT_OF_MEMORY);
+
+  return GetClassIDNoAlloc(*aClassID);
+}
+
+NS_IMETHODIMP 
+nsBlobURI::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
+{
+  *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
+  return NS_OK;
+}
+
+NS_IMETHODIMP 
+nsBlobURI::GetFlags(PRUint32 *aFlags)
+{
+  *aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
+  return NS_OK;
+}
+
+NS_IMETHODIMP 
+nsBlobURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
+{
+  *aClassIDNoAlloc = kBLOBURICID;
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsBlobURI.h
@@ -0,0 +1,50 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsBlobURI_h
+#define nsBlobURI_h
+
+#include "nsCOMPtr.h"
+#include "nsIClassInfo.h"
+#include "nsIPrincipal.h"
+#include "nsISerializable.h"
+#include "nsIURIWithPrincipal.h"
+#include "nsSimpleURI.h"
+
+class nsBlobURI : public nsSimpleURI,
+                  public nsIURIWithPrincipal
+{
+public:
+  nsBlobURI(nsIPrincipal* aPrincipal) :
+      nsSimpleURI(), mPrincipal(aPrincipal)
+  {}
+  virtual ~nsBlobURI() {}
+
+  // For use only from deserialization
+  nsBlobURI() : nsSimpleURI() {}
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIURIWITHPRINCIPAL
+  NS_DECL_NSISERIALIZABLE
+  NS_DECL_NSICLASSINFO
+
+  // Override CloneInternal() and EqualsInternal()
+  virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
+                                 nsIURI** aClone);
+  virtual nsresult EqualsInternal(nsIURI* aOther,
+                                  RefHandlingEnum aRefHandlingMode,
+                                  bool* aResult);
+
+  // Override StartClone to hand back a nsBlobURI
+  virtual nsSimpleURI* StartClone(RefHandlingEnum /* unused */)
+  { return new nsBlobURI(); }
+
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+};
+
+#define NS_BLOBURI_CID \
+{ 0xf5475c51, 0x59a7, 0x4757, \
+  { 0xb3, 0xd9, 0xe2, 0x11, 0xa9, 0x41, 0x08, 0x72 } }
+
+#endif /* nsBlobURI_h */
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -17,16 +17,17 @@
 #include "nsIDOMHTMLFrameElement.h"
 #include "nsIDOMMozBrowserFrame.h"
 #include "nsIDOMWindow.h"
 #include "nsIPresShell.h"
 #include "nsIContent.h"
 #include "nsIContentViewer.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
+#include "nsIDOMFile.h"
 #include "nsPIDOMWindow.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebProgress.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocShellLoadInfo.h"
@@ -78,16 +79,17 @@
 #include "mozilla/GuardObjects.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "nsIAppsService.h"
 
 #include "jsapi.h"
+#include "mozilla/dom/StructuredCloneUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 typedef FrameMetrics::ViewID ViewID;
 
 class nsAsyncDocShellDestroyer : public nsRunnable
@@ -2151,48 +2153,88 @@ bool LoadScript(void* aCallbackData, con
   }
   return true;
 }
 
 class nsAsyncMessageToChild : public nsRunnable
 {
 public:
   nsAsyncMessageToChild(nsFrameLoader* aFrameLoader,
-                        const nsAString& aMessage, const nsAString& aJSON)
-    : mFrameLoader(aFrameLoader), mMessage(aMessage), mJSON(aJSON) {}
+                              const nsAString& aMessage,
+                              const StructuredCloneData& aData)
+    : mFrameLoader(aFrameLoader), mMessage(aMessage)
+  {
+    if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
+      NS_RUNTIMEABORT("OOM");
+    }
+    mClosure = aData.mClosure;
+  }
 
   NS_IMETHOD Run()
   {
     nsInProcessTabChildGlobal* tabChild =
       static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
     if (tabChild && tabChild->GetInnerManager()) {
       nsFrameScriptCx cx(static_cast<nsIDOMEventTarget*>(tabChild), tabChild);
+
+      StructuredCloneData data;
+      data.mData = mData.data();
+      data.mDataLength = mData.nbytes();
+      data.mClosure = mClosure;
+
       nsRefPtr<nsFrameMessageManager> mm = tabChild->GetInnerManager();
       mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(tabChild), mMessage,
-                         false, mJSON, nullptr, nullptr);
+                         false, &data, nullptr, nullptr, nullptr);
     }
     return NS_OK;
   }
   nsRefPtr<nsFrameLoader> mFrameLoader;
   nsString mMessage;
-  nsString mJSON;
+  JSAutoStructuredCloneBuffer mData;
+  StructuredCloneClosure mClosure;
 };
 
 bool SendAsyncMessageToChild(void* aCallbackData,
                              const nsAString& aMessage,
-                             const nsAString& aJSON)
+                                   const StructuredCloneData& aData)
 {
-  mozilla::dom::PBrowserParent* tabParent =
+  PBrowserParent* tabParent =
     static_cast<nsFrameLoader*>(aCallbackData)->GetRemoteBrowser();
   if (tabParent) {
-    return tabParent->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
+    ClonedMessageData data;
+
+    SerializedStructuredCloneBuffer& buffer = data.data();
+    buffer.data = aData.mData;
+    buffer.dataLength = aData.mDataLength;
+
+    const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
+    if (!blobs.IsEmpty()) {
+      InfallibleTArray<PBlobParent*>& blobParents = data.blobsParent();
+
+      PRUint32 length = blobs.Length();
+      blobParents.SetCapacity(length);
+
+      ContentParent* cp = static_cast<ContentParent*>(tabParent->Manager());
+
+      for (PRUint32 i = 0; i < length; ++i) {
+        BlobParent* blobParent = cp->GetOrCreateActorForBlob(blobs[i]);
+        if (!blobParent) {
+          return false;
+        }
+
+        blobParents.AppendElement(blobParent);
+      }
+    }
+
+    return tabParent->SendAsyncMessage(nsString(aMessage), data);
   }
+
   nsRefPtr<nsIRunnable> ev =
     new nsAsyncMessageToChild(static_cast<nsFrameLoader*>(aCallbackData),
-                              aMessage, aJSON);
+                                    aMessage, aData);
   NS_DispatchToCurrentThread(ev);
   return true;
 }
 
 NS_IMETHODIMP
 nsFrameLoader::GetMessageManager(nsIChromeFrameMessageManager** aManager)
 {
   EnsureMessageManager();
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1,38 +1,44 @@
 /* -*- 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 "base/basictypes.h"
+
+#include "nsFrameMessageManager.h"
+
 #include "ContentChild.h"
 #include "ContentParent.h"
-#include "nsFrameMessageManager.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "jsapi.h"
 #include "nsJSUtils.h"
 #include "nsJSPrincipals.h"
 #include "nsNetUtil.h"
 #include "nsScriptLoader.h"
 #include "nsIJSContextStack.h"
 #include "nsIXULRuntime.h"
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIJSRuntimeService.h"
+#include "nsIDOMFile.h"
 #include "xpcpublic.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/StructuredCloneUtils.h"
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 static bool
 IsChromeProcess()
 {
   nsCOMPtr<nsIXULRuntime> rt = do_GetService("@mozilla.org/xre/runtime;1");
   if (!rt)
     return true;
 
@@ -165,46 +171,68 @@ static JSBool
 JSONCreator(const jschar* aBuf, uint32_t aLen, void* aData)
 {
   nsAString* result = static_cast<nsAString*>(aData);
   result->Append(static_cast<const PRUnichar*>(aBuf),
                  static_cast<PRUint32>(aLen));
   return true;
 }
 
-void
-nsFrameMessageManager::GetParamsForMessage(const jsval& aObject,
-                                           JSContext* aCx,
-                                           nsAString& aJSON)
+static bool
+GetParamsForMessage(JSContext* aCx,
+                    const jsval& aObject,
+                    JSAutoStructuredCloneBuffer& aBuffer,
+                    StructuredCloneClosure& aClosure)
 {
-  aJSON.Truncate();
+  if (WriteStructuredClone(aCx, aObject, aBuffer, aClosure)) {
+    return true;
+  }
+  JS_ClearPendingException(aCx);
+
+  // Not clonable, try JSON
+  //XXX This is ugly but currently structured cloning doesn't handle
+  //    properly cases when interface is implemented in JS and used
+  //    as a dictionary.
+  nsAutoString json;
   JSAutoRequest ar(aCx);
   jsval v = aObject;
-  JS_Stringify(aCx, &v, nullptr, JSVAL_NULL, JSONCreator, &aJSON);
+  NS_ENSURE_TRUE(JS_Stringify(aCx, &v, nullptr, JSVAL_NULL, JSONCreator, &json), false);
+  NS_ENSURE_TRUE(!json.IsEmpty(), false);
+
+  jsval val = JSVAL_NULL;
+  NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast<const jschar*>(PromiseFlatString(json).get()),
+                              json.Length(), &val), false);
+
+  return WriteStructuredClone(aCx, val, aBuffer, aClosure);
 }
 
 NS_IMETHODIMP
 nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
                                        const jsval& aObject,
                                        JSContext* aCx,
                                        PRUint8 aArgc,
                                        jsval* aRetval)
 {
   NS_ASSERTION(!IsGlobal(), "Should not call SendSyncMessage in chrome");
   NS_ASSERTION(!IsWindowLevel(), "Should not call SendSyncMessage in chrome");
   NS_ASSERTION(!mParentManager, "Should not have parent manager in content!");
   *aRetval = JSVAL_VOID;
   if (mSyncCallback) {
     NS_ENSURE_TRUE(mCallbackData, NS_ERROR_NOT_INITIALIZED);
-    nsString json;
-    if (aArgc >= 2) {
-      GetParamsForMessage(aObject, aCx, json);
+    StructuredCloneData data;
+    JSAutoStructuredCloneBuffer buffer;
+    if (aArgc >= 2 &&
+        !GetParamsForMessage(aCx, aObject, buffer, data.mClosure)) {
+      return NS_ERROR_DOM_DATA_CLONE_ERR;
     }
+    data.mData = buffer.data();
+    data.mDataLength = buffer.nbytes();
+
     InfallibleTArray<nsString> retval;
-    if (mSyncCallback(mCallbackData, aMessageName, json, &retval)) {
+    if (mSyncCallback(mCallbackData, aMessageName, data, &retval)) {
       JSAutoRequest ar(aCx);
       PRUint32 len = retval.Length();
       JSObject* dataArray = JS_NewArrayObject(aCx, len, NULL);
       NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY);
 
       for (PRUint32 i = 0; i < len; ++i) {
         if (retval[i].IsEmpty()) {
           continue;
@@ -221,41 +249,48 @@ nsFrameMessageManager::SendSyncMessage(c
       *aRetval = OBJECT_TO_JSVAL(dataArray);
     }
   }
   return NS_OK;
 }
 
 nsresult
 nsFrameMessageManager::SendAsyncMessageInternal(const nsAString& aMessage,
-                                                const nsAString& aJSON)
+                                                const StructuredCloneData& aData)
 {
   if (mAsyncCallback) {
     NS_ENSURE_TRUE(mCallbackData, NS_ERROR_NOT_INITIALIZED);
-    mAsyncCallback(mCallbackData, aMessage, aJSON);
+    mAsyncCallback(mCallbackData, aMessage, aData);
   }
   PRInt32 len = mChildManagers.Count();
   for (PRInt32 i = 0; i < len; ++i) {
     static_cast<nsFrameMessageManager*>(mChildManagers[i])->
-      SendAsyncMessageInternal(aMessage, aJSON);
+      SendAsyncMessageInternal(aMessage, aData);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
                                         const jsval& aObject,
                                         JSContext* aCx,
                                         PRUint8 aArgc)
 {
-  nsString json;
-  if (aArgc >= 2) {
-    GetParamsForMessage(aObject, aCx, json);
+  StructuredCloneData data;
+  JSAutoStructuredCloneBuffer buffer;
+
+  if (aArgc >= 2 &&
+      !GetParamsForMessage(aCx, aObject, buffer, data.mClosure)) {
+    return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
-  return SendAsyncMessageInternal(aMessageName, json);
+
+  data.mData = buffer.data();
+  data.mDataLength = buffer.nbytes();
+
+  return SendAsyncMessageInternal(aMessageName, data);
 }
 
 NS_IMETHODIMP
 nsFrameMessageManager::Dump(const nsAString& aStr)
 {
 #ifdef ANDROID
   __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", NS_ConvertUTF16toUTF8(aStr).get());
 #endif
@@ -337,17 +372,18 @@ public:
 
   bool mWasHandlingMessage;
   nsRefPtr<nsFrameMessageManager> mMM;
 };
 
 nsresult
 nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
                                       const nsAString& aMessage,
-                                      bool aSync, const nsAString& aJSON,
+                                      bool aSync,
+                                      const StructuredCloneData* aCloneData,
                                       JSObject* aObjectsArray,
                                       InfallibleTArray<nsString>* aJSONRetVal,
                                       JSContext* aContext)
 {
   JSContext* ctx = mContext ? mContext : aContext;
   if (!ctx) {
     ctx = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext();
   }
@@ -397,33 +433,33 @@ nsFrameMessageManager::ReceiveMessage(ns
         }
 
         JS::AutoValueRooter objectsv(ctx);
         objectsv.set(OBJECT_TO_JSVAL(aObjectsArray));
         if (!JS_WrapValue(ctx, objectsv.jsval_addr()))
             return NS_ERROR_UNEXPECTED;
 
         jsval json = JSVAL_NULL;
-        if (!aJSON.IsEmpty()) {
-          if (!JS_ParseJSON(ctx, static_cast<const jschar*>(PromiseFlatString(aJSON).get()),
-                            aJSON.Length(), &json)) {
-            json = JSVAL_NULL;
-          }
+        if (aCloneData && aCloneData->mDataLength &&
+            !ReadStructuredClone(ctx, *aCloneData, &json)) {
+          JS_ClearPendingException(ctx);
+          return NS_OK;
         }
         JSString* jsMessage =
           JS_NewUCStringCopyN(ctx,
                               static_cast<const jschar*>(PromiseFlatString(aMessage).get()),
                               aMessage.Length());
         NS_ENSURE_TRUE(jsMessage, NS_ERROR_OUT_OF_MEMORY);
         JS_DefineProperty(ctx, param, "target", targetv, NULL, NULL, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "name",
                           STRING_TO_JSVAL(jsMessage), NULL, NULL, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "sync",
                           BOOLEAN_TO_JSVAL(aSync), NULL, NULL, JSPROP_ENUMERATE);
-        JS_DefineProperty(ctx, param, "json", json, NULL, NULL, JSPROP_ENUMERATE);
+        JS_DefineProperty(ctx, param, "json", json, NULL, NULL, JSPROP_ENUMERATE); // deprecated
+        JS_DefineProperty(ctx, param, "data", json, NULL, NULL, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "objects", objectsv.jsval_value(), NULL, NULL, JSPROP_ENUMERATE);
 
         jsval thisValue = JSVAL_VOID;
 
         JS::Value funval;
         if (JS_ObjectIsCallable(ctx, object)) {
           // If the listener is a JS function:
           funval.setObject(*object);
@@ -474,17 +510,18 @@ nsFrameMessageManager::ReceiveMessage(ns
             }
           }
         }
       }
     }
   }
   nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = mParentManager;
   return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
-                                                         aSync, aJSON, aObjectsArray,
+                                                         aSync, aCloneData,
+                                                         aObjectsArray,
                                                          aJSONRetVal, mContext) : NS_OK;
 }
 
 void
 nsFrameMessageManager::AddChildManager(nsFrameMessageManager* aManager,
                                        bool aLoadScripts)
 {
   mChildManagers.AppendObject(aManager);
@@ -883,135 +920,214 @@ NS_IMPL_ISUPPORTS1(nsScriptCacheCleaner,
 
 nsFrameMessageManager* nsFrameMessageManager::sChildProcessManager = nullptr;
 nsFrameMessageManager* nsFrameMessageManager::sParentProcessManager = nullptr;
 nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr;
 nsTArray<nsCOMPtr<nsIRunnable> >* nsFrameMessageManager::sPendingSameProcessAsyncMessages = nullptr;
 
 bool SendAsyncMessageToChildProcess(void* aCallbackData,
                                     const nsAString& aMessage,
-                                    const nsAString& aJSON)
+                                    const StructuredCloneData& aData)
 {
   mozilla::dom::ContentParent* cp =
     static_cast<mozilla::dom::ContentParent*>(aCallbackData);
   NS_WARN_IF_FALSE(cp, "No child process!");
   if (cp) {
-    return cp->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
+    ClonedMessageData data;
+    SerializedStructuredCloneBuffer& buffer = data.data();
+    buffer.data = aData.mData;
+    buffer.dataLength = aData.mDataLength;
+    const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
+    if (!blobs.IsEmpty()) {
+      InfallibleTArray<PBlobParent*>& blobParents = data.blobsParent();
+      PRUint32 length = blobs.Length();
+      blobParents.SetCapacity(length);
+      for (PRUint32 i = 0; i < length; ++i) {
+        BlobParent* blobParent = cp->GetOrCreateActorForBlob(blobs[i]);
+        if (!blobParent) {
+          return false;
+  }
+        blobParents.AppendElement(blobParent);
+      }
+    }
+
+    return cp->SendAsyncMessage(nsString(aMessage), data);
   }
   return true;
 }
 
 class nsAsyncMessageToSameProcessChild : public nsRunnable
 {
 public:
-  nsAsyncMessageToSameProcessChild(const nsAString& aMessage, const nsAString& aJSON)
-    : mMessage(aMessage), mJSON(aJSON) {}
+  nsAsyncMessageToSameProcessChild(const nsAString& aMessage,
+                                   const StructuredCloneData& aData)
+    : mMessage(aMessage)
+  {
+    if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
+      NS_RUNTIMEABORT("OOM");
+    }
+    mClosure = aData.mClosure;
+  }
 
   NS_IMETHOD Run()
   {
     if (nsFrameMessageManager::sChildProcessManager) {
+      StructuredCloneData data;
+      data.mData = mData.data();
+      data.mDataLength = mData.nbytes();
+      data.mClosure = mClosure;
+
       nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sChildProcessManager;
       ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), mMessage,
-                          false, mJSON, nullptr, nullptr);
+                          false, &data, nullptr, nullptr, nullptr);
     }
     return NS_OK;
   }
   nsString mMessage;
-  nsString mJSON;
+  JSAutoStructuredCloneBuffer mData;
+  StructuredCloneClosure mClosure;
 };
 
 bool SendAsyncMessageToSameProcessChild(void* aCallbackData,
                                         const nsAString& aMessage,
-                                        const nsAString& aJSON)
+                                        const StructuredCloneData& aData)
 {
   nsRefPtr<nsIRunnable> ev =
-    new nsAsyncMessageToSameProcessChild(aMessage, aJSON);
+    new nsAsyncMessageToSameProcessChild(aMessage, aData);
   NS_DispatchToCurrentThread(ev);
   return true;
 }
 
 bool SendSyncMessageToParentProcess(void* aCallbackData,
                                     const nsAString& aMessage,
-                                    const nsAString& aJSON,
+                                    const StructuredCloneData& aData,
                                     InfallibleTArray<nsString>* aJSONRetVal)
 {
   mozilla::dom::ContentChild* cc =
     mozilla::dom::ContentChild::GetSingleton();
   if (cc) {
+    ClonedMessageData data;
+    SerializedStructuredCloneBuffer& buffer = data.data();
+    buffer.data = aData.mData;
+    buffer.dataLength = aData.mDataLength;
+    const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
+    if (!blobs.IsEmpty()) {
+      InfallibleTArray<PBlobChild*>& blobChildList = data.blobsChild();
+      PRUint32 length = blobs.Length();
+      blobChildList.SetCapacity(length);
+      for (PRUint32 i = 0; i < length; ++i) {
+        BlobChild* blobChild = cc->GetOrCreateActorForBlob(blobs[i]);
+        if (!blobChild) {
+          return false;
+        }
+        blobChildList.AppendElement(blobChild);
+      }
+    }
     return
-      cc->SendSyncMessage(nsString(aMessage), nsString(aJSON), aJSONRetVal);
+      cc->SendSyncMessage(nsString(aMessage), data, aJSONRetVal);
   }
   return true;
 }
 
 bool SendSyncMessageToSameProcessParent(void* aCallbackData,
                                         const nsAString& aMessage,
-                                        const nsAString& aJSON,
+                                        const StructuredCloneData& aData,
                                         InfallibleTArray<nsString>* aJSONRetVal)
 {
   nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
   if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
     asyncMessages.SwapElements(*nsFrameMessageManager::sPendingSameProcessAsyncMessages);
     PRUint32 len = asyncMessages.Length();
     for (PRUint32 i = 0; i < len; ++i) {
       nsCOMPtr<nsIRunnable> async = asyncMessages[i];
       async->Run();
     }
   }
   if (nsFrameMessageManager::sSameProcessParentManager) {
     nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), aMessage,
-                        true, aJSON, nullptr, aJSONRetVal);
+                        true, &aData, nullptr, aJSONRetVal);
   }
   return true;
 }
 
 bool SendAsyncMessageToParentProcess(void* aCallbackData,
                                      const nsAString& aMessage,
-                                     const nsAString& aJSON)
+                                          const StructuredCloneData& aData)
 {
   mozilla::dom::ContentChild* cc =
     mozilla::dom::ContentChild::GetSingleton();
   if (cc) {
-    return cc->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
+    ClonedMessageData data;
+    SerializedStructuredCloneBuffer& buffer = data.data();
+    buffer.data = aData.mData;
+    buffer.dataLength = aData.mDataLength;
+    const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
+    if (!blobs.IsEmpty()) {
+      InfallibleTArray<PBlobChild*>& blobChildList = data.blobsChild();
+      PRUint32 length = blobs.Length();
+      blobChildList.SetCapacity(length);
+      for (PRUint32 i = 0; i < length; ++i) {
+        BlobChild* blobChild = cc->GetOrCreateActorForBlob(blobs[i]);
+        if (!blobChild) {
+          return false;
+        }
+        blobChildList.AppendElement(blobChild);
+      }
+    }
+    return cc->SendAsyncMessage(nsString(aMessage), data);
   }
   return true;
 }
 
 class nsAsyncMessageToSameProcessParent : public nsRunnable
 {
 public:
-  nsAsyncMessageToSameProcessParent(const nsAString& aMessage, const nsAString& aJSON)
-    : mMessage(aMessage), mJSON(aJSON) {}
+  nsAsyncMessageToSameProcessParent(const nsAString& aMessage,
+                                         const StructuredCloneData& aData)
+    : mMessage(aMessage)
+  {
+    if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
+      NS_RUNTIMEABORT("OOM");
+    }
+    mClosure = aData.mClosure;
+  }
 
   NS_IMETHOD Run()
   {
     if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
       nsFrameMessageManager::sPendingSameProcessAsyncMessages->RemoveElement(this);
     }
     if (nsFrameMessageManager::sSameProcessParentManager) {
-      nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
-      ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), mMessage, false,
-                          mJSON, nullptr, nullptr);
-    }
-    return NS_OK;
+      StructuredCloneData data;
+      data.mData = mData.data();
+      data.mDataLength = mData.nbytes();
+      data.mClosure = mClosure;
+
+      nsRefPtr<nsFrameMessageManager> ppm =
+        nsFrameMessageManager::sSameProcessParentManager;
+      ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
+                          mMessage, false, &data, nullptr, nullptr, nullptr);
+     }
+     return NS_OK;
   }
   nsString mMessage;
-  nsString mJSON;
+  JSAutoStructuredCloneBuffer mData;
+  StructuredCloneClosure mClosure;
 };
 
 bool SendAsyncMessageToSameProcessParent(void* aCallbackData,
-                                         const nsAString& aMessage,
-                                         const nsAString& aJSON)
+                                              const nsAString& aMessage,
+                                              const StructuredCloneData& aData)
 {
   if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
     nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray<nsCOMPtr<nsIRunnable> >;
   }
   nsCOMPtr<nsIRunnable> ev =
-    new nsAsyncMessageToSameProcessParent(aMessage, aJSON);
+    new nsAsyncMessageToSameProcessParent(aMessage, aData);
   nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev);
   NS_DispatchToCurrentThread(ev);
   return true;
 }
 
 // This creates the global parent process message manager.
 nsresult
 NS_NewParentProcessMessageManager(nsIFrameMessageManager** aResult)
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -20,55 +20,58 @@
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
 namespace dom {
 class ContentParent;
+struct StructuredCloneData;
 }
 }
 
 class nsAXPCNativeCallContext;
 struct JSContext;
 struct JSObject;
 
 struct nsMessageListenerInfo
 {
   nsCOMPtr<nsIFrameMessageListener> mListener;
   nsCOMPtr<nsIAtom> mMessage;
 };
 
 typedef bool (*nsLoadScriptCallback)(void* aCallbackData, const nsAString& aURL);
 typedef bool (*nsSyncMessageCallback)(void* aCallbackData,
                                       const nsAString& aMessage,
-                                      const nsAString& aJSON,
+                                      const mozilla::dom::StructuredCloneData& aData,
                                       InfallibleTArray<nsString>* aJSONRetVal);
 typedef bool (*nsAsyncMessageCallback)(void* aCallbackData,
                                        const nsAString& aMessage,
-                                       const nsAString& aJSON);
+                                             const mozilla::dom::StructuredCloneData& aData);
 
 class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
                                         public nsIChromeFrameMessageManager
 {
+  typedef mozilla::dom::StructuredCloneData StructuredCloneData;
 public:
   nsFrameMessageManager(bool aChrome,
                         nsSyncMessageCallback aSyncCallback,
                         nsAsyncMessageCallback aAsyncCallback,
                         nsLoadScriptCallback aLoadScriptCallback,
                         void* aCallbackData,
                         nsFrameMessageManager* aParentManager,
                         JSContext* aContext,
                         bool aGlobal = false,
                         bool aProcessManager = false)
   : mChrome(aChrome), mGlobal(aGlobal), mIsProcessManager(aProcessManager),
     mHandlingMessage(false), mDisconnected(false), mParentManager(aParentManager),
     mSyncCallback(aSyncCallback), mAsyncCallback(aAsyncCallback),
-    mLoadScriptCallback(aLoadScriptCallback), mCallbackData(aCallbackData),
+    mLoadScriptCallback(aLoadScriptCallback),
+    mCallbackData(aCallbackData),
     mContext(aContext)
   {
     NS_ASSERTION(mContext || (aChrome && !aParentManager) || aProcessManager,
                  "Should have mContext in non-global/non-process manager!");
     NS_ASSERTION(aChrome || !aParentManager, "Should not set parent manager!");
     // This is a bit hackish. When parent manager is global, we want
     // to attach the window message manager to it immediately.
     // Is it just the frame message manager which waits until the
@@ -107,35 +110,33 @@ public:
   NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
   NS_DECL_NSICHROMEFRAMEMESSAGEMANAGER
   NS_DECL_NSITREEITEMFRAMEMESSAGEMANAGER
 
   static nsFrameMessageManager*
   NewProcessMessageManager(mozilla::dom::ContentParent* aProcess);
 
   nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
-                          bool aSync, const nsAString& aJSON,
+                          bool aSync, const StructuredCloneData* aCloneData,
                           JSObject* aObjectsArray,
                           InfallibleTArray<nsString>* aJSONRetVal,
                           JSContext* aContext = nullptr);
+
   void AddChildManager(nsFrameMessageManager* aManager,
                        bool aLoadScripts = true);
   void RemoveChildManager(nsFrameMessageManager* aManager)
   {
     mChildManagers.RemoveObject(aManager);
   }
 
   void Disconnect(bool aRemoveFromParent = true);
   void SetCallbackData(void* aData, bool aLoadScripts = true);
   void* GetCallbackData() { return mCallbackData; }
-  void GetParamsForMessage(const jsval& aObject,
-                           JSContext* aCx,
-                           nsAString& aJSON);
   nsresult SendAsyncMessageInternal(const nsAString& aMessage,
-                                    const nsAString& aJSON);
+                                          const StructuredCloneData& aData);
   JSContext* GetJSContext() { return mContext; }
   void SetJSContext(JSContext* aCx) { mContext = aCx; }
   void RemoveFromParent();
   nsFrameMessageManager* GetParentManager() { return mParentManager; }
   void SetParentManager(nsFrameMessageManager* aParent)
   {
     NS_ASSERTION(!mParentManager, "We have parent manager already!");
     NS_ASSERTION(mChrome, "Should not set parent manager!");
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -15,69 +15,86 @@
 #include "nsComponentManagerUtils.h"
 #include "nsNetUtil.h"
 #include "nsScriptLoader.h"
 #include "nsIJSContextStack.h"
 #include "nsFrameLoader.h"
 #include "xpcpublic.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsDOMClassInfoID.h"
+#include "mozilla/dom/StructuredCloneUtils.h"
+
+using mozilla::dom::StructuredCloneData;
+using mozilla::dom::StructuredCloneClosure;
 
 bool SendSyncMessageToParent(void* aCallbackData,
                              const nsAString& aMessage,
-                             const nsAString& aJSON,
+                             const StructuredCloneData& aData,
                              InfallibleTArray<nsString>* aJSONRetVal)
 {
   nsInProcessTabChildGlobal* tabChild =
     static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
   nsCOMPtr<nsIContent> owner = tabChild->mOwner;
   nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
   asyncMessages.SwapElements(tabChild->mASyncMessages);
   PRUint32 len = asyncMessages.Length();
   for (PRUint32 i = 0; i < len; ++i) {
     nsCOMPtr<nsIRunnable> async = asyncMessages[i];
     async->Run();
   }
   if (tabChild->mChromeMessageManager) {
     nsRefPtr<nsFrameMessageManager> mm = tabChild->mChromeMessageManager;
-    mm->ReceiveMessage(owner, aMessage, true, aJSON, nullptr, aJSONRetVal);
+    mm->ReceiveMessage(owner, aMessage, true, &aData, nullptr, aJSONRetVal);
   }
   return true;
 }
 
 class nsAsyncMessageToParent : public nsRunnable
 {
 public:
   nsAsyncMessageToParent(nsInProcessTabChildGlobal* aTabChild,
-                         const nsAString& aMessage, const nsAString& aJSON)
-    : mTabChild(aTabChild), mMessage(aMessage), mJSON(aJSON) {}
+                         const nsAString& aMessage,
+                         const StructuredCloneData& aData)
+    : mTabChild(aTabChild), mMessage(aMessage)
+  {
+    if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
+      NS_RUNTIMEABORT("OOM");
+    }
+    mClosure = aData.mClosure;
+  }
 
   NS_IMETHOD Run()
   {
     mTabChild->mASyncMessages.RemoveElement(this);
     if (mTabChild->mChromeMessageManager) {
+      StructuredCloneData data;
+      data.mData = mData.data();
+      data.mDataLength = mData.nbytes();
+      data.mClosure = mClosure;
+
       nsRefPtr<nsFrameMessageManager> mm = mTabChild->mChromeMessageManager;
-      mm->ReceiveMessage(mTabChild->mOwner, mMessage, false,
-                         mJSON, nullptr, nullptr);
+      mm->ReceiveMessage(mTabChild->mOwner, mMessage, false, &data,
+                         nullptr, nullptr, nullptr);
     }
     return NS_OK;
   }
   nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
   nsString mMessage;
-  nsString mJSON;
+  JSAutoStructuredCloneBuffer mData;
+  StructuredCloneClosure mClosure;
 };
 
 bool SendAsyncMessageToParent(void* aCallbackData,
                               const nsAString& aMessage,
-                              const nsAString& aJSON)
+                              const StructuredCloneData& aData)
 {
   nsInProcessTabChildGlobal* tabChild =
     static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
   nsCOMPtr<nsIRunnable> ev =
-    new nsAsyncMessageToParent(tabChild, aMessage, aJSON);
+    new nsAsyncMessageToParent(tabChild, aMessage, aData);
   tabChild->mASyncMessages.AppendElement(ev);
   NS_DispatchToCurrentThread(ev);
   return true;
 }
 
 nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
                                                      nsIContent* aOwner,
                                                      nsFrameMessageManager* aChrome)
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -547,16 +547,17 @@ MOCHITEST_FILES_B = \
 		test_bug749367.html \
 		test_bug753278.html \
 		test_bug761120.html \
 		test_XHR_onuploadprogress.html \
 		test_XHR_anon.html \
 		file_XHR_anon.sjs \
 		test_XHR_system.html \
 		test_XHR_parameters.html \
+		test_ipc_messagemanager_blob.html \
 		$(NULL)
 
 MOCHITEST_CHROME_FILES =	\
 		test_bug357450.js \
 		$(NULL)
 
 MOCHITEST_FILES_PARTS = $(foreach s,A B,MOCHITEST_FILES_$(s))
 
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_ipc_messagemanager_blob.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for OOP Blobs in MessageManager</title>
+  <script type="application/javascript"
+          src="/tests/SimpleTest/SimpleTest.js">
+  </script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+  <script type="application/javascript;version=1.7">
+    "use strict";
+
+    SimpleTest.waitForExplicitFinish();
+
+    const childFrameURL =
+      "data:text/html,<!DOCTYPE HTML><html><body></body></html>";
+
+    function childFrameScript() {
+      "use strict";
+
+      addMessageListener("test:ipcClonedMessage", function(message) {
+        if (!(message.json instanceof Components.interfaces.nsIDOMBlob)) {
+          sendAsyncMessage(message.name, message.json);
+          return;
+        }
+
+        let reader =
+          Components.classes["@mozilla.org/files/filereader;1"]
+                    .createInstance(Components.interfaces.nsIDOMFileReader);
+        reader.addEventListener("load", function() {
+          let response = reader.result == "this is a great success!" ?
+                         message.json :
+                         "error";
+          sendAsyncMessage(message.name, response);
+        });
+        reader.readAsText(message.json);
+      });
+    }
+
+    function runTests() {
+      ok("Browser prefs set.");
+
+      let iframe = document.createElement("iframe");
+      iframe.mozbrowser = true;
+      iframe.id = "iframe";
+      iframe.src = childFrameURL;
+
+      iframe.addEventListener("mozbrowserloadend", function() {
+        ok(true, "Got iframe load event.");
+
+        const messages = [
+          "hi!",
+          "",
+          2,
+          -.04,
+          3432987324987239872948732982,
+          true,
+          false,
+          null,
+          0,
+          new Blob(["this ", "is ", "a ", "great ", "success!"],
+                   {"type" : "text\/plain"}),
+        ];
+        let receivedMessageIndex = 0;
+
+        let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+        mm.addMessageListener("test:ipcClonedMessage", function(message) {
+          is(message.json, messages[receivedMessageIndex++],
+             "Got correct round-tripped response");
+          if (receivedMessageIndex == messages.length) {
+            SimpleTest.finish();
+          }
+        });
+        mm.loadFrameScript("data:,(" + childFrameScript.toString() + ")();",
+                           false);
+
+        for each (let message in messages) {
+          mm.sendAsyncMessage("test:ipcClonedMessage", message);
+        }
+      });
+
+      document.body.appendChild(iframe);
+    }
+
+    addEventListener("load", function() {
+      info("Got load event.");
+
+      let whitelist;
+      try {
+        whitelist =
+          SpecialPowers.getCharPref("dom.mozBrowserFramesWhitelist") + ", ";
+      } catch (e) {
+        whitelist = "";
+      }
+
+      whitelist += window.location.protocol + "//" + window.location.host;
+
+      SpecialPowers.pushPrefEnv({
+        "set": [
+          ["dom.ipc.browser_frames.oop_by_default", true],
+          ["dom.mozBrowserFramesEnabled", true],
+          ["dom.mozBrowserFramesWhitelist", whitelist],
+          ["browser.pageThumbs.enabled", false]
+        ]
+      }, runTests);
+    });
+  </script>
+</body>
+</html>
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -68,16 +68,26 @@ NS_NewCanvasRenderingContextWebGL(nsIDOM
     nsIDOMWebGLRenderingContext* ctx = new WebGLContext();
     if (!ctx)
         return NS_ERROR_OUT_OF_MEMORY;
 
     NS_ADDREF(*aResult = ctx);
     return NS_OK;
 }
 
+WebGLContextOptions::WebGLContextOptions()
+    : alpha(true), depth(true), stencil(false),
+      premultipliedAlpha(true), antialias(true),
+      preserveDrawingBuffer(false)
+{
+    // Set default alpha state based on preference.
+    if (Preferences::GetBool("webgl.default-no-alpha", false))
+        alpha = false;
+}
+
 WebGLContext::WebGLContext()
     : gl(nullptr)
 {
     SetIsDOMBinding();
     mExtensions.SetLength(WebGLExtensionID_number_of_extensions);
 
     mGeneration = 0;
     mInvalidated = false;
@@ -284,32 +294,24 @@ GetBoolFromPropertyBag(nsIPropertyBag *b
 }
 
 NS_IMETHODIMP
 WebGLContext::SetContextOptions(nsIPropertyBag *aOptions)
 {
     if (!aOptions)
         return NS_OK;
 
-    bool defaultNoAlpha =
-        Preferences::GetBool("webgl.default-no-alpha", false);
-
     WebGLContextOptions newOpts;
 
     GetBoolFromPropertyBag(aOptions, "stencil", &newOpts.stencil);
     GetBoolFromPropertyBag(aOptions, "depth", &newOpts.depth);
     GetBoolFromPropertyBag(aOptions, "premultipliedAlpha", &newOpts.premultipliedAlpha);
     GetBoolFromPropertyBag(aOptions, "antialias", &newOpts.antialias);
     GetBoolFromPropertyBag(aOptions, "preserveDrawingBuffer", &newOpts.preserveDrawingBuffer);
-
-    // alpha defaults to true as per the spec, but we want to evaluate
-    // what will happen if it were to default to false based on a pref
-    if (!GetBoolFromPropertyBag(aOptions, "alpha", &newOpts.alpha) && defaultNoAlpha) {
-        newOpts.alpha = false;
-    }
+    GetBoolFromPropertyBag(aOptions, "alpha", &newOpts.alpha);
 
     // enforce that if stencil is specified, we also give back depth
     newOpts.depth |= newOpts.stencil;
 
 #if 0
     GenerateWarning("aaHint: %d stencil: %d depth: %d alpha: %d premult: %d preserve: %d\n",
                newOpts.antialias ? 1 : 0,
                newOpts.stencil ? 1 : 0,
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -419,21 +419,17 @@ public:
 
 protected:
     WebGLsizei mWidth;
     WebGLsizei mHeight;
 };
 
 struct WebGLContextOptions {
     // these are defaults
-    WebGLContextOptions()
-        : alpha(true), depth(true), stencil(false),
-          premultipliedAlpha(true), antialias(true),
-          preserveDrawingBuffer(false)
-    { }
+    WebGLContextOptions();
 
     bool operator==(const WebGLContextOptions& other) const {
         return
             alpha == other.alpha &&
             depth == other.depth &&
             stencil == other.stencil &&
             premultipliedAlpha == other.premultipliedAlpha &&
             antialias == other.antialias &&
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -547,18 +547,17 @@ PRUint8 (*nsCanvasRenderingContext2DAzur
 PRUint8 (*nsCanvasRenderingContext2DAzure::sPremultiplyTable)[256] = nullptr;
 
 namespace mozilla {
 namespace dom {
 
 bool
 AzureCanvasEnabled()
 {
-  BackendType dontCare;
-  return gfxPlatform::GetPlatform()->SupportsAzureCanvas(dontCare);
+  return gfxPlatform::GetPlatform()->SupportsAzureCanvas();
 }
 
 }
 }
 
 nsresult
 NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult)
 {
--- a/content/canvas/test/test_canvas.html
+++ b/content/canvas/test/test_canvas.html
@@ -39,41 +39,41 @@ function IsMacOSX10_5orOlder() {
 }
 
 
 function IsAzureEnabled() {
   var enabled = false;
 
   try {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureBackend;
+    var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
     enabled = (backend != "none");
   } catch (e) { }
 
   return enabled;
 }
 
 function IsAzureSkia() {
   var enabled = false;
   
   try {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureBackend;
+    var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
     enabled = (backend == "skia");
   } catch (e) { }
 
   return enabled;
 }
 
 function IsAzureCairo() {
   var enabled = false;
   
   try {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureBackend;
+    var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
     enabled = (backend == "cairo");
   } catch (e) { }
 
   return enabled;
 }
 
 </script>
 <!-- Includes all the tests in the content/canvas/tests except for test_bug397524.html -->
@@ -3533,18 +3533,23 @@ isPixel(ctx, 55,25, 0,255,0,255, 2);
 
 function test_2d_drawImage_null() {
 
 var canvas = document.getElementById('c121');
 var ctx = canvas.getContext('2d');
 
 var _thrown = undefined; try {
   ctx.drawImage(null, 0, 0);
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
-
+} catch (e) { _thrown = e };
+
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
 
 }
 </script>
 
 <!-- [[[ test_2d.drawImage.outsidesource.html ]]] -->
 
 <p>Canvas test: 2d.drawImage.outsidesource</p>
 <canvas id="c122" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
@@ -3710,27 +3715,49 @@ isPixel(ctx, 50,25, 0,255,0,255, 2);
 
 function test_2d_drawImage_wrongtype() {
 
 var canvas = document.getElementById('c127');
 var ctx = canvas.getContext('2d');
 
 var _thrown = undefined; try {
   ctx.drawImage(undefined, 0, 0);
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} catch (e) { _thrown = e }; 
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
+
 var _thrown = undefined; try {
   ctx.drawImage(0, 0, 0);
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} catch (e) { _thrown = e };
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
+
 var _thrown = undefined; try {
   ctx.drawImage("", 0, 0);
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} catch (e) { _thrown = e };
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
+
 var _thrown = undefined; try {
   ctx.drawImage(document.createElement('p'), 0, 0);
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
-
+} catch (e) { _thrown = e };
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
 
 }
 </script>
 
 <!-- [[[ test_2d.drawImage.zerosource.html ]]] -->
 
 <p>Canvas test: 2d.drawImage.zerosource</p>
 <!-- Testing: drawImage with zero-sized source rectangle throws INDEX_SIZE_ERR -->
@@ -7691,17 +7718,22 @@ var _thrown = undefined; try {
 
 function test_2d_imageData_create1_zero() {
 
 var canvas = document.getElementById('c262a');
 var ctx = canvas.getContext('2d');
 
 var _thrown = undefined; try {
   ctx.createImageData(null);
-} catch (e) { _thrown = e }; todo(_thrown && _thrown instanceof TypeError, "should throw TypeError");
+} catch (e) { _thrown = e };
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.get.basic.html ]]] -->
 
 <p>Canvas test: 2d.imageData.get.basic</p>
@@ -9202,18 +9234,22 @@ var _thrown = undefined; try {
 
 function test_2d_imageData_put_null() {
 
 var canvas = document.getElementById('c300');
 var ctx = canvas.getContext('2d');
 
 var _thrown = undefined; try {
   ctx.putImageData(null, 0, 0);
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
-
+} catch (e) { _thrown = e };
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.put.path.html ]]] -->
 
 <p>Canvas test: 2d.imageData.put.path</p>
 <!-- Testing: putImageData() does not affect the current path -->
@@ -9314,23 +9350,41 @@ for (var i = 0; i < imgdata2.data.length
 function test_2d_imageData_put_wrongtype() {
 
 var canvas = document.getElementById('c304');
 var ctx = canvas.getContext('2d');
 
 var imgdata = { width: 1, height: 1, data: [255, 0, 0, 255] };
 var _thrown = undefined; try {
   ctx.putImageData(imgdata, 0, 0);
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} catch (e) { _thrown = e }; 
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
+
 var _thrown = undefined; try {
   ctx.putImageData("cheese", 0, 0);
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} catch (e) { _thrown = e };
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
+
 var _thrown = undefined; try {
   ctx.putImageData(42, 0, 0);
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} catch (e) { _thrown = e };
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
+
 
 
 }
 </script>
 
 <!-- [[[ test_2d.line.cap.butt.html ]]] -->
 
 <p>Canvas test: 2d.line.cap.butt</p>
@@ -15126,17 +15180,22 @@ var _thrown = undefined; try {
 
 function test_2d_pattern_image_null() {
 
 var canvas = document.getElementById('c467');
 var ctx = canvas.getContext('2d');
 
 var _thrown = undefined; try {
   ctx.createPattern(null, 'repeat');
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} catch (e) { _thrown = e };
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
 
 
 }
 </script>
 
 <!-- [[[ test_2d.pattern.image.string.html ]]] -->
 
 <p>Canvas test: 2d.pattern.image.string</p>
@@ -15145,17 +15204,22 @@ var _thrown = undefined; try {
 
 function test_2d_pattern_image_string() {
 
 var canvas = document.getElementById('c468');
 var ctx = canvas.getContext('2d');
 
 var _thrown = undefined; try {
   ctx.createPattern('image_red.png', 'repeat');
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} catch (e) { _thrown = e };
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
 
 
 }
 </script>
 
 <!-- [[[ test_2d.pattern.image.undefined.html ]]] -->
 
 <p>Canvas test: 2d.pattern.image.undefined</p>
@@ -15164,17 +15228,22 @@ var _thrown = undefined; try {
 
 function test_2d_pattern_image_undefined() {
 
 var canvas = document.getElementById('c469');
 var ctx = canvas.getContext('2d');
 
 var _thrown = undefined; try {
   ctx.createPattern(undefined, 'repeat');
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} catch (e) { _thrown = e };
+if (IsAzureEnabled()) {
+  ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+} else {
+  todo(_thrown && _thrown.name == "TypeError", "should throw TypeError");
+}
 
 
 }
 </script>
 
 <!-- [[[ test_2d.pattern.modify.canvas1.html ]]] -->
 
 <p>Canvas test: 2d.pattern.modify.canvas1</p>
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -284,31 +284,31 @@ public:
   static char const *const gOggCodecs[3];
   static bool IsOpusEnabled();
   static char const *const gOggCodecsWithOpus[4];
 #endif
 
 #ifdef MOZ_WAVE
   static bool IsWaveEnabled();
   static bool IsWaveType(const nsACString& aType);
-  static const char gWaveTypes[4][16];
+  static const char gWaveTypes[4][15];
   static char const *const gWaveCodecs[2];
 #endif
 
 #ifdef MOZ_WEBM
   static bool IsWebMEnabled();
   static bool IsWebMType(const nsACString& aType);
-  static const char gWebMTypes[2][17];
+  static const char gWebMTypes[2][11];
   static char const *const gWebMCodecs[4];
 #endif
 
 #ifdef MOZ_GSTREAMER
   static bool IsH264Enabled();
   static bool IsH264Type(const nsACString& aType);
-  static const char gH264Types[3][17];
+  static const char gH264Types[3][16];
   static char const *const gH264Codecs[7];
 #endif
 
 #ifdef MOZ_MEDIA_PLUGINS
   static bool IsMediaPluginsEnabled();
   static bool IsMediaPluginsType(const nsACString& aType);
 #endif
 
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -1954,22 +1954,22 @@ void nsHTMLMediaElement::UnbindFromTree(
                                         bool aNullParent)
 {
   if (!mPaused && mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY)
     Pause();
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 }
 
 #ifdef MOZ_RAW
-static const char gRawTypes[][16] = {
+static const char gRawTypes[2][16] = {
   "video/x-raw",
   "video/x-raw-yuv"
 };
 
-static const char* gRawCodecs[] = {
+static const char* gRawCodecs[1] = {
   nullptr
 };
 
 bool
 nsHTMLMediaElement::IsRawEnabled()
 {
   return Preferences::GetBool("media.raw.enabled");
 }
@@ -2043,17 +2043,17 @@ nsHTMLMediaElement::IsOggType(const nsAC
   return false;
 }
 #endif
 
 #ifdef MOZ_WAVE
 // See http://www.rfc-editor.org/rfc/rfc2361.txt for the definitions
 // of WAVE media types and codec types. However, the audio/vnd.wave
 // MIME type described there is not used.
-const char nsHTMLMediaElement::gWaveTypes[4][16] = {
+const char nsHTMLMediaElement::gWaveTypes[4][15] = {
   "audio/x-wav",
   "audio/wav",
   "audio/wave",
   "audio/x-pn-wav"
 };
 
 char const *const nsHTMLMediaElement::gWaveCodecs[2] = {
   "1", // Microsoft PCM Format
@@ -2079,17 +2079,17 @@ nsHTMLMediaElement::IsWaveType(const nsA
     }
   }
 
   return false;
 }
 #endif
 
 #ifdef MOZ_WEBM
-const char nsHTMLMediaElement::gWebMTypes[2][17] = {
+const char nsHTMLMediaElement::gWebMTypes[2][11] = {
   "video/webm",
   "audio/webm"
 };
 
 char const *const nsHTMLMediaElement::gWebMCodecs[4] = {
   "vp8",
   "vp8.0",
   "vorbis",
@@ -2115,17 +2115,17 @@ nsHTMLMediaElement::IsWebMType(const nsA
     }
   }
 
   return false;
 }
 #endif
 
 #ifdef MOZ_GSTREAMER
-const char nsHTMLMediaElement::gH264Types[3][17] = {
+const char nsHTMLMediaElement::gH264Types[3][16] = {
   "video/mp4",
   "video/3gpp",
   "video/quicktime",
 };
 
 char const *const nsHTMLMediaElement::gH264Codecs[7] = {
   "avc1.42E01E",
   "avc1.42001E",
--- a/content/media/test/test_info_leak.html
+++ b/content/media/test/test_info_leak.html
@@ -30,17 +30,17 @@ var manager = new MediaTestManager;
 var gEventTypes = [ 'loadstart', 'progress', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'play', 'pause', 'loadedmetadata', 'loadeddata', 'waiting', 'playing', 'canplay', 'canplaythrough', 'seeking', 'seeked', 'timeupdate', 'ended', 'ratechange', 'durationchange', 'volumechange' ];
 
 var gExpectedEvents = ['loadstart', 'error'];
 
 function createTestArray() {
   var tests = [];
   var tmpVid = document.createElement("video");
 
-  for (var testNum=0; testNum<gSeekTests.length; testNum++) {
+  for (var testNum=0; testNum<gInfoLeakTests.length; testNum++) {
     var test = gInfoLeakTests[testNum];
     if (!tmpVid.canPlayType(test.type)) {
       continue;
     }
 
     var t = new Object;
     t.name = test.src;
     t.type = test.type;
--- a/content/xbl/src/nsXBLProtoImplMethod.cpp
+++ b/content/xbl/src/nsXBLProtoImplMethod.cpp
@@ -53,16 +53,21 @@ nsXBLProtoImplMethod::AppendBodyText(con
 }
 
 void 
 nsXBLProtoImplMethod::AddParameter(const nsAString& aText)
 {
   NS_PRECONDITION(!IsCompiled(),
                   "Must not be compiled when accessing uncompiled method");
 
+  if (aText.IsEmpty()) {
+    NS_WARNING("Empty name attribute in xbl:parameter!");
+    return;
+  }
+
   nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
   if (!uncompiledMethod) {
     uncompiledMethod = new nsXBLUncompiledMethod();
     if (!uncompiledMethod)
       return;
     SetUncompiledMethod(uncompiledMethod);
   }
 
--- a/content/xbl/test/Makefile.in
+++ b/content/xbl/test/Makefile.in
@@ -41,12 +41,13 @@ MOCHITEST_FILES =	\
 
 MOCHITEST_CHROME_FILES = \
 		test_bug296375.xul \
 		test_bug378518.xul \
 		test_bug398135.xul \
 		test_bug398492.xul \
 		test_bug721452.xul \
 		test_bug723676.xul \
+		test_bug772966.xul \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
new file mode 100644
--- /dev/null
+++ b/content/xbl/test/test_bug772966.xul
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=772966
+-->
+<window title="Mozilla Bug 772966"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="runTest()">
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=772966"
+     target="_blank">Mozilla Bug 772966</a>
+  </body>
+
+  <script>
+    function runTest() {
+      is(document.getElementById('b').test(123, 123, 123), 2, "Should have 2 params.");
+    }
+  </script>
+  
+  <box id="b" style="-moz-binding: url(#binding)"/>
+  
+  <xbl:bindings xmlns:xbl="http://www.mozilla.org/xbl">
+    <xbl:binding id="binding">
+      <xbl:implementation>
+        <xbl:method name="test">
+          <xbl:parameter name="p1"/>
+          <xbl:parameter name=""/>
+          <xbl:parameter name="p2"/>
+          <xbl:body><![CDATA[
+            return arguments.callee.length;
+          ]]></xbl:body>
+        </xbl:method>
+      </xbl:implementation>
+    </xbl:binding>
+  </xbl:bindings>
+  
+
+</window>
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -11,19 +11,19 @@ VPATH		= @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= dom
 
 DIRS = \
   interfaces/base \
   interfaces/canvas \
   interfaces/core \
-  interfaces/devicestorage \
   interfaces/html \
   interfaces/events \
+  interfaces/devicestorage \
   interfaces/contacts \
   interfaces/settings \
   interfaces/stylesheets \
   interfaces/sidebar \
   interfaces/css \
   interfaces/traversal \
   interfaces/range \
   interfaces/xbl \
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -8,17 +8,16 @@
 #include "base/basictypes.h"
 
 #include "Navigator.h"
 #include "nsIXULAppInfo.h"
 #include "nsPluginArray.h"
 #include "nsMimeTypeArray.h"
 #include "nsDesktopNotification.h"
 #include "nsGeolocation.h"
-#include "nsDeviceStorage.h"
 #include "nsIHttpProtocolHandler.h"
 #include "nsICachingChannel.h"
 #include "nsIDocShell.h"
 #include "nsIWebContentHandlerRegistrar.h"
 #include "nsICookiePermission.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIJSContextStack.h"
 #include "nsCharSeparatedTokenizer.h"
@@ -187,16 +186,22 @@ Navigator::Invalidate()
   mCameraManager = nullptr;
 
 #ifdef MOZ_SYS_MSG
   if (mMessagesManager) {
     mMessagesManager = nullptr;
   }
 #endif
 
+  PRUint32 len = mDeviceStorageStores.Length();
+  for (PRUint32 i = 0; i < len; ++i) {
+    mDeviceStorageStores[i]->Shutdown();
+  }
+  mDeviceStorageStores.Clear();
+
 }
 
 nsPIDOMWindow *
 Navigator::GetWindow()
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
 
   return win;
@@ -868,29 +873,37 @@ Navigator::MozIsLocallyAvailable(const n
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
   return httpChannel->GetRequestSucceeded(aIsAvailable);
 }
 
 //*****************************************************************************
 //    Navigator::nsIDOMNavigatorDeviceStorage
 //*****************************************************************************
 
-NS_IMETHODIMP Navigator::GetDeviceStorage(const nsAString &aType, nsIVariant** _retval)
+NS_IMETHODIMP Navigator::GetDeviceStorage(const nsAString &aType, nsIDOMDeviceStorage** _retval)
 {
   if (!Preferences::GetBool("device.storage.enabled", false)) {
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
 
   if (!win || !win->GetOuterWindow() || !win->GetDocShell()) {
     return NS_ERROR_FAILURE;
   }
 
-  nsDOMDeviceStorage::CreateDeviceStoragesFor(win, aType, _retval);
+  nsRefPtr<nsDOMDeviceStorage> storage;
+  nsDOMDeviceStorage::CreateDeviceStoragesFor(win, aType, getter_AddRefs(storage));
+
+  if (!storage) {
+    return NS_OK;
+  }
+
+  NS_ADDREF(*_retval = storage.get());
+  mDeviceStorageStores.AppendElement(storage);                                                                                                                                                                                              
   return NS_OK;
 }
 
 //*****************************************************************************
 //    Navigator::nsIDOMNavigatorGeolocation
 //*****************************************************************************
 
 NS_IMETHODIMP Navigator::GetGeolocation(nsIDOMGeoGeolocation** _retval)
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -12,16 +12,17 @@
 #include "nsIDOMNavigatorDeviceStorage.h"
 #include "nsIDOMNavigatorDesktopNotification.h"
 #include "nsIDOMClientInformation.h"
 #include "nsINavigatorBattery.h"
 #include "nsIDOMNavigatorSms.h"
 #include "nsIDOMNavigatorNetwork.h"
 #include "nsAutoPtr.h"
 #include "nsWeakReference.h"
+#include "DeviceStorage.h"
 
 class nsPluginArray;
 class nsMimeTypeArray;
 class nsGeolocation;
 class nsDesktopNotificationCenter;
 class nsPIDOMWindow;
 class nsIDOMMozConnection;
 
@@ -157,16 +158,17 @@ private:
 #endif
   nsRefPtr<network::Connection> mConnection;
   nsRefPtr<network::MobileConnection> mMobileConnection;
 #ifdef MOZ_B2G_BT
   nsCOMPtr<nsIDOMBluetoothManager> mBluetooth;
 #endif
   nsRefPtr<nsDOMCameraManager> mCameraManager;
   nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
+  nsTArray<nsRefPtr<nsDOMDeviceStorage> > mDeviceStorageStores;
   nsWeakPtr mWindow;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
 nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -135,16 +135,17 @@
 #include "nsIDOMHTMLOptionElement.h"
 #include "nsGenericElement.h"
 
 // Event related includes
 #include "nsEventListenerManager.h"
 #include "nsIDOMEventTarget.h"
 
 // CSS related includes
+#include "nsCSSRules.h"
 #include "nsIDOMStyleSheet.h"
 #include "nsIDOMStyleSheetList.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIDOMCSSRule.h"
 #include "nsICSSRuleList.h"
 #include "nsIDOMRect.h"
 #include "nsIDOMRGBColor.h"
 #include "nsIDOMNSRGBAColor.h"
@@ -284,16 +285,17 @@
 #endif
 #include "nsIDOMProgressEvent.h"
 #include "nsIDOMCSS2Properties.h"
 #include "nsIDOMCSSCharsetRule.h"
 #include "nsIDOMCSSImportRule.h"
 #include "nsIDOMCSSMediaRule.h"
 #include "nsIDOMCSSFontFaceRule.h"
 #include "nsIDOMCSSMozDocumentRule.h"
+#include "nsIDOMCSSSupportsRule.h"
 #include "nsIDOMMozCSSKeyframeRule.h"
 #include "nsIDOMMozCSSKeyframesRule.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMCSSStyleRule.h"
 #include "nsIDOMCSSStyleSheet.h"
 #include "nsDOMCSSValueList.h"
 #define MOZ_GENERATED_EVENTS_INCLUDES
 #include "GeneratedEvents.h"
@@ -413,16 +415,17 @@
 
 #include "nsIImageDocument.h"
 
 // Storage includes
 #include "nsDOMStorage.h"
 
 // Device Storage
 #include "nsIDOMDeviceStorage.h"
+#include "nsIDOMDeviceStorageChangeEvent.h"
 #include "nsIDOMDeviceStorageCursor.h"
 
 // Drag and drop
 #include "nsIDOMDataTransfer.h"
 
 // Geolocation
 #include "nsIDOMGeoGeolocation.h"
 #include "nsIDOMGeoPosition.h"
@@ -1083,16 +1086,19 @@ static nsDOMClassInfoData sClassInfoData
 
   NS_DEFINE_CLASSINFO_DATA(TreeColumns, nsTreeColumnsSH,
                            ARRAY_SCRIPTABLE_FLAGS)
 #endif
 
   NS_DEFINE_CLASSINFO_DATA(CSSMozDocumentRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
+  NS_DEFINE_CLASSINFO_DATA(CSSSupportsRule, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
   NS_DEFINE_CLASSINFO_DATA(BeforeUnloadEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // SVG document
   NS_DEFINE_CLASSINFO_DATA(SVGDocument, nsDocumentSH,
                            DOCUMENT_SCRIPTABLE_FLAGS)
 
   // SVG element classes
@@ -1426,17 +1432,20 @@ static nsDOMClassInfoData sClassInfoData
                            WINDOW_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DataContainerEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MessageEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(DeviceStorage, nsDOMGenericSH,
+  NS_DEFINE_CLASSINFO_DATA(DeviceStorage, nsEventTargetSH,
+                           EVENTTARGET_SCRIPTABLE_FLAGS)
+
+  NS_DEFINE_CLASSINFO_DATA(DeviceStorageChangeEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DeviceStorageCursor, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(GeoGeolocation, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   
@@ -3166,16 +3175,20 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsITreeColumns)
   DOM_CLASSINFO_MAP_END
 #endif
 
   DOM_CLASSINFO_MAP_BEGIN(CSSMozDocumentRule, nsIDOMCSSMozDocumentRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMozDocumentRule)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(CSSSupportsRule, nsIDOMCSSSupportsRule)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSSupportsRule)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(BeforeUnloadEvent, nsIDOMBeforeUnloadEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBeforeUnloadEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
 #define DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES                           \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)                          \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGElement)                           \
@@ -4022,16 +4035,22 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN(MessageEvent, nsIDOMMessageEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMessageEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DeviceStorage, nsIDOMDeviceStorage)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceStorage)
+     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(DeviceStorageChangeEvent, nsIDOMDeviceStorageChangeEvent)
+     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceStorageChangeEvent)
+     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DeviceStorageCursor, nsIDOMDeviceStorageCursor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceStorageCursor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
@@ -5810,26 +5829,22 @@ DefineInterfaceConstants(JSContext *cx, 
       case nsXPTType::T_I16:
       case nsXPTType::T_U16:
       {
         v = INT_TO_JSVAL(c->GetValue()->val.u16);
         break;
       }
       case nsXPTType::T_I32:
       {
-        if (!JS_NewNumberValue(cx, c->GetValue()->val.i32, &v)) {
-          return NS_ERROR_UNEXPECTED;
-        }
+        v = JS_NumberValue(c->GetValue()->val.i32);
         break;
       }
       case nsXPTType::T_U32:
       {
-        if (!JS_NewNumberValue(cx, c->GetValue()->val.u32, &v)) {
-          return NS_ERROR_UNEXPECTED;
-        }
+        v = JS_NumberValue(c->GetValue()->val.u32);
         break;
       }
       default:
       {
 #ifdef DEBUG
         NS_ERROR("Non-numeric constant found in interface.");
 #endif
         continue;
@@ -6692,16 +6707,23 @@ ConstructorEnabled(const nsGlobalNameStr
 
   // For now don't expose server events unless user has explicitly enabled them
   if (aStruct->mDOMClassInfoID == eDOMClassInfo_EventSource_id) {
     if (!nsEventSource::PrefEnabled()) {
       return false;
     }
   }
 
+  // Don't expose CSSSupportsRule unless @supports processing is enabled.
+  if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSSupportsRule_id) {
+    if (!CSSSupportsRule::PrefEnabled()) {
+      return false;
+    }
+  }
+
   return true;
 }
 
 // static
 nsresult
 nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
                           JSObject *obj, jsid id, bool *did_resolve)
 {
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -188,16 +188,17 @@ DOMCI_CLASS(XULTreeBuilder)
 DOMCI_CLASS(DOMStringList)
 
 #ifdef MOZ_XUL
 DOMCI_CLASS(TreeColumn)
 DOMCI_CLASS(TreeColumns)
 #endif
 
 DOMCI_CLASS(CSSMozDocumentRule)
+DOMCI_CLASS(CSSSupportsRule)
 
 DOMCI_CLASS(BeforeUnloadEvent)
 
 // The SVG document
 DOMCI_CLASS(SVGDocument)
 
 // SVG element classes
 DOMCI_CLASS(SVGAElement)
@@ -379,16 +380,17 @@ DOMCI_CLASS(ModalContentWindow)
 // Data Events
 DOMCI_CLASS(DataContainerEvent)
 
 // event used for cross-domain message-passing and for server-sent events in
 // HTML5
 DOMCI_CLASS(MessageEvent)
 
 DOMCI_CLASS(DeviceStorage)
+DOMCI_CLASS(DeviceStorageChangeEvent)
 DOMCI_CLASS(DeviceStorageCursor)
 
 // Geolocation
 DOMCI_CLASS(GeoGeolocation)
 DOMCI_CLASS(GeoPosition)
 DOMCI_CLASS(GeoPositionCoords)
 DOMCI_CLASS(GeoPositionError)
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8344,17 +8344,18 @@ nsGlobalWindow::GetIndexedDB(nsIIDBFacto
       if (isThirdParty) {
         NS_WARNING("IndexedDB is not permitted in a third-party window.");
         *_retval = nullptr;
         return NS_OK;
       }
     }
 
     // This may be null if being created from a file.
-    rv = indexedDB::IDBFactory::Create(this, getter_AddRefs(mIndexedDB));
+    rv = indexedDB::IDBFactory::Create(this, nullptr,
+                                       getter_AddRefs(mIndexedDB));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<nsIIDBFactory> request(mIndexedDB);
   request.forget(_retval);
   return NS_OK;
 }
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2415,31 +2415,29 @@ nsJSContext::AddSupportsPrimitiveTojsval
     case nsISupportsPrimitive::TYPE_FLOAT : {
       nsCOMPtr<nsISupportsFloat> p(do_QueryInterface(argPrimitive));
       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
 
       float data;
 
       p->GetData(&data);
 
-      JSBool ok = ::JS_NewNumberValue(cx, data, aArgv);
-      NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
+      *aArgv = ::JS_NumberValue(data);
 
       break;
     }
     case nsISupportsPrimitive::TYPE_DOUBLE : {
       nsCOMPtr<nsISupportsDouble> p(do_QueryInterface(argPrimitive));
       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
 
       double data;
 
       p->GetData(&data);
 
-      JSBool ok = ::JS_NewNumberValue(cx, data, aArgv);
-      NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
+      *aArgv = ::JS_NumberValue(data);
 
       break;
     }
     case nsISupportsPrimitive::TYPE_INTERFACE_POINTER : {
       nsCOMPtr<nsISupportsInterfacePointer> p(do_QueryInterface(argPrimitive));
       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
 
       nsCOMPtr<nsISupports> data;
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1508,23 +1508,26 @@ def getJSToNativeConversionTemplate(type
     """
     # If we have a defaultValue then we're not actually optional for
     # purposes of what we need to be declared as.
     assert(defaultValue is None or not isOptional)
 
     # Also, we should not have a defaultValue if we know we're an object
     assert(not isDefinitelyObject or defaultValue is None)
 
-    # A helper function for dealing with failures due to the JS value being the
+    # Helper functions for dealing with failures due to the JS value being the
     # wrong type of value
-    def onFailure(failureCode, isWorker):
+    def onFailureNotAnObject(failureCode):
         return CGWrapper(CGGeneric(
                 failureCode or
-                "return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);"
-                % toStringBool(isWorker)), post="\n")
+                'return ThrowErrorMessage(cx, MSG_NOT_OBJECT);'), post="\n")
+    def onFailureBadType(failureCode, typeName):
+        return CGWrapper(CGGeneric(
+                failureCode or
+                'return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' % typeName), post="\n")
 
     # A helper function for handling default values.  Takes a template
     # body and the C++ code to set the default value and wraps the
     # given template body in handling for the default value.
     def handleDefault(template, setDefault):
         if defaultValue is None:
             return template
         return CGWrapper(
@@ -1542,30 +1545,30 @@ def getJSToNativeConversionTemplate(type
         if (defaultValue is not None and
             not isinstance(defaultValue, IDLNullValue)):
             raise TypeError("Can't handle non-null default value here")
         return handleDefault(template, codeToSetNull)
 
     # A helper function for wrapping up the template body for
     # possibly-nullable objecty stuff
     def wrapObjectTemplate(templateBody, isDefinitelyObject, type,
-                           codeToSetNull, isWorker, failureCode=None):
+                           codeToSetNull, failureCode=None):
         if not isDefinitelyObject:
             # Handle the non-object cases by wrapping up the whole
             # thing in an if cascade.
             templateBody = (
                 "if (${val}.isObject()) {\n" +
                 CGIndenter(CGGeneric(templateBody)).define() + "\n")
             if type.nullable():
                 templateBody += (
                     "} else if (${val}.isNullOrUndefined()) {\n"
                     "  %s;\n" % codeToSetNull)
             templateBody += (
                 "} else {\n" +
-                CGIndenter(onFailure(failureCode, isWorker)).define() +
+                CGIndenter(onFailureNotAnObject(failureCode)).define() +
                 "}")
             if type.nullable():
                 templateBody = handleDefaultNull(templateBody, codeToSetNull)
             else:
                 assert(defaultValue is None)
 
         return templateBody
 
@@ -1641,18 +1644,17 @@ for (uint32_t i = 0; i < length; ++i) {
                         "valPtr": "&temp",
                         "declName" : "(*arr.AppendElement())"
                         }
                     ))).define()
 
         templateBody += "\n}"
         templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
                                           type,
-                                          "const_cast< %s & >(${declName}).SetNull()" % mutableTypeName.define(),
-                                          descriptorProvider.workers)
+                                          "const_cast< %s & >(${declName}).SetNull()" % mutableTypeName.define())
         return (templateBody, typeName, None, isOptional)
 
     if type.isUnion():
         if isMember:
             raise TypeError("Can't handle unions as members, we have a "
                             "holderType")
         nullable = type.nullable();
         if nullable:
@@ -1661,64 +1663,69 @@ for (uint32_t i = 0; i < length; ++i) {
         assert(defaultValue is None or
                (isinstance(defaultValue, IDLNullValue) and nullable))
 
         unionArgumentObj = "${holderName}"
         if isOptional or nullable:
             unionArgumentObj += ".ref()"
 
         memberTypes = type.flatMemberTypes
+        names = []
 
         interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
         if len(interfaceMemberTypes) > 0:
             interfaceObject = []
             for memberType in interfaceMemberTypes:
                 if type.isGeckoInterface():
                     name = memberType.inner.identifier.name
                 else:
                     name = memberType.name
                 interfaceObject.append(CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext" % (unionArgumentObj, name)))
+                names.append(name)
             interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"), pre="done = ", post=";\n", reindent=True)
         else:
             interfaceObject = None
 
         arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes)
         if len(arrayObjectMemberTypes) > 0:
             assert len(arrayObjectMemberTypes) == 1
             memberType = arrayObjectMemberTypes[0]
             name = memberType.name
             arrayObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
             # XXX Now we're supposed to check for an array or a platform object
             # that supports indexed properties... skip that last for now. It's a
             # bit of a pain.
             arrayObject = CGWrapper(CGIndenter(arrayObject),
                                     pre="if (IsArrayLike(cx, &argObj)) {\n",
                                     post="}")
+            names.append(name)
         else:
             arrayObject = None
 
         dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
         if len(dateObjectMemberTypes) > 0:
             assert len(dateObjectMemberTypes) == 1
             memberType = dateObjectMemberTypes[0]
             name = memberType.name
             dateObject = CGGeneric("%s.SetTo%s(cx, ${val}, ${valPtr});\n"
                                    "done = true;" % (unionArgumentObj, name))
             dateObject = CGWrapper(CGIndenter(dateObject),
                                    pre="if (JS_ObjectIsDate(cx, &argObj)) {\n",
                                    post="\n}")
+            names.append(name)
         else:
             dateObject = None
 
         callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
         if len(callbackMemberTypes) > 0:
             assert len(callbackMemberTypes) == 1
             memberType = callbackMemberTypes[0]
             name = memberType.name
             callbackObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
+            names.append(name)
         else:
             callbackObject = None
 
         dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
         if len(dictionaryMemberTypes) > 0:
             raise TypeError("No support for unwrapping dictionaries as member "
                             "of a union")
         else:
@@ -1778,34 +1785,35 @@ for (uint32_t i = 0; i < length; ++i) {
         if len(otherMemberTypes) > 0:
             assert len(otherMemberTypes) == 1
             memberType = otherMemberTypes[0]
             if memberType.isEnum():
                 name = memberType.inner.identifier.name
             else:
                 name = memberType.name
             other = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
+            names.append(name)
             if hasObjectTypes:
                 other = CGWrapper(CGIndenter(other), "{\n", post="\n}")
                 if object:
                     join = " else "
                 else:
                     other = CGWrapper(other, pre="if (!done) ")
                     join = "\n"
                 templateBody = CGList([templateBody, other], join)
         else:
             other = None
 
         templateBody = CGWrapper(templateBody, pre="bool done = false, failed = false, tryNext;\n")
         throw = CGGeneric("if (failed) {\n"
                           "  return false;\n"
                           "}\n"
                           "if (!done) {\n"
-                          "  return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
-                          "}" % toStringBool(descriptorProvider.workers))
+                          "  return ThrowErrorMessage(cx, MSG_NOT_IN_UNION, \"%s\");\n"
+                          "}" % ", ".join(names))
         templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}")
 
         typeName = type.name
         argumentTypeName = typeName + "Argument"
         if nullable:
             typeName = "Nullable<" + typeName + " >"
         if isOptional:
             nonConstDecl = "const_cast<Optional<" + typeName + " >& >(${declName})"
@@ -1934,18 +1942,18 @@ for (uint32_t i = 0; i < length; ++i) {
                 # will just own stuff.
                 templateBody += "nsRefPtr<" + typeName + "> ${holderName};\n"
             else:
                 holderType = "nsRefPtr<" + typeName + ">"
             templateBody += (
                 "jsval tmpVal = ${val};\n" +
                 typePtr + " tmp;\n"
                 "if (NS_FAILED(xpc_qsUnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n")
-            templateBody += CGIndenter(onFailure(failureCode,
-                                                 descriptor.workers)).define()
+            templateBody += CGIndenter(onFailureBadType(failureCode,
+                                                        descriptor.interface.identifier.name)).define()
             templateBody += ("}\n"
                 "MOZ_ASSERT(tmp);\n")
 
             if not isDefinitelyObject:
                 # Our tmpVal will go out of scope, so we can't rely on it
                 # for rooting
                 templateBody += (
                     "if (tmpVal != ${val} && !${holderName}) {\n"
@@ -1954,17 +1962,17 @@ for (uint32_t i = 0; i < length; ++i) {
                     "  ${holderName} = tmp;\n"
                     "}\n")
 
             # And store our tmp, before it goes out of scope.
             templateBody += "${declName} = tmp;"
 
         templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
                                           type, "${declName} = NULL",
-                                          descriptor.workers, failureCode)
+                                          failureCode)
 
         declType = CGGeneric(declType)
         if holderType is not None:
             holderType = CGGeneric(holderType)
         return (templateBody, declType, holderType, isOptional)
 
     if type.isSpiderMonkeyInterface():
         if isMember:
@@ -1992,34 +2000,33 @@ for (uint32_t i = 0; i < length; ++i) {
                 constructLoc = "(const_cast<Optional<" + name + ">& >(${declName}))"
                 constructMethod = "Construct"
                 constructInternal = "Value"
             else:
                 declType = "NonNull<" + name + ">"
         template = (
             "%s.%s(cx, &${val}.toObject());\n"
             "if (!%s.%s().inited()) {\n"
-            "%s" # No newline here because onFailure() handles that
+            "%s" # No newline here because onFailureBadType() handles that
             "}\n" %
             (constructLoc, constructMethod, constructLoc, constructInternal,
-             CGIndenter(onFailure(failureCode, descriptorProvider.workers)).define()))
+             CGIndenter(onFailureBadType(failureCode, type.name)).define()))
         nullableTarget = ""
         if type.nullable():
             if isOptional:
                 mutableDecl = "(const_cast<Optional<" + name + "*>& >(${declName}))"
                 template += "%s.Construct();\n" % mutableDecl
                 nullableTarget = "%s.Value()" % mutableDecl
             else:
                 nullableTarget = "${declName}"
             template += "%s = ${holderName}.addr();" % nullableTarget
         elif not isOptional:
             template += "${declName} = ${holderName}.addr();"
         template = wrapObjectTemplate(template, isDefinitelyObject, type,
                                       "%s = NULL" % nullableTarget,
-                                      descriptorProvider.workers,
                                       failureCode)
 
         if holderType is not None:
             holderType = CGGeneric(holderType)
         # We handle all the optional stuff ourselves; no need for caller to do it.
         return (template, CGGeneric(declType), holderType, False)
 
     if type.isString():
@@ -2044,19 +2051,19 @@ for (uint32_t i = 0; i < length; ++i) {
                 return conversionCode
 
             if isinstance(defaultValue, IDLNullValue):
                 assert(type.nullable())
                 return handleDefault(conversionCode,
                                      "%s.SetNull()" % varName)
             return handleDefault(
                 conversionCode,
-                ("static const PRUnichar data[] = { %s, 0 };\n"
+                ("static const PRUnichar data[] = { %s };\n"
                  "%s.SetData(data, ArrayLength(data) - 1)" %
-                 (", ".join("'" + char + "'" for char in defaultValue.value),
+                 (", ".join(["'" + char + "'" for char in defaultValue.value] + ["0"]),
                   varName)))
 
         if isMember:
             # We have to make a copy, because our jsval may well not
             # live as long as our string needs to.
             declType = CGGeneric("nsString")
             return (
                 "{\n"
@@ -2143,17 +2150,17 @@ for (uint32_t i = 0; i < length; ++i) {
 
     if type.isObject():
         if isMember:
             raise TypeError("Can't handle member 'object'; need to sort out "
                             "rooting issues")
         template = wrapObjectTemplate("${declName} = &${val}.toObject();",
                                       isDefinitelyObject, type,
                                       "${declName} = NULL",
-                                      descriptorProvider.workers, failureCode)
+                                      failureCode)
         if type.nullable():
             declType = CGGeneric("JSObject*")
         else:
             declType = CGGeneric("NonNull<JSObject>")
         return (template, declType, None, isOptional)
 
     if type.isDictionary():
         if failureCode is not None:
@@ -2574,17 +2581,17 @@ if (!%(resultStr)s) {
     if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
                IDLType.Tags.uint16, IDLType.Tags.int32]:
         return setValue("INT_TO_JSVAL(int32_t(%s))" % result)
 
     elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64, IDLType.Tags.float,
                  IDLType.Tags.double]:
         # XXXbz will cast to double do the "even significand" thing that webidl
         # calls for for 64-bit ints?  Do we care?
-        return wrapAndSetPtr("JS_NewNumberValue(cx, double(%s), ${jsvalPtr})" % result)
+        return setValue("JS_NumberValue(double(%s))" % result)
 
     elif tag == IDLType.Tags.uint32:
         return setValue("UINT_TO_JSVAL(%s)" % result)
 
     elif tag == IDLType.Tags.bool:
         return setValue("BOOLEAN_TO_JSVAL(%s)" % result)
 
     else:
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -14,10 +14,13 @@
  * <ARGUMENT_COUNT> is an integer literal specifying the total number of
  * replaceable arguments in the following format string.
  *
  * <FORMAT_STRING> is a string literal, containing <ARGUMENT_COUNT> sequences
  * {X} where X  is an integer representing the argument number that will
  * be replaced with a string value when the error is reported.
  */
 
-MSG_DEF(MSG_INVALID_ENUM_VALUE, 2, "Value '{0}' is not a valid value for enumeration '{1}'.")
+MSG_DEF(MSG_INVALID_ENUM_VALUE, 2, "Value '{0}' is not a valid value for enumeration {1}.")
 MSG_DEF(MSG_MISSING_ARGUMENTS, 1, "Not enough arguments to {0}.")
+MSG_DEF(MSG_NOT_OBJECT, 0, "Value not an object.")
+MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE, 1, "Value does not implement interface {0}.")
+MSG_DEF(MSG_NOT_IN_UNION, 1, "Value could not be converted to any of: {0}.")
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -352,16 +352,17 @@ DiamondBranch1B implements DiamondImplem
 
 dictionary Dict : ParentDict {
   TestEnum someEnum;
   long x;
   long a;
   long b = 8;
   long z = 9;
   DOMString str;
+  DOMString empty = "";
   TestEnum otherEnum = "b";
   DOMString otherStr = "def";
   DOMString? yetAnotherStr = null;
 };
 
 dictionary ParentDict : GrandparentDict {
   long c = 5;
   TestInterface someInterface;
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -149,19 +149,19 @@ BluetoothAdapter::SetPropertyByValue(con
     }
   } else if (name.EqualsLiteral("Devices")) {
     mDeviceAddresses = value.get_ArrayOfnsString();
     nsresult rv;
     nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     if (sc) {
       rv =
         StringArrayToJSArray(sc->GetNativeContext(),
-                             sc->GetNativeGlobal(), mUuids, &mJsDeviceAddresses);
+                             sc->GetNativeGlobal(), mDeviceAddresses, &mJsDeviceAddresses);
       if (NS_FAILED(rv)) {
-        NS_WARNING("Cannot set JS Devices Addresses object!");
+        NS_WARNING("Cannot set JS Device Addresses object!");
         return;
       }
       Root();
     } else {
       NS_WARNING("Could not get context!");
     }
   } else {
 #ifdef DEBUG
@@ -330,17 +330,17 @@ BluetoothAdapter::GetDiscoverableTimeout
 
 NS_IMETHODIMP
 BluetoothAdapter::GetDevices(JSContext* aCx, jsval* aDevices)
 {
   if (mJsDeviceAddresses) {
     aDevices->setObject(*mJsDeviceAddresses);
   }
   else {
-    NS_WARNING("UUIDs not yet set!\n");
+    NS_WARNING("Devices not yet set!\n");
     return NS_ERROR_FAILURE;
   }    
   return NS_OK;
 }
 
 nsresult
 BluetoothAdapter::GetUuids(JSContext* aCx, jsval* aValue)
 {
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -14,16 +14,25 @@ Cu.import("resource://gre/modules/XPCOMU
 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
 const BROWSER_FRAMES_ENABLED_PREF = "dom.mozBrowserFramesEnabled";
 const TOUCH_EVENTS_ENABLED_PREF = "dom.w3c_touch_events.enabled";
 
 function debug(msg) {
   //dump("BrowserElementParent - " + msg + "\n");
 }
 
+function getBoolPref(prefName, def) {
+  try {
+    return Services.prefs.getBoolPref(prefName);
+  }
+  catch(err) {
+    return def;
+  }
+}
+
 /**
  * BrowserElementParent implements one half of <iframe mozbrowser>.  (The other
  * half is, unsurprisingly, BrowserElementChild.)
  *
  * BrowserElementParentFactory detects when we create a windows or docshell
  * contained inside a <iframe mozbrowser> and creates a BrowserElementParent
  * object for that window.
  *
@@ -184,17 +193,17 @@ function BrowserElementParent(frameLoade
         return self._sendDOMRequest(msgName);
       }
     };
   }
 
   // Define methods on the frame element.
   defineMethod('setVisible', this._setVisible);
   defineMethod('sendMouseEvent', this._sendMouseEvent);
-  if (Services.prefs.getBoolPref(TOUCH_EVENTS_ENABLED_PREF)) {
+  if (getBoolPref(TOUCH_EVENTS_ENABLED_PREF, false)) {
     defineMethod('sendTouchEvent', this._sendTouchEvent);
   }
   defineMethod('goBack', this._goBack);
   defineMethod('goForward', this._goForward);
   defineMethod('reload', this._reload);
   defineMethod('stop', this._stop);
   defineDOMRequestMethod('getScreenshot', 'get-screenshot');
   defineDOMRequestMethod('getCanGoBack', 'get-can-go-back');
--- a/dom/camera/CameraControl.cpp
+++ b/dom/camera/CameraControl.cpp
@@ -393,19 +393,17 @@ nsCameraControl::GetPreviewStream(const 
 {
   NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
 
   CameraSize size;
   nsresult rv = size.Init(cx, &aOptions);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIRunnable> getPreviewStreamTask = new GetPreviewStreamTask(this, size, onSuccess, onError);
-  mCameraThread->Dispatch(getPreviewStreamTask, NS_DISPATCH_NORMAL);
-
-  return NS_OK;
+  return NS_DispatchToMainThread(getPreviewStreamTask);
 }
 
 /* void autoFocus (in nsICameraAutoFocusCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
 NS_IMETHODIMP
 nsCameraControl::AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
 {
   NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
 
--- a/dom/camera/CameraPreview.cpp
+++ b/dom/camera/CameraPreview.cpp
@@ -57,22 +57,23 @@ public:
         break;
     }
   }
 
 protected:
   nsCOMPtr<CameraPreview> mPreview;
 };
 
-CameraPreview::CameraPreview(PRUint32 aWidth, PRUint32 aHeight)
+CameraPreview::CameraPreview(nsIThread* aCameraThread, PRUint32 aWidth, PRUint32 aHeight)
   : nsDOMMediaStream()
   , mWidth(aWidth)
   , mHeight(aHeight)
   , mFramesPerSecond(0)
   , mFrameCount(0)
+  , mCameraThread(aCameraThread)
 {
   DOM_CAMERA_LOGI("%s:%d : mWidth=%d, mHeight=%d : this=%p\n", __func__, __LINE__, mWidth, mHeight, this);
 
   mImageContainer = LayerManager::CreateImageContainer();
   MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
   mStream = gm->CreateInputStream(this);
   mInput = GetStream()->AsSourceStream();
   mInput->AddListener(new CameraPreviewListener(this));
@@ -81,18 +82,32 @@ CameraPreview::CameraPreview(PRUint32 aW
 void
 CameraPreview::SetFrameRate(PRUint32 aFramesPerSecond)
 {
   mFramesPerSecond = aFramesPerSecond;
   mInput->AddTrack(TRACK_VIDEO, mFramesPerSecond, 0, new VideoSegment());
   mInput->AdvanceKnownTracksTime(MEDIA_TIME_MAX);
 }
 
+void
+CameraPreview::Start()
+{
+  nsCOMPtr<nsIRunnable> cameraPreviewControl = NS_NewRunnableMethod(this, &CameraPreview::StartImpl);
+  nsresult rv = mCameraThread->Dispatch(cameraPreviewControl, NS_DISPATCH_NORMAL);
+  if (NS_FAILED(rv)) {
+    DOM_CAMERA_LOGE("failed to start camera preview (%d)\n", rv);
+  }
+}
+
+void
+CameraPreview::Stop()
+{
+  nsCOMPtr<nsIRunnable> cameraPreviewControl = NS_NewRunnableMethod(this, &CameraPreview::StopImpl);
+  nsresult rv = mCameraThread->Dispatch(cameraPreviewControl, NS_DISPATCH_NORMAL);
+  if (NS_FAILED(rv)) {
+    DOM_CAMERA_LOGE("failed to stop camera preview (%d)\n", rv);
+  }
+}
+
 CameraPreview::~CameraPreview()
 {
   DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
-
-  /**
-   * We _must_ remember to call RemoveListener on this before destroying this,
-   * else the media framework will trigger a double-free.
-   */
-  DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
 }
--- a/dom/camera/CameraPreview.h
+++ b/dom/camera/CameraPreview.h
@@ -18,38 +18,42 @@ using namespace mozilla::layers;
 namespace mozilla {
 
 class CameraPreview : public nsDOMMediaStream
                     , public MediaStreamListener
 {
 public:
   NS_DECL_ISUPPORTS
 
-  CameraPreview(PRUint32 aWidth, PRUint32 aHeight);
+  CameraPreview(nsIThread* aCameraThread, PRUint32 aWidth, PRUint32 aHeight);
 
   void SetFrameRate(PRUint32 aFramesPerSecond);
 
   NS_IMETHODIMP
   GetCurrentTime(double* aCurrentTime) {
     return nsDOMMediaStream::GetCurrentTime(aCurrentTime);
   }
 
-  virtual void Start() = 0;
-  virtual void Stop() = 0;
+  void Start();
+  void Stop();
+
+  virtual nsresult StartImpl() = 0;
+  virtual nsresult StopImpl() = 0;
 
 protected:
   virtual ~CameraPreview();
 
   PRUint32 mWidth;
   PRUint32 mHeight;
   PRUint32 mFramesPerSecond;
   SourceMediaStream* mInput;
   nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
   VideoSegment mVideoSegment;
   PRUint32 mFrameCount;
+  nsCOMPtr<nsIThread> mCameraThread;
 
   enum { TRACK_VIDEO = 1 };
 
 private:
   CameraPreview(const CameraPreview&) MOZ_DELETE;
   CameraPreview& operator=(const CameraPreview&) MOZ_DELETE;
 };
 
--- a/dom/camera/GonkCameraCapabilities.cpp
+++ b/dom/camera/GonkCameraCapabilities.cpp
@@ -45,22 +45,20 @@ static nsresult
 ParseZoomRatioItemAndAdd(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, const char* aStart, char** aEnd)
 {
   if (!*aEnd) {
     // make 'aEnd' follow the same semantics as strchr().
     aEnd = nullptr;
   }
 
   double d = strtod(aStart, aEnd);
-  jsval v;
+  d /= 100;
 
-  d /= 100;
-  if (!JS_NewNumberValue(aCx, d, &v)) {
-    return NS_ERROR_FAILURE;
-  }
+  jsval v = JS_NumberValue(d);
+
   if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 static nsresult
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -409,17 +409,17 @@ nsGonkCameraControl::SetParameter(PRUint
 
 nsresult
 nsGonkCameraControl::GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream)
 {
   nsCOMPtr<CameraPreview> preview = mPreview;
   nsresult rv;
 
   if (!preview) {
-    preview = new GonkCameraPreview(mHwHandle, aGetPreviewStream->mSize.width, aGetPreviewStream->mSize.height);
+    preview = new GonkCameraPreview(mCameraThread, mHwHandle, aGetPreviewStream->mSize.width, aGetPreviewStream->mSize.height);
     if (!preview) {
       if (aGetPreviewStream->mOnErrorCb) {
         rv = NS_DispatchToMainThread(new CameraErrorResult(aGetPreviewStream->mOnErrorCb, NS_LITERAL_STRING("OUT_OF_MEMORY")));
         NS_ENSURE_SUCCESS(rv, rv);
       }
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
--- a/dom/camera/GonkCameraPreview.cpp
+++ b/dom/camera/GonkCameraPreview.cpp
@@ -157,41 +157,45 @@ GonkCameraPreview::ReceiveFrame(PRUint8 
 
   mFrameCount += 1;
 
   if ((mFrameCount % 10) == 0) {
     DOM_CAMERA_LOGI("%s:%d : mFrameCount = %d\n", __func__, __LINE__, mFrameCount);
   }
 }
 
-void
-GonkCameraPreview::Start()
+nsresult
+GonkCameraPreview::StartImpl()
 {
   DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
 
   /**
    * We set and then immediately get the preview size, in case the camera
    * driver has decided to ignore our given dimensions.  We need to know
    * the dimensions the driver is using so that, if needed, we can properly
    * de-interlace the yuv420sp format in ReceiveFrame() above.
    */
   GonkCameraHardware::SetPreviewSize(mHwHandle, mWidth, mHeight);
   GonkCameraHardware::GetPreviewSize(mHwHandle, &mWidth, &mHeight);
   SetFrameRate(GonkCameraHardware::GetFps(mHwHandle));
 
-  if (GonkCameraHardware::StartPreview(mHwHandle) == OK) {
-    // GetPreviewFormat() must be called after StartPreview().
-    mFormat = GonkCameraHardware::GetPreviewFormat(mHwHandle);
-    DOM_CAMERA_LOGI("preview stream is (actually!) %d x %d (w x h), %d frames per second, format %d\n", mWidth, mHeight, mFramesPerSecond, mFormat);
-  } else {
+  if (GonkCameraHardware::StartPreview(mHwHandle) != OK) {
     DOM_CAMERA_LOGE("%s: failed to start preview\n", __func__);
+    return NS_ERROR_FAILURE;
   }
+
+  // GetPreviewFormat() must be called after StartPreview().
+  mFormat = GonkCameraHardware::GetPreviewFormat(mHwHandle);
+  DOM_CAMERA_LOGI("preview stream is (actually!) %d x %d (w x h), %d frames per second, format %d\n", mWidth, mHeight, mFramesPerSecond, mFormat);
+  return NS_OK;
 }
 
-void
-GonkCameraPreview::Stop()
+nsresult
+GonkCameraPreview::StopImpl()
 {
   DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
 
   GonkCameraHardware::StopPreview(mHwHandle);
   mInput->EndTrack(TRACK_VIDEO);
   mInput->Finish();
+
+  return NS_OK;
 }
--- a/dom/camera/GonkCameraPreview.h
+++ b/dom/camera/GonkCameraPreview.h
@@ -22,27 +22,27 @@
 #define DOM_CAMERA_LOG_LEVEL  3
 #include "CameraCommon.h"
 
 namespace mozilla {
 
 class GonkCameraPreview : public CameraPreview
 {
 public:
-  GonkCameraPreview(PRUint32 aHwHandle, PRUint32 aWidth, PRUint32 aHeight)
-    : CameraPreview(aWidth, aHeight)
+  GonkCameraPreview(nsIThread* aCameraThread, PRUint32 aHwHandle, PRUint32 aWidth, PRUint32 aHeight)
+    : CameraPreview(aCameraThread, aWidth, aHeight)
     , mHwHandle(aHwHandle)
     , mDiscardedFrameCount(0)
     , mFormat(GonkCameraHardware::PREVIEW_FORMAT_UNKNOWN)
   { }
 
   void ReceiveFrame(PRUint8 *aData, PRUint32 aLength);
 
-  void Start();
-  void Stop();
+  nsresult StartImpl();
+  nsresult StopImpl();
 
 protected:
   ~GonkCameraPreview()
   {
     Stop();
   }
 
   PRUint32 mHwHandle;
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -448,26 +448,21 @@ ContactManager.prototype = {
     if (!Services.prefs.getBoolPref("dom.mozContacts.enabled"))
       return null;
 
     this.initHelper(aWindow, ["Contacts:Find:Return:OK", "Contacts:Find:Return:KO",
                               "Contacts:Clear:Return:OK", "Contacts:Clear:Return:KO",
                               "Contact:Save:Return:OK", "Contact:Save:Return:KO",
                               "Contact:Remove:Return:OK", "Contact:Remove:Return:KO"]);
 
-    let principal = aWindow.document.nodePrincipal;
-    let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
-
-    let perm = principal == secMan.getSystemPrincipal()
-                 ? Ci.nsIPermissionManager.ALLOW_ACTION
-                 : Services.perms.testExactPermissionFromPrincipal(principal, "webcontacts-manage");
+    let perm = Services.perms.testExactPermissionFromPrincipal(aWindow.document.nodePrincipal, "contacts");
  
     //only pages with perm set can use the contacts
     this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
-    debug("has privileges :" + this.hasPrivileges);
+    debug("Contacts permission: " + this.hasPrivileges);
   },
 
   // Called from DOMRequestIpcHelper
   uninit: function uninit() {
     debug("uninit call");
     if (this._oncontactchange)
       this._oncontactchange = null;
   },
--- a/dom/contacts/fallback/ContactService.jsm
+++ b/dom/contacts/fallback/ContactService.jsm
@@ -35,26 +35,16 @@ let DOMContactManager = {
     }).bind(this));
 
     var idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
     idbManager.initWindowless(myGlobal);
     this._db = new ContactDB(myGlobal);
     this._db.init(myGlobal);
 
     Services.obs.addObserver(this, "profile-before-change", false);
-
-    try {
-      let hosts = Services.prefs.getCharPref("dom.mozContacts.whitelist")
-      hosts.split(",").forEach(function(aHost) {
-        debug("Add host: " + JSON.stringify(aHost));
-        if (aHost.length > 0)
-          Services.perms.add(Services.io.newURI(aHost, null, null), "webcontacts-manage",
-                             Ci.nsIPermissionManager.ALLOW_ACTION);
-      });
-    } catch(e) { debug(e); }
   },
 
   observe: function(aSubject, aTopic, aData) {
     myGlobal = null;
     this._messages.forEach((function(msgName) {
       ppmm.removeMessageListener(msgName, this);
     }).bind(this));
     Services.obs.removeObserver(this, "profile-before-change");
--- a/dom/contacts/tests/test_contacts_basics.html
+++ b/dom/contacts/tests/test_contacts_basics.html
@@ -19,17 +19,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 "use strict";
 
 var comp = SpecialPowers.wrap(Components);
 comp.utils.import("resource://gre/modules/ContactService.jsm");
 SpecialPowers.setBoolPref("dom.mozContacts.enabled", true);
-SpecialPowers.addPermission("webcontacts-manage", true, document);
+SpecialPowers.addPermission("contacts", true, document);
 
 // For Sorting
 var c1 = {
   name: "a",
   familyName: ["a"],
   givenName: ["a"],
 };
 
new file mode 100644
--- /dev/null
+++ b/dom/devicestorage/DeviceStorage.h
@@ -0,0 +1,73 @@
+/* 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 DeviceStorage_h
+#define DeviceStorage_h
+
+#include "nsIDOMDeviceStorage.h"
+#include "nsIFile.h"
+#include "nsIObserver.h"
+#include "nsDOMEventTargetHelper.h"
+
+class nsDOMDeviceStorage MOZ_FINAL
+  : public nsIDOMDeviceStorage
+  , public nsIFileUpdateListener
+  , public nsDOMEventTargetHelper
+  , public nsIObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMDEVICESTORAGE
+
+  NS_DECL_NSIFILEUPDATELISTENER
+  NS_DECL_NSIOBSERVER
+  NS_DECL_NSIDOMEVENTTARGET
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
+  NS_DECL_EVENT_HANDLER(change)
+
+  nsDOMDeviceStorage();
+
+  nsresult Init(nsPIDOMWindow* aWindow, const nsAString &aType);
+
+  void SetRootFileForType(const nsAString& aType);
+
+  static void CreateDeviceStoragesFor(nsPIDOMWindow* aWin,
+                                      const nsAString &aType,
+                                      nsDOMDeviceStorage** aStore);
+  void Shutdown();
+
+private:
+  ~nsDOMDeviceStorage();
+
+  nsresult GetInternal(const JS::Value & aName,
+                       JSContext* aCx,
+                       nsIDOMDOMRequest** aRetval,
+                       bool aEditable);
+
+  nsresult EnumerateInternal(const JS::Value & aName,
+                             const JS::Value & aOptions,
+                             JSContext* aCx,
+                             PRUint8 aArgc, 
+                             bool aEditable, 
+                             nsIDOMDeviceStorageCursor** aRetval);
+
+  PRInt32 mStorageType;
+  nsCOMPtr<nsIFile> mFile;
+
+  nsCOMPtr<nsIURI> mURI;
+
+  friend class WatchFileEvent;
+  friend class DeviceStorageRequest;
+
+  bool  mIsWatchingFile;
+
+  // nsIDOMDeviceStorage.type
+  enum {
+      DEVICE_STORAGE_TYPE_DEFAULT = 0,
+      DEVICE_STORAGE_TYPE_SHARED,
+      DEVICE_STORAGE_TYPE_EXTERNAL,
+  };
+};
+
+#endif
--- a/dom/devicestorage/Makefile.in
+++ b/dom/devicestorage/Makefile.in
@@ -26,17 +26,17 @@ EXPORTS_mozilla/dom/devicestorage = \
 
 CPPSRCS		= \
 		nsDeviceStorage.cpp \
 		DeviceStorageRequestParent.cpp \
 		DeviceStorageRequestChild.cpp \
 		$(NULL)
 
 EXPORTS         = \
-		nsDeviceStorage.h \
+		DeviceStorage.h \
 		$(NULL)
 
 LOCAL_INCLUDES = \
 		-I$(topsrcdir)/dom/base \
 		-I$(topsrcdir)/dom/ipc \
 		-I$(topsrcdir)/content/base/src \
 		-I$(topsrcdir)/content/events/src \
 		$(NULL)
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -1,13 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/PBrowserChild.h"
+#include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/dom/PContentPermissionRequestChild.h"
+
 #include "nsDeviceStorage.h"
+
+#include "nsDOMEvent.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIFile.h"
 #include "nsIDirectoryEnumerator.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIDOMFile.h"
 #include "nsDOMBlobBuilder.h"
 #include "nsNetUtil.h"
@@ -16,16 +24,20 @@
 #include "mozilla/Preferences.h"
 #include "nsJSUtils.h"
 #include "DictionaryHelpers.h"
 #include "mozilla/Attributes.h"
 #include "nsContentUtils.h"
 #include "nsXULAppAPI.h"
 #include "TabChild.h"
 #include "DeviceStorageRequestChild.h"
+#include "nsIDOMDeviceStorageChangeEvent.h"
+#include "nsCRT.h"
+#include "mozilla/Services.h"
+#include "nsIObserverService.h"
 
 // Microsoft's API Name hackery sucks
 #undef CreateEvent
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsIVolumeService.h"
 #endif
 
@@ -85,18 +97,18 @@ DeviceStorageFile::IsSafePath()
    }
   // split on /.  if any token is "", ., or .., return false.
   NS_ConvertUTF16toUTF8 cname(mPath);
   char* buffer = cname.BeginWriting();
   const char* token;
 
   while ((token = nsCRT::strtok(buffer, "/", &buffer))) {
     if (PL_strcmp(token, "") == 0 ||
-	PL_strcmp(token, ".") == 0 ||
-	PL_strcmp(token, "..") == 0 ) {
+        PL_strcmp(token, ".") == 0 ||
+        PL_strcmp(token, "..") == 0 ) {
       return false;
     }
   }
   return true;
 }
 
 void
 DeviceStorageFile::NormalizeFilePath() {
@@ -148,18 +160,18 @@ DeviceStorageFile::Write(nsIDOMBlob* aBl
   NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile);
 
   if (!outputStream) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIOutputStream> bufferedOutputStream;
   NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
-			     outputStream,
-			     4096*4);
+                             outputStream,
+                             4096*4);
 
   if (!bufferedOutputStream) {
     return NS_ERROR_FAILURE;
   }
 
   PRUint32 wrote;
   bufferedOutputStream->WriteFrom(stream, bufSize, &wrote);
   bufferedOutputStream->Close();
@@ -192,28 +204,31 @@ DeviceStorageFile::Write(InfallibleTArra
   if (aBits.Length() != wrote) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 void
 DeviceStorageFile::CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles,
-				PRUint64 aSince)
+                                PRUint64 aSince)
 {
   nsString rootPath;
-  mFile->GetPath(rootPath);
+  nsresult rv = mFile->GetPath(rootPath);
+  if (NS_FAILED(rv)) {
+    return;
+  }
 
   return collectFilesInternal(aFiles, aSince, rootPath);
 }
 
 void
 DeviceStorageFile::collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles,
-					PRUint64 aSince,
-					nsAString& aRootPath)
+                                        PRUint64 aSince,
+                                        nsAString& aRootPath)
 {
   nsCOMPtr<nsISimpleEnumerator> e;
   mFile->GetDirectoryEntries(getter_AddRefs(e));
 
   if (!e) {
     return;
   }
 
@@ -231,17 +246,20 @@ DeviceStorageFile::collectFilesInternal(
 
     bool isDir;
     f->IsDirectory(&isDir);
 
     bool isFile;
     f->IsFile(&isFile);
 
     nsString fullpath;
-    f->GetPath(fullpath);
+    nsresult rv = f->GetPath(fullpath);
+    if (NS_FAILED(rv)) {
+      continue;
+    }
 
     if (!StringBeginsWith(fullpath, aRootPath)) {
       NS_ERROR("collectFiles returned a path that does not belong!");
       continue;
     }
 
     nsAString::size_type len = aRootPath.Length() + 1; // +1 for the trailing /
     nsDependentSubstring newPath = Substring(fullpath, len);
@@ -256,117 +274,94 @@ DeviceStorageFile::collectFilesInternal(
       aFiles.AppendElement(dsf);
     }
   }
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS0(DeviceStorageFile)
 
 
-// TODO - eventually, we will want to factor this method
-// out into different system specific subclasses (or
-// something)
-PRInt32
-nsDOMDeviceStorage::SetRootFileForType(const nsAString& aType, const PRInt32 aIndex)
+void
+nsDOMDeviceStorage::SetRootFileForType(const nsAString& aType)
 {
-  PRInt32 typeResult = DEVICE_STORAGE_TYPE_DEFAULT;
-
   nsCOMPtr<nsIFile> f;
   nsCOMPtr<nsIProperties> dirService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
   NS_ASSERTION(dirService, "Must have directory service");
 
 #ifdef MOZ_WIDGET_GONK
   mFile = nullptr;
 
   nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID);
   if (!vs) {
-    return typeResult;
+    return;
   }
 
   nsCOMPtr<nsIVolume> v;
   vs->GetVolumeByPath(NS_LITERAL_STRING("/sdcard"), getter_AddRefs(v));
   
   if (!v) {
-    return typeResult;
+    return;
   }
 
   PRInt32 state;
   v->GetState(&state);
 
   if (state != nsIVolume::STATE_MOUNTED) {
-    return typeResult;
+    return;
   }
 #endif
 
   // Picture directory
   if (aType.Equals(NS_LITERAL_STRING("pictures"))) {
 #ifdef MOZ_WIDGET_GONK
-    if (aIndex == 0) {
-      NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/DCIM"), false, getter_AddRefs(f));
-    }
+    NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/DCIM"), false, getter_AddRefs(f));
 #elif defined (MOZ_WIDGET_COCOA)
-    if (aIndex == 0) {
-      dirService->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
-    }
+    dirService->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #elif defined (XP_UNIX)
-    if (aIndex == 0) {
-      dirService->Get(NS_UNIX_XDG_PICTURES_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
-    }
+    dirService->Get(NS_UNIX_XDG_PICTURES_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #endif
   }
 
   // Video directory
   if (aType.Equals(NS_LITERAL_STRING("videos"))) {
 #ifdef MOZ_WIDGET_GONK
-    if (aIndex == 0) {
-      NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/Movies"), false, getter_AddRefs(f));
-    }
+    NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/Movies"), false, getter_AddRefs(f));
 #elif defined (MOZ_WIDGET_COCOA)
-    if (aIndex == 0) {
-      dirService->Get(NS_OSX_MOVIE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
-    }
+    dirService->Get(NS_OSX_MOVIE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #elif defined (XP_UNIX)
-    if (aIndex == 0) {
-      dirService->Get(NS_UNIX_XDG_VIDEOS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
-    }
+    dirService->Get(NS_UNIX_XDG_VIDEOS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #endif
   }
 
   // Music directory
   if (aType.Equals(NS_LITERAL_STRING("music"))) {
 #ifdef MOZ_WIDGET_GONK
-    if (aIndex == 0) {
-      NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/Music"), false, getter_AddRefs(f));
-    }
+    NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/Music"), false, getter_AddRefs(f));
 #elif defined (MOZ_WIDGET_COCOA)
-    if (aIndex == 0) {
-      dirService->Get(NS_OSX_MUSIC_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
-    }
+    dirService->Get(NS_OSX_MUSIC_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #elif defined (XP_UNIX)
-    if (aIndex == 0) {
-      dirService->Get(NS_UNIX_XDG_MUSIC_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
-    }
+    dirService->Get(NS_UNIX_XDG_MUSIC_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #endif
   }
 
   // in testing, we have access to a few more directory locations
   if (mozilla::Preferences::GetBool("device.storage.testing", false)) {
 
     // testing directory
-    if (aType.Equals(NS_LITERAL_STRING("testing")) && aIndex == 0) {
+    if (aType.Equals(NS_LITERAL_STRING("testing"))) {
       dirService->Get(NS_OS_TEMP_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
       if (f) {
 	f->AppendRelativeNativePath(NS_LITERAL_CSTRING("device-storage-testing"));
 	f->Create(nsIFile::DIRECTORY_TYPE, 0777);
+       f->Normalize();
       }
     }
   } 
 
   mFile = f;
-  return typeResult;
 }
 
 static jsval nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aWindow, "Null Window");
 
   if (aFile->mEditable) {
@@ -438,16 +433,102 @@ jsval StringToJsval(nsPIDOMWindow* aWind
   jsval result = JSVAL_NULL;
   if (!xpc::StringToJsval(cx, aString, &result)) {
     return JSVAL_NULL;
   }
 
   return result;
 }
 
+class nsDOMDeviceStorageChangeEvent : public nsDOMEvent, public nsIDOMDeviceStorageChangeEvent
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_FORWARD_NSIDOMEVENT(nsDOMEvent::)
+  NS_DECL_NSIDOMDEVICESTORAGECHANGEEVENT
+
+  nsDOMDeviceStorageChangeEvent();
+
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx,
+                                jsval* aVal);
+    
+  NS_IMETHOD Init(const nsAString & aEventTypeArg,
+                  bool aCanBubbleArg,
+                  bool aCancelableArg,
+                  nsAString& aPath,
+                  nsAString& aReason);
+
+private:
+  ~nsDOMDeviceStorageChangeEvent();
+
+protected:
+  nsString mPath;
+  nsString mReason;
+};
+
+DOMCI_DATA(DeviceStorageChangeEvent, nsDOMDeviceStorageChangeEvent)
+
+NS_INTERFACE_MAP_BEGIN(nsDOMDeviceStorageChangeEvent)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceStorageChangeEvent)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceStorageChangeEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+
+NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorageChangeEvent, nsDOMEvent)
+NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorageChangeEvent, nsDOMEvent)
+
+nsDOMDeviceStorageChangeEvent::nsDOMDeviceStorageChangeEvent()
+  : nsDOMEvent(nullptr, nullptr)
+{ 
+}
+
+nsDOMDeviceStorageChangeEvent::~nsDOMDeviceStorageChangeEvent()
+{
+}
+
+NS_IMETHODIMP
+nsDOMDeviceStorageChangeEvent::Init(const nsAString & aEventTypeArg,
+                                    bool aCanBubbleArg,
+                                    bool aCancelableArg,
+                                    nsAString& aPath,
+                                    nsAString& aReason)
+{
+  nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mPath = aPath;
+  mReason = aReason;
+  return NS_OK;
+}
+
+nsresult
+nsDOMDeviceStorageChangeEvent::InitFromCtor(const nsAString& aType,
+                                            JSContext* aCx,
+                                            jsval* aVal)
+{
+  mozilla::dom::DeviceStorageChangeEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return Init(aType, d.bubbles, d.cancelable, d.path, d.reason);
+}
+
+NS_IMETHODIMP
+nsDOMDeviceStorageChangeEvent::GetPath(nsAString & aPath)
+{
+  aPath = mPath;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMDeviceStorageChangeEvent::GetReason(nsAString & aReason)
+{
+  aReason = mReason;
+  return NS_OK;
+}
+
 class DeviceStorageCursorRequest MOZ_FINAL
   : public nsIContentPermissionRequest
   , public PCOMContentPermissionRequestChild
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageCursorRequest, nsIContentPermissionRequest)
 
@@ -483,21 +564,21 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DeviceStorageCursorRequest)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageCursorRequest)
 NS_IMPL_CYCLE_COLLECTION_CLASS(DeviceStorageCursorRequest)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DeviceStorageCursorRequest)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCursor)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCursor)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DeviceStorageCursorRequest)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCursor, nsIDOMDeviceStorageCursor)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCursor, nsIDOMDeviceStorageCursor)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
 class PostErrorEvent : public nsRunnable
 {
 public:
   PostErrorEvent(nsRefPtr<DOMRequest>& aRequest, const char* aMessage, DeviceStorageFile* aFile)
   {
@@ -702,17 +783,22 @@ nsDOMDeviceStorageCursor::Allow()
                                                  mFile);
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
 
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
 
     nsString fullpath;
-    mFile->mFile->GetPath(fullpath);
+    nsresult rv = mFile->mFile->GetPath(fullpath);
+
+    if (NS_FAILED(rv)) {
+      // just do nothing
+      return NS_OK;
+    }
 
     PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(this, mFile);
     DeviceStorageEnumerationParams params(fullpath, mSince);
     ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
     return NS_OK;
   }
 
   nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
@@ -822,24 +908,24 @@ public:
     NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
     nsresult rv = mFile->Write(mBlob);
 
     if (NS_FAILED(rv)) {
       mFile->mFile->Remove(false);
 
       nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest,
-							  POST_ERROR_EVENT_UNKNOWN,
-							  mFile);
+                                                          POST_ERROR_EVENT_UNKNOWN,
+                                                          mFile);
       NS_DispatchToMainThread(event);
       return NS_OK;
     }
 
     nsCOMPtr<PostResultEvent> event = new PostResultEvent(mRequest,
-							  mFile->mPath);
+                                                          mFile->mPath);
     NS_DispatchToMainThread(event);
 
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsIDOMBlob> mBlob;
   nsRefPtr<DeviceStorageFile> mFile;
@@ -922,51 +1008,69 @@ private:
 
 class DeviceStorageRequest MOZ_FINAL
   : public nsIContentPermissionRequest
   , public nsIRunnable
   , public PCOMContentPermissionRequestChild
 {
 public:
 
-    enum {
+    enum DeviceStorageRequestType {
         DEVICE_STORAGE_REQUEST_READ,
         DEVICE_STORAGE_REQUEST_WRITE,
-        DEVICE_STORAGE_REQUEST_DELETE
+        DEVICE_STORAGE_REQUEST_DELETE,
+        DEVICE_STORAGE_REQUEST_WATCH
     };
-    DeviceStorageRequest(const PRInt32 aRequestType,
+
+    DeviceStorageRequest(const DeviceStorageRequestType aRequestType,
+                         nsPIDOMWindow *aWindow,
+                         nsIURI *aURI,
+                         DeviceStorageFile *aFile,
+                         DOMRequest* aRequest,
+                         nsDOMDeviceStorage *aDeviceStorage,
+                         nsIDOMEventListener *aListener)
+      : mRequestType(aRequestType)
+      , mWindow(aWindow)
+      , mURI(aURI)
+      , mFile(aFile)
+      , mRequest(aRequest)
+      , mDeviceStorage(aDeviceStorage)
+      , mListener(aListener) {}  
+
+    DeviceStorageRequest(const DeviceStorageRequestType aRequestType,
                          nsPIDOMWindow *aWindow,
                          nsIURI *aURI,
                          DeviceStorageFile *aFile,
                          DOMRequest* aRequest,
                          nsIDOMBlob *aBlob = nullptr)
-        : mRequestType(aRequestType)
-        , mWindow(aWindow)
-        , mURI(aURI)
-        , mFile(aFile)
-        , mRequest(aRequest)
-        , mBlob(aBlob) {}
+      : mRequestType(aRequestType)
+      , mWindow(aWindow)
+      , mURI(aURI)
+      , mFile(aFile)
+      , mRequest(aRequest)
+      , mBlob(aBlob) {}
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageRequest, nsIContentPermissionRequest)
 
   NS_IMETHOD Run() {
 
     if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
       Allow();
       return NS_OK;
     }
 
     if (XRE_GetProcessType() == GeckoProcessType_Content) {
 
       // because owner implements nsITabChild, we can assume that it is
       // the one and only TabChild.
       TabChild* child = GetTabChildFrom(mWindow->GetDocShell());
-      if (!child)
+      if (!child) {
         return NS_OK;
+      }
 
       // Retain a reference so the object isn't deleted without IPDL's knowledge.
       // Corresponding release occurs in DeallocPContentPermissionRequest.
       AddRef();
 
       nsCString type = NS_LITERAL_CSTRING("device-storage");
       child->SendPContentPermissionRequestConstructor(this, type, IPC::URI(mURI));
 
@@ -1018,71 +1122,98 @@ public:
   {
     nsCOMPtr<nsIRunnable> r;
 
     if (!mRequest) {
       return NS_ERROR_FAILURE;
     }
 
     nsString fullpath;
-    mFile->mFile->GetPath(fullpath);
+    nsresult rv = mFile->mFile->GetPath(fullpath);
+
+    if (NS_FAILED(rv)) {
+      // just do nothing
+      return NS_OK;
+    }
 
     switch(mRequestType) {
       case DEVICE_STORAGE_REQUEST_WRITE:
       {
         if (!mBlob) {
           return NS_ERROR_FAILURE;
         }
 
-	if (XRE_GetProcessType() != GeckoProcessType_Default) {
-	  PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
+        if (XRE_GetProcessType() != GeckoProcessType_Default) {
+          PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
 
-	  nsCOMPtr<nsIInputStream> stream;
-	  mBlob->GetInternalStream(getter_AddRefs(stream));
+          nsCOMPtr<nsIInputStream> stream;
+          mBlob->GetInternalStream(getter_AddRefs(stream));
 
-	  InfallibleTArray<PRUint8> bits;
-	  PRUint32 bufSize, numRead;
+          InfallibleTArray<PRUint8> bits;
+          PRUint32 bufSize, numRead;
 
-	  stream->Available(&bufSize);
-	  bits.SetCapacity(bufSize);
+          stream->Available(&bufSize);
+          bits.SetCapacity(bufSize);
 
-	  void* buffer = (void*) bits.Elements();
+          void* buffer = (void*) bits.Elements();
 
-	  stream->Read((char*)buffer, bufSize, &numRead);
+          stream->Read((char*)buffer, bufSize, &numRead);
 
-	  DeviceStorageAddParams params(fullpath, bits);
-	  ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
-	  return NS_OK;
-	}
-	r = new WriteFileEvent(mBlob, mFile, mRequest);
+          DeviceStorageAddParams params(fullpath, bits);
+          ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
+          return NS_OK;
+        }
+        r = new WriteFileEvent(mBlob, mFile, mRequest);
         break;
       }
+
       case DEVICE_STORAGE_REQUEST_READ:
       {
-	if (XRE_GetProcessType() != GeckoProcessType_Default) {
-	  PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
-	  DeviceStorageGetParams params(fullpath);
-	  ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
-	  return NS_OK;
-	}
+        if (XRE_GetProcessType() != GeckoProcessType_Default) {
+          PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
+          DeviceStorageGetParams params(fullpath);
+          ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
+          return NS_OK;
+        }
 
         r = new ReadFileEvent(mFile, mRequest);
         break;
       }
+
       case DEVICE_STORAGE_REQUEST_DELETE:
       {
-	if (XRE_GetProcessType() != GeckoProcessType_Default) {
-	  PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
-	  DeviceStorageDeleteParams params(fullpath);
-	  ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
-	  return NS_OK;
-	}
+        if (XRE_GetProcessType() != GeckoProcessType_Default) {
+          PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
+          DeviceStorageDeleteParams params(fullpath);
+          ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
+          return NS_OK;
+        }
         r = new DeleteFileEvent(mFile, mRequest);
         break;
       }
+
+      case DEVICE_STORAGE_REQUEST_WATCH:
+      {
+         if (XRE_GetProcessType() != GeckoProcessType_Default) {
+           nsString fullpath;
+           mFile->mFile->GetPath(fullpath);
+           nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+           obs->AddObserver(mDeviceStorage, "file-watcher-update", false);
+           ContentChild::GetSingleton()->SendAddFileWatch(fullpath);
+         } else {
+           if (!mDeviceStorage->mIsWatchingFile) {
+
+             //TODO
+
+             mFile->mFile->Watch(mDeviceStorage);
+             mDeviceStorage->mIsWatchingFile = true;
+           }
+         }
+        return NS_OK;
+      }
     }
 
     if (r) {
       nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       NS_ASSERTION(target, "Must have stream transport service");
       target->Dispatch(r, NS_DISPATCH_NORMAL);
     }
     return NS_OK;
@@ -1107,70 +1238,83 @@ public:
 private:
   PRInt32 mRequestType;
   nsCOMPtr<nsPIDOMWindow> mWindow;
   nsCOMPtr<nsIURI> mURI;
   nsRefPtr<DeviceStorageFile> mFile;
 
   nsRefPtr<DOMRequest> mRequest;
   nsCOMPtr<nsIDOMBlob> mBlob;
+  nsRefPtr<nsDOMDeviceStorage> mDeviceStorage;
+  nsCOMPtr<nsIDOMEventListener> mListener;
 };
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageRequest)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
   NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
   NS_INTERFACE_MAP_ENTRY(nsIRunnable)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DeviceStorageRequest)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageRequest)
 NS_IMPL_CYCLE_COLLECTION_CLASS(DeviceStorageRequest)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DeviceStorageRequest)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRequest)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindow)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mBlob)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDeviceStorage)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListener)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DeviceStorageRequest)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mRequest, nsIDOMDOMRequest)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWindow, nsPIDOMWindow)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mBlob, nsIDOMBlob)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mDeviceStorage, nsIDOMDeviceStorage)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mListener, nsIDOMEventListener)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMDeviceStorage)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(change)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(change)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
 DOMCI_DATA(DeviceStorage, nsDOMDeviceStorage)
 
-NS_INTERFACE_MAP_BEGIN(nsDOMDeviceStorage)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDeviceStorage)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceStorage)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDeviceStorage)
+  NS_INTERFACE_MAP_ENTRY(nsIFileUpdateListener)
+  NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceStorage)
-NS_INTERFACE_MAP_END
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
-NS_IMPL_THREADSAFE_ADDREF(nsDOMDeviceStorage)
-NS_IMPL_THREADSAFE_RELEASE(nsDOMDeviceStorage)
+NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
 
 nsDOMDeviceStorage::nsDOMDeviceStorage()
- : mStorageType(DEVICE_STORAGE_TYPE_DEFAULT)
-{
-}
+  : mIsWatchingFile(false)
+{ }
 
 nsresult
-nsDOMDeviceStorage::Init(nsPIDOMWindow* aWindow, const nsAString &aType, const PRInt32 aIndex)
+nsDOMDeviceStorage::Init(nsPIDOMWindow* aWindow, const nsAString &aType)
 {
   NS_ASSERTION(aWindow, "Must have a content dom");
 
-  mStorageType = SetRootFileForType(aType, aIndex);
+  SetRootFileForType(aType);
   if (!mFile) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  mOwner = do_GetWeakReference(aWindow);
-  if (!mOwner) {
-    return NS_ERROR_FAILURE;
-  }
+  BindToOwner(aWindow);
 
   // Grab the uri of the document
   nsCOMPtr<nsIDOMDocument> domdoc;
   aWindow->GetDocument(getter_AddRefs(domdoc));
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
   if (!doc) {
     return NS_ERROR_FAILURE;
   }
@@ -1178,60 +1322,44 @@ nsDOMDeviceStorage::Init(nsPIDOMWindow* 
   return NS_OK;
 }
 
 nsDOMDeviceStorage::~nsDOMDeviceStorage()
 {
 }
 
 void
+nsDOMDeviceStorage::Shutdown()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  if (mIsWatchingFile) {
+    if (XRE_GetProcessType() != GeckoProcessType_Default) {
+      nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+      obs->RemoveObserver(this, "file-watcher-update");
+
+      nsString fullpath;
+      mFile->GetPath(fullpath);
+      ContentChild::GetSingleton()->SendRemoveFileWatch(fullpath);
+    }
+    else {
+      mFile->Unwatch(this);
+    }
+  }
+}
+
+void
 nsDOMDeviceStorage::CreateDeviceStoragesFor(nsPIDOMWindow* aWin,
                                             const nsAString &aType,
-                                            nsIVariant** _retval)
+                                            nsDOMDeviceStorage** aStore)
 {
-  nsTArray<nsRefPtr<nsIDOMDeviceStorage> > stores;
-
-  PRInt32 index = 0;
-  while (1) {
-    nsresult rv;
-    nsRefPtr<nsDOMDeviceStorage> storage = new nsDOMDeviceStorage();
-    rv = storage->Init(aWin, aType, index++);
-    if (NS_FAILED(rv))
-      break;
-    stores.AppendElement(storage);
-  }
-
-  nsCOMPtr<nsIWritableVariant> result = do_CreateInstance("@mozilla.org/variant;1");
-  if (!result) {
-    return;
+  nsRefPtr<nsDOMDeviceStorage> storage = new nsDOMDeviceStorage();
+  if (NS_SUCCEEDED(storage->Init(aWin, aType))) {
+    NS_ADDREF(*aStore = storage);
   }
-
-  result->SetAsArray(nsIDataType::VTYPE_INTERFACE,
-                     &NS_GET_IID(nsIDOMDeviceStorage),
-                     stores.Length(),
-                     const_cast<void*>(static_cast<const void*>(stores.Elements())));
-  NS_ADDREF(*_retval = result);
-}
-
-NS_IMETHODIMP
-nsDOMDeviceStorage::GetType(nsAString & aType)
-{
-  switch(mStorageType) {
-    case DEVICE_STORAGE_TYPE_EXTERNAL:
-      aType.AssignLiteral("external");
-      break;
-    case DEVICE_STORAGE_TYPE_SHARED:
-      aType.AssignLiteral("shared");
-      break;
-    case DEVICE_STORAGE_TYPE_DEFAULT:
-    default:
-      aType.AssignLiteral("default");
-      break;
-  }
-  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::Add(nsIDOMBlob *aBlob, nsIDOMDOMRequest * *_retval)
 {
   // possible race here w/ unique filename
   char buffer[128];
   NS_MakeRandomString(buffer, 128);
@@ -1246,17 +1374,17 @@ NS_IMETHODIMP
 nsDOMDeviceStorage::AddNamed(nsIDOMBlob *aBlob,
                              const nsAString & aPath,
                              nsIDOMDOMRequest * *_retval)
 {
   // if the blob is null here, bail
   if (aBlob == nullptr)
     return NS_OK;
 
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mOwner);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     return NS_ERROR_UNEXPECTED;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   NS_ADDREF(*_retval = request);
 
   nsCOMPtr<nsIRunnable> r;
@@ -1291,17 +1419,17 @@ nsDOMDeviceStorage::GetEditable(const JS
 }
 
 nsresult
 nsDOMDeviceStorage::GetInternal(const JS::Value & aPath,
                                 JSContext* aCx,
                                 nsIDOMDOMRequest * *_retval,
                                 bool aEditable)
 {
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mOwner);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     return NS_ERROR_UNEXPECTED;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   NS_ADDREF(*_retval = request);
 
   nsCOMPtr<nsIRunnable> r;
@@ -1330,17 +1458,17 @@ nsDOMDeviceStorage::GetInternal(const JS
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::Delete(const JS::Value & aPath, JSContext* aCx, nsIDOMDOMRequest * *_retval)
 {
   nsCOMPtr<nsIRunnable> r;
 
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mOwner);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     return NS_ERROR_UNEXPECTED;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   NS_ADDREF(*_retval = request);
 
   JSString* jsstr = JS_ValueToString(aCx, aPath);
@@ -1406,17 +1534,17 @@ ExtractDateFromOptions(JSContext* aCx, c
 nsresult
 nsDOMDeviceStorage::EnumerateInternal(const JS::Value & aName,
                                      const JS::Value & aOptions,
                                      JSContext* aCx,
                                      PRUint8 aArgc,
                                      bool aEditable,
                                      nsIDOMDeviceStorageCursor** aRetval)
 {
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mOwner);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win)
     return NS_ERROR_UNEXPECTED;
 
   PRTime since = 0;
   nsString path;
   path.SetIsVoid(true);
 
   if (aArgc > 0) {
@@ -1473,8 +1601,211 @@ nsDOMDeviceStorage::EnumerateInternal(co
 
   nsCOMPtr<nsIContentPermissionPrompt> prompt = do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
   if (prompt) {
     prompt->Prompt(r);
   }
 
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsDOMDeviceStorage::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
+{
+  // data strings will have the format of
+  //  reason:path
+  nsDependentString data(aData);
+
+  nsAString::const_iterator start, end;
+  nsAString::const_iterator colon;
+
+  data.BeginReading(start);
+  data.EndReading(end);
+  colon = end;
+
+  nsString reason;
+  nsString filepath;
+  if (!FindInReadable(NS_LITERAL_STRING(":"), start, colon)) {
+    return NS_OK;
+  }
+   
+  filepath = Substring(colon, end);
+  data.BeginReading(start);
+  reason = Substring(start, --colon);
+
+  nsCOMPtr<nsIFile> f;
+  NS_NewLocalFile(filepath, false, getter_AddRefs(f));
+ 
+  nsCString creason;
+  creason.AssignWithConversion(reason);
+  CopyUTF16toUTF8(reason, creason);
+
+  Update(creason.get(), f);
+ 
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMDeviceStorage::Update(const char* aReason, nsIFile* aFile)
+{
+  nsString rootpath;
+  nsresult rv = mFile->GetPath(rootpath);
+  if (NS_FAILED(rv)) {
+    return NS_OK;
+  }
+  
+  nsString fullpath;
+  rv = aFile->GetPath(fullpath);
+  if (NS_FAILED(rv)) {
+    return NS_OK;
+  }
+
+  NS_ASSERTION(fullpath.Length() >= rootpath.Length(), "Root path longer than full path!");
+  
+  if (!StringBeginsWith(fullpath, rootpath)) {
+    NS_WARNING("Observing a path outside of our root!");
+    return NS_OK;
+  }
+
+  nsAString::size_type len = rootpath.Length() + 1; // +1 for the trailing /
+  nsDependentSubstring newPath (fullpath, len, fullpath.Length() - len);
+
+  nsRefPtr<nsDOMDeviceStorageChangeEvent> event = new nsDOMDeviceStorageChangeEvent();
+  nsString reason;
+  reason.AssignWithConversion(aReason);
+  rv = event->Init(NS_LITERAL_STRING("change"), true, false, newPath, reason);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIDOMDeviceStorageChangeEvent> e = event.get();
+
+  bool ignore;
+  DispatchEvent(e, &ignore);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMDeviceStorage::AddEventListener(const nsAString & aType,
+                                     nsIDOMEventListener *aListener,
+                                     bool aUseCapture,
+                                     bool aWantsUntrusted,
+                                     PRUint8 aArgc)
+{
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
+  nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mFile);
+  nsCOMPtr<nsIRunnable> r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_WATCH,
+                                                     win, mURI, dsf, request, this, aListener);
+  NS_DispatchToMainThread(r);
+  return nsDOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted, aArgc);
+}
+
+NS_IMETHODIMP
+nsDOMDeviceStorage::AddSystemEventListener(const nsAString & aType,
+                                           nsIDOMEventListener *aListener,
+                                           bool aUseCapture,
+                                           bool aWantsUntrusted,
+                                           PRUint8 aArgc)
+{
+  return nsDOMDeviceStorage::AddEventListener(aType,aListener,aUseCapture,aWantsUntrusted, aArgc);
+}
+
+NS_IMETHODIMP
+nsDOMDeviceStorage::RemoveEventListener(const nsAString & aType,
+                                        nsIDOMEventListener *aListener,
+                                        bool aUseCapture)
+{
+  nsDOMEventTargetHelper::RemoveEventListener(aType, aListener, false);
+
+  if (mIsWatchingFile && !HasListenersFor(NS_LITERAL_STRING("change"))) {
+    if (XRE_GetProcessType() != GeckoProcessType_Default) {
+      nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+      obs->RemoveObserver(this, "file-watcher-update");
+
+      nsString fullpath;
+      mFile->GetPath(fullpath);
+      ContentChild::GetSingleton()->SendRemoveFileWatch(fullpath);
+    } else {
+      mFile->Unwatch(this);
+    }
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMDeviceStorage::RemoveSystemEventListener(const nsAString & aType,
+                                              nsIDOMEventListener *aListener,
+                                              bool aUseCapture)
+{
+  return nsDOMDeviceStorage::RemoveEventListener(aType, aListener, aUseCapture);
+}
+
+NS_IMETHODIMP
+nsDOMDeviceStorage::DispatchEvent(nsIDOMEvent *aEvt,
+                                  bool *aRetval)
+{
+  return nsDOMEventTargetHelper::DispatchEvent(aEvt, aRetval);
+}
+
+nsIDOMEventTarget *
+nsDOMDeviceStorage::GetTargetForDOMEvent()
+{
+  return nsDOMEventTargetHelper::GetTargetForDOMEvent();
+}
+
+nsIDOMEventTarget *
+nsDOMDeviceStorage::GetTargetForEventTargetChain()
+{
+  return nsDOMEventTargetHelper::GetTargetForEventTargetChain();
+}
+
+nsresult
+nsDOMDeviceStorage::PreHandleEvent(nsEventChainPreVisitor & aVisitor)
+{
+  return nsDOMEventTargetHelper::PreHandleEvent(aVisitor);
+}
+
+nsresult
+nsDOMDeviceStorage::WillHandleEvent(nsEventChainPostVisitor & aVisitor)
+{
+  return nsDOMEventTargetHelper::WillHandleEvent(aVisitor);
+}
+
+nsresult
+nsDOMDeviceStorage::PostHandleEvent(nsEventChainPostVisitor & aVisitor)
+{
+  return nsDOMEventTargetHelper::PostHandleEvent(aVisitor);
+}
+
+nsresult
+nsDOMDeviceStorage::DispatchDOMEvent(nsEvent *aEvent,
+                                     nsIDOMEvent *aDOMEvent,
+                                     nsPresContext *aPresContext,
+                                     nsEventStatus *aEventStatus)
+{
+  return nsDOMEventTargetHelper::DispatchDOMEvent(aEvent,
+                                                  aDOMEvent,
+                                                  aPresContext,
+                                                  aEventStatus);
+}
+
+nsEventListenerManager *
+nsDOMDeviceStorage::GetListenerManager(bool aMayCreate)
+{
+  return nsDOMEventTargetHelper::GetListenerManager(aMayCreate);
+}
+
+nsIScriptContext *
+nsDOMDeviceStorage::GetContextForEventHandlers(nsresult *aRv)
+{
+  return nsDOMEventTargetHelper::GetContextForEventHandlers(aRv);
+}
+
+JSContext *
+nsDOMDeviceStorage::GetJSContextForEventHandlers()
+{
+  return nsDOMEventTargetHelper::GetJSContextForEventHandlers();
+}
+
+NS_IMPL_EVENT_HANDLER(nsDOMDeviceStorage, change)
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -1,38 +1,35 @@
 /* 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 nsDeviceStorage_h
 #define nsDeviceStorage_h
 
 class nsPIDOMWindow;
-
-#include "mozilla/dom/ContentChild.h"
-#include "mozilla/dom/PBrowserChild.h"
-#include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
-
+#include "PCOMContentPermissionRequestChild.h"
 
 #include "DOMRequest.h"
-#include "PCOMContentPermissionRequestChild.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/dom/PContentPermissionRequestChild.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIClassInfo.h"
 #include "nsIContentPermissionPrompt.h"
-#include "nsIDOMDeviceStorage.h"
 #include "nsIDOMDeviceStorageCursor.h"
 #include "nsIDOMWindow.h"
 #include "nsIURI.h"
 #include "nsInterfaceHashtable.h"
 #include "nsString.h"
 #include "nsWeakPtr.h"
+#include "nsIDOMEventListener.h"
+#include "nsIDOMEventTarget.h"
+#include "nsIObserver.h"
+#include "mozilla/Mutex.h"
+#include "DeviceStorage.h"
 
 
 #define POST_ERROR_EVENT_FILE_DOES_NOT_EXIST         "File location doesn't exists"
 #define POST_ERROR_EVENT_FILE_NOT_ENUMERABLE         "File location is not enumerable"
 #define POST_ERROR_EVENT_PERMISSION_DENIED           "Permission Denied"
 #define POST_ERROR_EVENT_ILLEGAL_FILE_NAME           "Illegal file name"
 #define POST_ERROR_EVENT_UNKNOWN                     "Unknown"
 #define POST_ERROR_EVENT_NON_STRING_TYPE_UNSUPPORTED "Non-string type unsupported"
@@ -61,51 +58,16 @@ public:
   void CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRUint64 aSince = 0);
   void collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRUint64 aSince, nsAString& aRootPath);
 
 private:
   void NormalizeFilePath();
   void AppendRelativePath();
 };
 
-class nsDOMDeviceStorage MOZ_FINAL : public nsIDOMDeviceStorage
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIDOMDEVICESTORAGE
-
-  nsDOMDeviceStorage();
-
-  nsresult Init(nsPIDOMWindow* aWindow, const nsAString &aType, const PRInt32 aIndex);
-
-  PRInt32 SetRootFileForType(const nsAString& aType, const PRInt32 aIndex);
-
-  static void CreateDeviceStoragesFor(nsPIDOMWindow* aWin, const nsAString &aType, nsIVariant** _retval);
-
-private:
-  ~nsDOMDeviceStorage();
-
-  nsresult GetInternal(const JS::Value & aName, JSContext* aCx, nsIDOMDOMRequest * *_retval, bool aEditable);
-
-  nsresult EnumerateInternal(const JS::Value & aName, const JS::Value & aOptions, JSContext* aCx, PRUint8 aArgc, bool aEditable, nsIDOMDeviceStorageCursor** aRetval);
-
-  PRInt32 mStorageType;
-  nsCOMPtr<nsIFile> mFile;
-
-  nsWeakPtr mOwner;
-  nsCOMPtr<nsIURI> mURI;
-
-  // nsIDOMDeviceStorage.type
-  enum {
-      DEVICE_STORAGE_TYPE_DEFAULT = 0,
-      DEVICE_STORAGE_TYPE_SHARED,
-      DEVICE_STORAGE_TYPE_EXTERNAL,
-  };
-};
-
 class ContinueCursorEvent MOZ_FINAL: public nsRunnable
 {
 public:
   ContinueCursorEvent(nsRefPtr<DOMRequest>& aRequest);
   ContinueCursorEvent(DOMRequest* aRequest);
   ~ContinueCursorEvent();
   NS_IMETHOD Run();
 private:
--- a/dom/devicestorage/test/devicestorage_common.js
+++ b/dom/devicestorage/test/devicestorage_common.js
@@ -54,21 +54,21 @@ function getRandomBuffer() {
   return buffer;
 }
 
 function createRandomBlob() {
   return blob = new Blob([getRandomBuffer()], {type: 'binary/random'});
 }
 
 function randomFilename(l) {
-    var set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ";
-    var result = "";
-    for (var i=0; i<l; i++) {
-	var r = Math.floor(set.length * Math.random());
-	result += set.substring(r, r + 1);
-    }
-    return result;
+  var set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ";
+  var result = "";
+  for (var i=0; i<l; i++) {
+    var r = Math.floor(set.length * Math.random());
+    result += set.substring(r, r + 1);
+  }
+  return result;
 }
 
 function reportErrorAndQuit(e) {
   ok(false, "handleError was called : " + e.target.error.name);
   devicestorage_cleanup();
 }
--- a/dom/devicestorage/test/test_basic.html
+++ b/dom/devicestorage/test/test_basic.html
@@ -49,17 +49,17 @@ function getAfterDeleteError(e) {
 }
 
 function deleteSuccess(e) {
 
   ok(e.target.result == gFileName, "File name should match");
   dump(e.target.result + "\n")
 
   var storage = navigator.getDeviceStorage("testing");
-  request = storage[0].get(e.target.result);
+  request = storage.get(e.target.result);
   request.onsuccess = getAfterDeleteSuccess;
   request.onerror = getAfterDeleteError;
 
 }
 
 function deleteError(e) {
   ok(false, "deleteError was called : " + e.target.error.name);
   devicestorage_cleanup();
@@ -72,17 +72,17 @@ function getSuccess(e) {
   ok(e.target.result.name == gFileName, "File name should match");
 
   var name = e.target.result.name;
 
   gFileReader.readAsArrayBuffer(gDataBlob);
   gFileReader.onload = function(e) {
     readerCallback(e);
 
-    request = storage[0].delete(name)
+    request = storage.delete(name)
     request.onsuccess = deleteSuccess;
     request.onerror = deleteError;
   }
 }
 
 function readerCallback(e) {
 
   ab = e.target.result;
@@ -97,34 +97,34 @@ function getError(e) {
   devicestorage_cleanup();
 }
 
 function addSuccess(e) {
 
   ok(e.target.result == gFileName, "File name should match");
 
   var storage = navigator.getDeviceStorage("testing");
-  request = storage[0].get(gFileName);
+  request = storage.get(gFileName);
   request.onsuccess = getSuccess;
   request.onerror = getError;
 
   ok(true, "addSuccess was called");
 }
 
 function addError(e) {
   ok(false, "addError was called : " + e.target.error.name);
   devicestorage_cleanup();
 }
 
 ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
 
 var storage = navigator.getDeviceStorage("testing");
 ok(storage, "Should have gotten a storage");
 
-request = storage[0].addNamed(gDataBlob, "devicestorage/hi");
+request = storage.addNamed(gDataBlob, "devicestorage/hi");
 ok(request, "Should have a non-null request");
 
 request.onsuccess = addSuccess;
 request.onerror = addError;
 
 </script>
 </pre>
 </body>
--- a/dom/devicestorage/test/test_dotdot.html
+++ b/dom/devicestorage/test/test_dotdot.html
@@ -20,17 +20,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 devicestorage_setup();
 
 function testingStorage() {
-  return navigator.getDeviceStorage("testing")[0];
+  return navigator.getDeviceStorage("testing");
 }
 
 var tests = [
   function () { return testingStorage().addNamed(createRandomBlob(), gFileName); },
   function () { return testingStorage().delete(gFileName); },
   function () { return testingStorage().get(gFileName); },
   function () { var r = testingStorage().enumerate("../"); return r; }
 ];
--- a/dom/devicestorage/test/test_enumerate.html
+++ b/dom/devicestorage/test/test_enumerate.html
@@ -36,32 +36,32 @@ function enumerateSuccess(e) {
   var filename = e.target.result.name;
 
   var index = files.indexOf(filename);
   files.remove(index);
 
   ok(index > -1, "filename should be in the enumeration : " + e.target.result.name);
 
   // clean up
-  var cleanup = storage[0].delete(prefix + "/" + filename);
+  var cleanup = storage.delete(prefix + "/" + filename);
   cleanup.onsuccess = function(e) {}  // todo - can i remove this?
 
   e.target.continue();
 }
 
 function handleError(e) {
   ok(false, "handleError was called : " + e.target.error.name);
   devicestorage_cleanup();
 }
 
 function addSuccess(e) {
   addedSoFar = addedSoFar + 1;
   if (addedSoFar == files.length) {
 
-    var cursor = storage[0].enumerate(prefix);
+    var cursor = storage.enumerate(prefix);
     cursor.onsuccess = enumerateSuccess;
     cursor.onerror = handleError;
   }
 }
 
 function addError(e) {
   ok(false, "addError was called : " + e.target.error.name);
   devicestorage_cleanup();
@@ -72,17 +72,17 @@ ok(navigator.getDeviceStorage, "Should h
 var prefix = "devicestorage/" + randomFilename(12)
 
 var files = [ "a", "b", "c", "d/a", "d/b", "d/c", "d/d", "The/quick/brown/fox/jumps/over/the/lazy/dog"]
 var addedSoFar = 0;
 
 
 for (var i=0; i<files.length; i++) {
 
- request = storage[0].addNamed(createRandomBlob(), prefix + '/' + files[i]);
+ request = storage.addNamed(createRandomBlob(), prefix + '/' + files[i]);
 
  ok(request, "Should have a non-null request");
  request.onsuccess = addSuccess;
  request.onerror = addError;
 }
 
 </script>
 </pre>
--- a/dom/devicestorage/test/test_enumerateMultipleContinue.html
+++ b/dom/devicestorage/test/test_enumerateMultipleContinue.html
@@ -25,17 +25,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 devicestorage_setup();
 
 function enumerateSuccess(e) {
 }
 
 function enumerateFailure(e) {
 }
 
-var cursor = navigator.getDeviceStorage("testing")[0].enumerate();
+var cursor = navigator.getDeviceStorage("testing").enumerate();
 cursor.onsuccess = enumerateSuccess;
 cursor.onerror = enumerateFailure;
 
 try {
  cursor.continue();
 }
 catch (e) {
   ok(true, "Calling continue before enumerateSuccess fires should throw");
--- a/dom/devicestorage/test/test_enumerateNoParam.html
+++ b/dom/devicestorage/test/test_enumerateNoParam.html
@@ -40,32 +40,32 @@ function enumerateSuccess(e) {
   
   var filename = e.target.result.name;
   var index = files.indexOf(filename);
   files.remove(index);
 
   ok(index > -1, "filename should be in the enumeration : " + e.target.result.name);
 
   // clean up
-  var cleanup = storage[0].delete(prefix + "/" + filename);
+  var cleanup = storage.delete(prefix + "/" + filename);
   cleanup.onsuccess = function(e) {}  // todo - can i remove this?
 
   e.target.continue();
 }
 
 function handleError(e) {
   ok(false, "handleError was called : " + e.target.error.name);
   devicestorage_cleanup();
 }
 
 function addSuccess(e) {
   addedSoFar = addedSoFar + 1;
   if (addedSoFar == files.length) {
 
-    var cursor = storage[0].enumerate();
+    var cursor = storage.enumerate();
     cursor.onsuccess = enumerateSuccess;
     cursor.onerror = handleError;
   }
 }
 
 function addError(e) {
   ok(false, "addError was called : " + e.target.error.name);
   devicestorage_cleanup();
@@ -76,17 +76,17 @@ ok(navigator.getDeviceStorage, "Should h
 var prefix = "devicestorage/" + randomFilename(12)
 
 var files = [ "a", "b", "c" ]
 var addedSoFar = 0;
 
 
 for (var i=0; i<files.length; i++) {
 
- request = storage[0].addNamed(createRandomBlob(), prefix + '/' + files[i]);
+ request = storage.addNamed(createRandomBlob(), prefix + '/' + files[i]);
 
  ok(request, "Should have a non-null request");
  request.onsuccess = addSuccess;
  request.onerror = addError;
 }
 
 </script>
 </pre>
--- a/dom/devicestorage/test/test_enumerateOptions.html
+++ b/dom/devicestorage/test/test_enumerateOptions.html
@@ -25,53 +25,53 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 devicestorage_setup()
 
 storage = navigator.getDeviceStorage("testing");
 
 
 throws = false;
 try {
-var cursor = storage[0].enumerate();
+var cursor = storage.enumerate();
 } catch(e) {throws = true}
 ok(!throws, "enumerate no parameter");
 
 throws = false;
 try {
-var cursor = storage[0].enumerate("string");
+var cursor = storage.enumerate("string");
 } catch(e) {throws = true}
 ok(!throws, "enumerate one string parameter");
 
 throws = false;
 try {
-var cursor = storage[0].enumerate("string", "string2");
+var cursor = storage.enumerate("string", "string2");
 } catch(e) {throws = true}
 ok(throws, "enumerate two string parameter");
 
 throws = false;
 try {
-var cursor = storage[0].enumerate("string", {"since": 1});
+var cursor = storage.enumerate("string", {"since": 1});
 } catch(e) {throws = true}
 ok(!throws, "enumerate a string and object parameter");
 
 throws = false;
 try {
-var cursor = storage[0].enumerate({"path": "a"});
+var cursor = storage.enumerate({"path": "a"});
 } catch(e) {throws = true}
 ok(!throws, "enumerate object parameter with path");
 
 throws = false;
 try {
-var cursor = storage[0].enumerate({}, "string");
+var cursor = storage.enumerate({}, "string");
 } catch(e) {throws = true}
 ok(throws, "enumerate object then a string");
 
 throws = false;
 try {
-var cursor = storage[0].enumerate({"path": "a", "since": 0});
+var cursor = storage.enumerate({"path": "a", "since": 0});
 } catch(e) {throws = true}
 ok(!throws, "enumerate object parameter with path");
 
 
 
 
 devicestorage_cleanup()
 </script>
--- a/dom/devicestorage/test/test_lastModificationFilter.html
+++ b/dom/devicestorage/test/test_lastModificationFilter.html
@@ -40,17 +40,17 @@ function verifyAndDelete(prefix, files, 
   ok(index > -1, "filename should be in the enumeration : " + e.target.result.name);
   if (index == -1)
     return;
 
   files.remove(index);
 
   // clean up
   var storage = navigator.getDeviceStorage("testing");
-  var cleanup = storage[0].delete(prefix + "/" + filename);
+  var cleanup = storage.delete(prefix + "/" + filename);
   cleanup.onsuccess = function(e) {}
 }
 
 function addFiles(prefix, files, date, callback) {
 
   const Cc = SpecialPowers.wrap(Components).classes;
   const Ci = Components.interfaces;
 
@@ -83,17 +83,17 @@ var newFiles = ["d", "e", "f"];
 addFiles(prefix, oldFiles, 157795200, addNewFiles);
 
 function enumerateNew() {
 
   var storage = navigator.getDeviceStorage("testing");
   ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
 
 // 836031600 is a long time ago
-  var cursor = storage[0].enumerate(prefix, {"since": new Date(836031600)});
+  var cursor = storage.enumerate(prefix, {"since": new Date(836031600)});
   cursor.onsuccess = function(e) {
     verifyAndDelete(prefix, newFiles, e);
     if (e.target.result) {
       e.target.continue();
     }
   }
 
   cursor.onerror = function (e) {
--- a/dom/devicestorage/test/test_overwrite.html
+++ b/dom/devicestorage/test/test_overwrite.html
@@ -41,46 +41,46 @@ function addOverwritingSuccess(e) {
   ok(false, "addOverwritingSuccess was called.");
   devicestorage_cleanup();
 }
 
 function addOverwritingError(e) {
   ok(true, "Adding to the same location should fail");
 
   var storage = navigator.getDeviceStorage("testing");
-  request = storage[0].delete(filename)
+  request = storage.delete(filename)
   request.onsuccess = deleteSuccess;
   request.onerror = deleteError;
 }
 
 function addSuccess(e) {
   ok(true, "addSuccess was called");
 
   var storage = navigator.getDeviceStorage("testing");
   ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
 
-  request = storage[0].addNamed(createRandomBlob(), filename);
+  request = storage.addNamed(createRandomBlob(), filename);
   ok(request, "Should have a non-null request");
 
   request.onsuccess = addOverwritingSuccess;
   request.onerror = addOverwritingError;
 }
 
 function addError(e) {
   // test file is already exists.  clean it up and try again..
   var storage = navigator.getDeviceStorage("testing");
-  request = storage[0].delete(filename)
+  request = storage.delete(filename)
   request.onsuccess = runtest;
 }
 
 function runtest() {
   var storage = navigator.getDeviceStorage("testing");
   ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
 
-  request = storage[0].addNamed(createRandomBlob(), filename);
+  request = storage.addNamed(createRandomBlob(), filename);
   ok(request, "Should have a non-null request");
 
   request.onsuccess = addSuccess;
   request.onerror = addError;
 }
 
 runtest();
 
--- a/dom/devicestorage/test/test_sanity.html
+++ b/dom/devicestorage/test/test_sanity.html
@@ -36,17 +36,17 @@ try {
 ok(throws, "getDeviceStorage takes one arg");
 
 storage = navigator.getDeviceStorage("kilimanjaro");
 ok(!storage, "kilimanjaro - Should not have this type of storage");
 
 storage = navigator.getDeviceStorage("testing");
 ok(storage, "testing - Should have getDeviceStorage");
 
-var cursor = storage[0].enumerate();
+var cursor = storage.enumerate();
 ok(cursor, "Should have a non-null cursor");
 
 devicestorage_cleanup();
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/file/LockedFile.cpp
+++ b/dom/file/LockedFile.cpp
@@ -511,20 +511,19 @@ NS_IMETHODIMP
 LockedFile::GetLocation(JSContext* aCx,
                         jsval* aLocation)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (mLocation == LL_MAXUINT) {
     *aLocation = JSVAL_NULL;
   }
-  else if (!JS_NewNumberValue(aCx, double(mLocation), aLocation)) {
-    return NS_ERROR_FAILURE;
+  else {
+    *aLocation = JS_NumberValue(double(mLocation));
   }
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LockedFile::SetLocation(JSContext* aCx,
                         const jsval& aLocation)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
--- a/dom/file/MetadataHelper.cpp
+++ b/dom/file/MetadataHelper.cpp
@@ -27,27 +27,17 @@ MetadataHelper::DoAsyncRun(nsISupports* 
 nsresult
 MetadataHelper::GetSuccessResult(JSContext* aCx,
                                  jsval* aVal)
 {
   JSObject* obj = JS_NewObject(aCx, nullptr, nullptr, nullptr);
   NS_ENSURE_TRUE(obj, NS_ERROR_OUT_OF_MEMORY);
 
   if (mParams->SizeRequested()) {
-    jsval val;
-
-    if (mParams->Size() <= JSVAL_INT_MAX) {
-      val = INT_TO_JSVAL(mParams->Size());
-    }
-    else {
-      double size = mParams->Size();
-      if (!JS_NewNumberValue(aCx, size, &val)) {
-        return NS_ERROR_FAILURE;
-      }
-    }
+    jsval val = JS_NumberValue(mParams->Size());
 
     if (!JS_DefineProperty(aCx, obj, "size", val, nullptr, nullptr,
                            JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   if (mParams->LastModifiedRequested()) {
--- a/dom/file/test/Makefile.in
+++ b/dom/file/test/Makefile.in
@@ -7,27 +7,29 @@ topsrcdir        = @top_srcdir@
 srcdir           = @srcdir@
 VPATH            = @srcdir@
 relativesrcdir   = dom/file/test
 
 include $(DEPTH)/config/autoconf.mk
 
 
 MOCHITEST_FILES = \
+  dummy_worker.js \
   helpers.js \
   test_append_read_data.html \
   test_getFileId.html \
   test_location.html \
   test_lockedfile_lifetimes.html \
   test_lockedfile_lifetimes_nested.html \
   test_lockedfile_ordering.html \
   test_overlapping_lockedfiles.html \
   test_progress_events.html \
   test_readonly_lockedfiles.html \
   test_request_readyState.html \
   test_stream_tracking.html \
   test_success_events_after_abort.html \
   test_truncate.html \
   test_write_read_data.html \
+  test_workers.html \
   test_archivereader.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/file/test/dummy_worker.js
@@ -0,0 +1,8 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+onmessage = function(event) {
+  throw("Shouldn't be called!");
+}
new file mode 100644
--- /dev/null
+++ b/dom/file/test/test_workers.html
@@ -0,0 +1,61 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>File Handle Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+  <script type="text/javascript;version=1.7">
+  function testSteps()
+  {
+    var testBuffer = getRandomBuffer(100000);
+
+    for each (let fileStorage in fileStorages) {
+      let request = getFileHandle(fileStorage.key, "test.txt");
+      request.onerror = errorHandler;
+      request.onsuccess = grabEventAndContinueHandler;
+      let event = yield;
+
+      let fileHandle = event.target.result;
+      fileHandle.onerror = errorHandler;
+
+      let lockedFile = fileHandle.open("readwrite");
+
+      request = lockedFile.write(testBuffer);
+      request.onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      request = fileHandle.getFile();
+      request.onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      let file = event.target.result;
+
+      var worker = new Worker("dummy_worker.js");
+      try {
+        worker.postMessage(file);
+        ok(false, "Should have thrown!");
+      }
+      catch (e) {
+        ok(e instanceof DOMException, "Got exception.");
+        is(e.name, "DataCloneError", "Good error.");
+        is(e.code, DOMException.DATA_CLONE_ERR, "Good error code.")
+      }
+      worker.terminate();
+    }
+
+    finishTest();
+    yield;
+  }
+  </script>
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+
+</head>
+
+<body onload="runTest();"></body>
+
+</html>
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -744,17 +744,17 @@ IDBCursor::Advance(PRInt64 aCount)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (aCount < 1 || aCount > PR_UINT32_MAX) {
     return NS_ERROR_TYPE_ERR;
   }
 
   Key key;
-  return ContinueInternal(key, aCount);
+  return ContinueInternal(key, PRInt32(aCount));
 }
 
 void
 CursorHelper::ReleaseMainThreadObjects()
 {
   mCursor = nullptr;
   AsyncConnectionHelper::ReleaseMainThreadObjects();
 }
@@ -871,30 +871,48 @@ ContinueHelper::MaybeSendResponseToChild
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   if (!actor) {
     return Success_NotSent;
   }
 
-  if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
-    NS_WARNING("No support for transferring blobs across processes yet!");
-    return Error;
+  InfallibleTArray<PBlobParent*> blobsParent;
+
+  if (NS_SUCCEEDED(aResultCode)) {
+    IDBDatabase* database = mTransaction->Database();
+    NS_ASSERTION(database, "This should never be null!");
+
+    ContentParent* contentParent = database->GetContentParent();
+    NS_ASSERTION(contentParent, "This should never be null!");
+
+    FileManager* fileManager = database->Manager();
+    NS_ASSERTION(fileManager, "This should never be null!");
+
+    const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
+
+    aResultCode =
+      IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
+                                           blobsParent);
+    if (NS_FAILED(aResultCode)) {
+      NS_WARNING("ConvertBlobsToActors failed!");
+    }
   }
 
   ResponseValue response;
   if (NS_FAILED(aResultCode)) {
     response = aResultCode;
   }
   else {
     ContinueResponse continueResponse;
     continueResponse.key() = mKey;
     continueResponse.objectKey() = mObjectKey;
     continueResponse.cloneInfo() = mCloneReadInfo;
+    continueResponse.blobsParent().SwapElements(blobsParent);
     response = continueResponse;
   }
 
   if (!actor->Send__delete__(actor, response)) {
     return Error;
   }
 
   UpdateCursorState();
@@ -920,16 +938,18 @@ ContinueHelper::UnpackResponseFromParent
                (cloneInfo.dataLength && cloneInfo.data),
                "Inconsistent clone info!");
 
   if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
     NS_WARNING("Failed to copy clone buffer!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
+  IDBObjectStore::ConvertActorsToBlobs(response.blobsChild(),
+                                       mCloneReadInfo.mFiles);
   return NS_OK;
 }
 
 nsresult
 ContinueObjectStoreHelper::BindArgumentsToStatement(
                                                mozIStorageStatement* aStatement)
 {
   // Bind object store id.
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "IDBDatabase.h"
 
 #include "mozilla/Mutex.h"
 #include "mozilla/storage.h"
+#include "mozilla/dom/ContentParent.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMLists.h"
 #include "nsJSUtils.h"
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
 
 #include "AsyncConnectionHelper.h"
 #include "CheckQuotaHelper.h"
@@ -28,16 +29,17 @@
 #include "IndexedDatabaseManager.h"
 #include "TransactionThreadPool.h"
 #include "DictionaryHelpers.h"
 #include "nsContentUtils.h"
 
 #include "ipc/IndexedDBChild.h"
 
 USING_INDEXEDDB_NAMESPACE
+using mozilla::dom::ContentParent;
 
 namespace {
 
 class NoRequestDatabaseHelper : public AsyncConnectionHelper
 {
 public:
   NoRequestDatabaseHelper(IDBTransaction* aTransaction)
   : AsyncConnectionHelper(aTransaction, nullptr)
@@ -165,17 +167,18 @@ private:
 
 } // anonymous namespace
 
 // static
 already_AddRefed<IDBDatabase>
 IDBDatabase::Create(IDBWrapperCache* aOwnerCache,
                     already_AddRefed<DatabaseInfo> aDatabaseInfo,
                     const nsACString& aASCIIOrigin,
-                    FileManager* aFileManager)
+                    FileManager* aFileManager,
+                    mozilla::dom::ContentParent* aContentParent)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
 
   nsRefPtr<DatabaseInfo> databaseInfo(aDatabaseInfo);
   NS_ASSERTION(databaseInfo, "Null pointer!");
 
   nsRefPtr<IDBDatabase> db(new IDBDatabase());
@@ -186,32 +189,34 @@ IDBDatabase::Create(IDBWrapperCache* aOw
   }
 
   db->mDatabaseId = databaseInfo->id;
   db->mName = databaseInfo->name;
   db->mFilePath = databaseInfo->filePath;
   databaseInfo.swap(db->mDatabaseInfo);
   db->mASCIIOrigin = aASCIIOrigin;
   db->mFileManager = aFileManager;
+  db->mContentParent = aContentParent;
 
   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   NS_ASSERTION(mgr, "This should never be null!");
 
   if (!mgr->RegisterDatabase(db)) {
     // Either out of memory or shutting down.
     return nullptr;
   }
 
   return db.forget();
 }
 
 IDBDatabase::IDBDatabase()
 : mDatabaseId(0),
   mActorChild(nullptr),
   mActorParent(nullptr),
+  mContentParent(nullptr),
   mInvalidated(0),
   mRegistered(false),
   mClosed(false),
   mRunningVersionChange(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -14,16 +14,22 @@
 #include "nsIIDBDatabase.h"
 #include "nsDOMEventTargetHelper.h"
 #include "mozilla/dom/indexedDB/IDBWrapperCache.h"
 #include "mozilla/dom/indexedDB/FileManager.h"
 
 class nsIScriptContext;
 class nsPIDOMWindow;
 
+namespace mozilla {
+namespace dom {
+class ContentParent;
+}
+}
+
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
 struct DatabaseInfo;
 class IDBIndex;
 class IDBObjectStore;
 class IDBTransaction;
 class IndexedDatabaseManager;
@@ -45,17 +51,18 @@ public:
   NS_DECL_NSIFILESTORAGE
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBDatabase, IDBWrapperCache)
 
   static already_AddRefed<IDBDatabase>
   Create(IDBWrapperCache* aOwnerCache,
          already_AddRefed<DatabaseInfo> aDatabaseInfo,
          const nsACString& aASCIIOrigin,
-         FileManager* aFileManager);
+         FileManager* aFileManager,
+         mozilla::dom::ContentParent* aContentParent);
 
   // nsIDOMEventTarget
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
 
   nsIAtom* Id() const
   {
     return mDatabaseId;
   }
@@ -130,16 +137,22 @@ public:
   }
 
   IndexedDBDatabaseChild*
   GetActorChild() const
   {
     return mActorChild;
   }
 
+  mozilla::dom::ContentParent*
+  GetContentParent() const
+  {
+    return mContentParent;
+  }
+
   nsresult
   CreateObjectStoreInternal(IDBTransaction* aTransaction,
                             const ObjectStoreInfoGuts& aInfo,
                             IDBObjectStore** _retval);
 
 private:
   IDBDatabase();
   ~IDBDatabase();
@@ -160,16 +173,18 @@ private:
   // Only touched on the main thread.
   NS_DECL_EVENT_HANDLER(abort)
   NS_DECL_EVENT_HANDLER(error)
   NS_DECL_EVENT_HANDLER(versionchange)
 
   IndexedDBDatabaseChild* mActorChild;
   IndexedDBDatabaseParent* mActorParent;
 
+  mozilla::dom::ContentParent* mContentParent;
+
   PRInt32 mInvalidated;
   bool mRegistered;
   bool mClosed;
   bool mRunningVersionChange;
 };
 
 END_INDEXEDDB_NAMESPACE
 
--- a/dom/indexedDB/IDBEvents.cpp
+++ b/dom/indexedDB/IDBEvents.cpp
@@ -114,14 +114,14 @@ NS_IMETHODIMP
 IDBVersionChangeEvent::GetNewVersion(JSContext* aCx,
                                      JS::Value* aNewVersion)
 {
   NS_ENSURE_ARG_POINTER(aNewVersion);
 
   if (!mNewVersion) {
     *aNewVersion = JSVAL_NULL;
   }
-  else if (!JS_NewNumberValue(aCx, double(mNewVersion), aNewVersion)) {
-    return NS_ERROR_FAILURE;
+  else {
+    *aNewVersion = JS_NumberValue(double(mNewVersion));
   }
 
   return NS_OK;
 }
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -2,25 +2,25 @@
 /* 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 "base/basictypes.h"
 
 #include "IDBFactory.h"
-
 #include "nsIFile.h"
 #include "nsIJSContextStack.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsIXPConnect.h"
 #include "nsIXPCScriptable.h"
 
 #include "jsdbgapi.h"
+#include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/storage.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsContentUtils.h"
@@ -41,16 +41,17 @@
 #include "IndexedDatabaseManager.h"
 #include "Key.h"
 
 #include "ipc/IndexedDBChild.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 using mozilla::dom::ContentChild;
+using mozilla::dom::ContentParent;
 using mozilla::dom::TabChild;
 
 namespace {
 
 struct ObjectStoreInfoMap
 {
   ObjectStoreInfoMap()
   : id(LL_MININT), info(nullptr) { }
@@ -58,17 +59,17 @@ struct ObjectStoreInfoMap
   PRInt64 id;
   ObjectStoreInfo* info;
 };
 
 } // anonymous namespace
 
 IDBFactory::IDBFactory()
 : mOwningObject(nullptr), mActorChild(nullptr), mActorParent(nullptr),
-  mRootedOwningObject(false)
+  mContentParent(nullptr), mRootedOwningObject(false)
 {
 }
 
 IDBFactory::~IDBFactory()
 {
   NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
   if (mActorChild) {
     NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
@@ -79,16 +80,17 @@ IDBFactory::~IDBFactory()
     NS_DROP_JS_OBJECTS(this, IDBFactory);
   }
 }
 
 // static
 nsresult
 IDBFactory::Create(nsPIDOMWindow* aWindow,
                    const nsACString& aASCIIOrigin,
+                   ContentParent* aContentParent,
                    IDBFactory** aFactory)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aASCIIOrigin.IsEmpty() || nsContentUtils::IsCallerChrome(),
                "Non-chrome may not supply their own origin!");
 
   NS_ENSURE_TRUE(aWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
@@ -113,16 +115,17 @@ IDBFactory::Create(nsPIDOMWindow* aWindo
       *aFactory = nullptr;
       return NS_OK;
     }
   }
 
   nsRefPtr<IDBFactory> factory = new IDBFactory();
   factory->mASCIIOrigin = origin;
   factory->mWindow = aWindow;
+  factory->mContentParent = aContentParent;
 
   if (!IndexedDatabaseManager::IsMainProcess()) {
     TabChild* tabChild = GetTabChildFrom(aWindow);
     NS_ENSURE_TRUE(tabChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     IndexedDBChild* actor = new IndexedDBChild(origin);
 
     bool allowed;
@@ -140,16 +143,17 @@ IDBFactory::Create(nsPIDOMWindow* aWindo
   factory.forget(aFactory);
   return NS_OK;
 }
 
 // static
 nsresult
 IDBFactory::Create(JSContext* aCx,
                    JSObject* aOwningObject,
+                   ContentParent* aContentParent,
                    IDBFactory** aFactory)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aOwningObject, "Null object!");
   NS_ASSERTION(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
                "Not a global object!");
   NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
@@ -157,16 +161,17 @@ IDBFactory::Create(JSContext* aCx,
   nsCString origin;
   nsresult rv =
     IndexedDatabaseManager::GetASCIIOriginFromWindow(nullptr, origin);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<IDBFactory> factory = new IDBFactory();
   factory->mASCIIOrigin = origin;
   factory->mOwningObject = aOwningObject;
+  factory->mContentParent = aContentParent;
 
   if (!IndexedDatabaseManager::IsMainProcess()) {
     ContentChild* contentChild = ContentChild::GetSingleton();
     NS_ENSURE_TRUE(contentChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     IndexedDBChild* actor = new IndexedDBChild(origin);
 
     contentChild->SendPIndexedDBConstructor(actor);
@@ -175,21 +180,23 @@ IDBFactory::Create(JSContext* aCx,
   }
 
   factory.forget(aFactory);
   return NS_OK;
 }
 
 // static
 nsresult
-IDBFactory::Create(IDBFactory** aFactory)
+IDBFactory::Create(ContentParent* aContentParent,
+                   IDBFactory** aFactory)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
+  NS_ASSERTION(aContentParent, "Null ContentParent!");
 
 #ifdef DEBUG
   {
     nsIThreadJSContextStack* cxStack = nsContentUtils::ThreadJSContextStack();
     NS_ASSERTION(cxStack, "Couldn't get ThreadJSContextStack!");
 
     JSContext* lastCx;
     if (NS_SUCCEEDED(cxStack->Peek(&lastCx))) {
@@ -238,17 +245,17 @@ IDBFactory::Create(IDBFactory** aFactory
 
   JSAutoEnterCompartment ac;
   if (!ac.enter(cx, global)) {
     NS_WARNING("Failed to enter compartment!");
     return NS_ERROR_FAILURE;
   }
 
   nsRefPtr<IDBFactory> factory;
-  rv = Create(cx, global, getter_AddRefs(factory));
+  rv = Create(cx, global, aContentParent, getter_AddRefs(factory));
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_HOLD_JS_OBJECTS(factory, IDBFactory);
   factory->mRootedOwningObject = true;
 
   factory.forget(aFactory);
   return NS_OK;
 }
@@ -505,35 +512,39 @@ IDBFactory::OpenCommon(const nsAString& 
                        JSContext* aCallingCx,
                        IDBOpenDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mWindow || mOwningObject, "Must have one of these!");
 
   nsCOMPtr<nsPIDOMWindow> window;
   JSObject* scriptOwner = nullptr;
+  FactoryPrivilege privilege;
 
   if (mWindow) {
     window = mWindow;
     scriptOwner =
       static_cast<nsGlobalWindow*>(window.get())->FastGetGlobalJSObject();
+    privilege = Content;
   }
   else {
     scriptOwner = mOwningObject;
+    privilege = Chrome;
   }
 
   nsRefPtr<IDBOpenDBRequest> request =
     IDBOpenDBRequest::Create(window, scriptOwner, aCallingCx);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsresult rv;
 
   if (IndexedDatabaseManager::IsMainProcess()) {
     nsRefPtr<OpenDatabaseHelper> openHelper =
-      new OpenDatabaseHelper(request, aName, mASCIIOrigin, aVersion, aDeleting);
+      new OpenDatabaseHelper(request, aName, mASCIIOrigin, aVersion, aDeleting,
+                             mContentParent, privilege);
 
     rv = openHelper->Init();
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     nsRefPtr<CheckPermissionsHelper> permissionHelper =
       new CheckPermissionsHelper(openHelper, window, aDeleting);
 
     IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -12,61 +12,73 @@
 #include "mozIStorageConnection.h"
 #include "nsIIDBFactory.h"
 
 #include "nsCycleCollectionParticipant.h"
 
 class nsIAtom;
 class nsPIDOMWindow;
 
+namespace mozilla {
+namespace dom {
+class ContentParent;
+}
+}
+
 BEGIN_INDEXEDDB_NAMESPACE
 
 struct DatabaseInfo;
 class IDBDatabase;
 class IDBOpenDBRequest;
 class IndexedDBChild;
 class IndexedDBParent;
 
 struct ObjectStoreInfo;
 
 class IDBFactory MOZ_FINAL : public nsIIDBFactory
 {
+  typedef mozilla::dom::ContentParent ContentParent;
   typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBFactory)
   NS_DECL_NSIIDBFACTORY
 
   // Called when using IndexedDB from a window in a different process.
   static nsresult Create(nsPIDOMWindow* aWindow,
                          const nsACString& aASCIIOrigin,
+                         ContentParent* aContentParent,
                          IDBFactory** aFactory);
 
   // Called when using IndexedDB from a window in the current process.
   static nsresult Create(nsPIDOMWindow* aWindow,
+                         ContentParent* aContentParent,
                          nsIIDBFactory** aFactory)
   {
     nsRefPtr<IDBFactory> factory;
-    nsresult rv = Create(aWindow, EmptyCString(), getter_AddRefs(factory));
+    nsresult rv =
+      Create(aWindow, EmptyCString(), aContentParent, getter_AddRefs(factory));
     NS_ENSURE_SUCCESS(rv, rv);
 
     factory.forget(aFactory);
     return NS_OK;
   }
 
   // Called when using IndexedDB from a JS component or a JSM in the current
   // process.
   static nsresult Create(JSContext* aCx,
                          JSObject* aOwningObject,
+                         ContentParent* aContentParent,
                          IDBFactory** aFactory);
 
   // Called when using IndexedDB from a JS component or a JSM in a different
   // process.
-  static nsresult Create(IDBFactory** aFactory);
+  static nsresult Create(ContentParent* aContentParent,
+                         IDBFactory** aFactory);
 
   static already_AddRefed<mozIStorageConnection>
   GetConnection(const nsAString& aDatabaseFilePath);
 
   static nsresult
   LoadDatabaseInformation(mozIStorageConnection* aConnection,
                           nsIAtom* aDatabaseId,
                           PRUint64* aVersion,
@@ -113,14 +125,16 @@ private:
   // If this factory lives on a window then mWindow must be non-null. Otherwise
   // mOwningObject must be non-null.
   nsCOMPtr<nsPIDOMWindow> mWindow;
   JSObject* mOwningObject;
 
   IndexedDBChild* mActorChild;
   IndexedDBParent* mActorParent;
 
+  mozilla::dom::ContentParent* mContentParent;
+
   bool mRootedOwningObject;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbfactory_h__
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -6,16 +6,19 @@
 
 #include "base/basictypes.h"
 
 #include "IDBIndex.h"
 
 #include "nsIIDBKeyRange.h"
 #include "nsIJSContextStack.h"
 
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/ipc/Blob.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsEventDispatcher.h"
 #include "nsThreadUtils.h"
 #include "mozilla/storage.h"
 #include "xpcpublic.h"
 
 #include "AsyncConnectionHelper.h"
@@ -27,16 +30,17 @@
 #include "DatabaseInfo.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 #include "IndexedDatabaseInlines.h"
 
 USING_INDEXEDDB_NAMESPACE
+using namespace mozilla::dom;
 using namespace mozilla::dom::indexedDB::ipc;
 
 namespace {
 
 class IndexHelper : public AsyncConnectionHelper
 {
 public:
   IndexHelper(IDBTransaction* aTransaction,
@@ -629,16 +633,17 @@ IDBIndex::OpenCursorFromChildProcess(IDB
 
 nsresult
 IDBIndex::OpenCursorFromChildProcess(
                             IDBRequest* aRequest,
                             size_t aDirection,
                             const Key& aKey,
                             const Key& aObjectKey,
                             const SerializedStructuredCloneReadInfo& aCloneInfo,
+                            nsTArray<StructuredCloneFile>& aBlobs,
                             IDBCursor** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION((!aCloneInfo.dataLength && !aCloneInfo.data) ||
                (aCloneInfo.dataLength && aCloneInfo.data),
                "Inconsistent clone info!");
 
   IDBCursor::Direction direction =
@@ -646,16 +651,18 @@ IDBIndex::OpenCursorFromChildProcess(
 
   StructuredCloneReadInfo cloneInfo;
 
   if (!cloneInfo.SetFromSerialized(aCloneInfo)) {
     NS_WARNING("Failed to copy clone buffer!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
+  cloneInfo.mFiles.SwapElements(aBlobs);
+
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(aRequest, mObjectStore->Transaction(), this, direction,
                       Key(), EmptyCString(), EmptyCString(), aKey, aObjectKey,
                       cloneInfo);
   NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!cloneInfo.mCloneBuffer.data(), "Should have swapped!");
 
@@ -1231,57 +1238,76 @@ GetHelper::MaybeSendResponseToChildProce
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   if (!actor) {
     return Success_NotSent;
   }
 
-  if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
-    NS_WARNING("No support for transferring blobs across processes yet!");
-    return Error;
+  InfallibleTArray<PBlobParent*> blobsParent;
+
+  if (NS_SUCCEEDED(aResultCode)) {
+    IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
+    NS_ASSERTION(database, "This should never be null!");
+
+    ContentParent* contentParent = database->GetContentParent();
+    NS_ASSERTION(contentParent, "This should never be null!");
+
+    FileManager* fileManager = database->Manager();
+    NS_ASSERTION(fileManager, "This should never be null!");
+
+    const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
+
+    aResultCode =
+      IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
+                                           blobsParent);
+    if (NS_FAILED(aResultCode)) {
+      NS_WARNING("ConvertBlobActors failed!");
+    }
   }
 
   ResponseValue response;
   if (NS_FAILED(aResultCode)) {
     response = aResultCode;
   }
   else {
-    SerializedStructuredCloneReadInfo readInfo;
-    readInfo = mCloneReadInfo;
-    GetResponse getResponse = readInfo;
+    GetResponse getResponse;
+    getResponse.cloneInfo() = mCloneReadInfo;
+    getResponse.blobsParent().SwapElements(blobsParent);
     response = getResponse;
   }
 
   if (!actor->Send__delete__(actor, response)) {
     return Error;
   }
 
   return Success_Sent;
 }
 
 nsresult
 GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
 {
   NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetResponse,
                "Bad response type!");
 
-  const SerializedStructuredCloneReadInfo& cloneInfo =
-    aResponseValue.get_GetResponse().cloneInfo();
+  const GetResponse& getResponse = aResponseValue.get_GetResponse();
+  const SerializedStructuredCloneReadInfo& cloneInfo = getResponse.cloneInfo();
 
   NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
                (cloneInfo.dataLength && cloneInfo.data),
                "Inconsistent clone info!");
 
   if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
     NS_WARNING("Failed to copy clone buffer!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
+  IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(),
+                                       mCloneReadInfo.mFiles);
   return NS_OK;
 }
 
 nsresult
 GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
   nsCString tableName;
   if (mIndex->IsUnique()) {
@@ -1562,40 +1588,68 @@ GetAllHelper::MaybeSendResponseToChildPr
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   if (!actor) {
     return Success_NotSent;
   }
 
-  for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
-    if (!mCloneReadInfos[index].mFileInfos.IsEmpty()) {
-      NS_WARNING("No support for transferring blobs across processes yet!");
-      return Error;
+  GetAllResponse getAllResponse;
+
+  if (NS_SUCCEEDED(aResultCode) && !mCloneReadInfos.IsEmpty()) {
+    IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
+    NS_ASSERTION(database, "This should never be null!");
+
+    ContentParent* contentParent = database->GetContentParent();
+    NS_ASSERTION(contentParent, "This should never be null!");
+
+    FileManager* fileManager = database->Manager();
+    NS_ASSERTION(fileManager, "This should never be null!");
+
+    PRUint32 length = mCloneReadInfos.Length();
+
+    InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
+      getAllResponse.cloneInfos();
+    infos.SetCapacity(length);
+
+    InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
+    blobArrays.SetCapacity(length);
+
+    for (PRUint32 index = 0;
+         NS_SUCCEEDED(aResultCode) && index < length;
+         index++) {
+      const StructuredCloneReadInfo& clone = mCloneReadInfos[index];
+
+      // Append the structured clone data.
+      SerializedStructuredCloneReadInfo* info = infos.AppendElement();
+      *info = clone;
+
+      const nsTArray<StructuredCloneFile>& files = clone.mFiles;
+
+      // Now take care of the files.
+      BlobArray* blobArray = blobArrays.AppendElement();
+
+      InfallibleTArray<PBlobParent*>& blobs = blobArray->blobsParent();
+
+      aResultCode =
+        IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
+                                             blobs);
+      if (NS_FAILED(aResultCode)) {
+        NS_WARNING("ConvertBlobsToActors failed!");
+        break;
+      }
     }
   }
 
   ResponseValue response;
   if (NS_FAILED(aResultCode)) {
     response = aResultCode;
   }
   else {
-    GetAllResponse getAllResponse;
-
-    InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
-      getAllResponse.cloneInfos();
-
-    infos.SetCapacity(mCloneReadInfos.Length());
-
-    for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
-      SerializedStructuredCloneReadInfo* info = infos.AppendElement();
-      *info = mCloneReadInfos[index];
-    }
-
     response = getAllResponse;
   }
 
   if (!actor->Send__delete__(actor, response)) {
     return Error;
   }
 
   return Success_Sent;
@@ -1603,29 +1657,34 @@ GetAllHelper::MaybeSendResponseToChildPr
 
 nsresult
 GetAllHelper::UnpackResponseFromParentProcess(
                                             const ResponseValue& aResponseValue)
 {
   NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllResponse,
                "Bad response type!");
 
+  const GetAllResponse& getAllResponse = aResponseValue.get_GetAllResponse();
   const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
-    aResponseValue.get_GetAllResponse().cloneInfos();
+    getAllResponse.cloneInfos();
+  const InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
 
   mCloneReadInfos.SetCapacity(cloneInfos.Length());
 
   for (PRUint32 index = 0; index < cloneInfos.Length(); index++) {
     const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
+    const InfallibleTArray<PBlobChild*> blobs = blobArrays[index].blobsChild();
 
     StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
     if (!destInfo->SetFromSerialized(srcInfo)) {
       NS_WARNING("Failed to copy clone buffer!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
+
+    IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles);
   }
 
   return NS_OK;
 }
 
 nsresult
 OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
@@ -2194,23 +2253,40 @@ OpenCursorHelper::MaybeSendResponseToChi
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   if (!actor) {
     return Success_NotSent;
   }
 
-  if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
-    NS_WARNING("No support for transferring blobs across processes yet!");
-    return Error;
+  NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
+
+  InfallibleTArray<PBlobParent*> blobsParent;
+
+  if (NS_SUCCEEDED(aResultCode)) {
+    IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
+    NS_ASSERTION(database, "This should never be null!");
+
+    ContentParent* contentParent = database->GetContentParent();
+    NS_ASSERTION(contentParent, "This should never be null!");
+
+    FileManager* fileManager = database->Manager();
+    NS_ASSERTION(fileManager, "This should never be null!");
+
+    const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
+
+    aResultCode =
+      IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
+                                           blobsParent);
+    if (NS_FAILED(aResultCode)) {
+      NS_WARNING("ConvertBlobsToActors failed!");
+    }
   }
 
-  NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
-
   if (NS_SUCCEEDED(aResultCode)) {
     nsresult rv = EnsureCursor();
     if (NS_FAILED(rv)) {
       NS_WARNING("EnsureCursor failed!");
       aResultCode = rv;
     }
   }
 
@@ -2236,16 +2312,17 @@ OpenCursorHelper::MaybeSendResponseToChi
                    "Shouldn't be possible!");
 
       IndexCursorConstructorParams params;
       params.requestParent() = requestActor;
       params.direction() = mDirection;
       params.key() = mKey;
       params.objectKey() = mObjectKey;
       params.optionalCloneInfo() = mSerializedCloneReadInfo;
+      params.blobsParent().SwapElements(blobsParent);
 
       IndexedDBCursorParent* cursorActor = new IndexedDBCursorParent(mCursor);
 
       if (!indexActor->SendPIndexedDBCursorConstructor(cursorActor, params)) {
         return Error;
       }
 
       openCursorResponse = cursorActor;
@@ -2319,21 +2396,17 @@ CountHelper::DoDatabaseWork(mozIStorageC
   mCount = stmt->AsInt64(0);
   return NS_OK;
 }
 
 nsresult
 CountHelper::GetSuccessResult(JSContext* aCx,
                               jsval* aVal)
 {
-  if (!JS_NewNumberValue(aCx, static_cast<double>(mCount), aVal)) {
-    NS_WARNING("Failed to make number value!");
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
-
+  *aVal = JS_NumberValue(static_cast<double>(mCount));
   return NS_OK;
 }
 
 void
 CountHelper::ReleaseMainThreadObjects()
 {
   mKeyRange = nullptr;
   IndexHelper::ReleaseMainThreadObjects();
--- a/dom/indexedDB/IDBIndex.h
+++ b/dom/indexedDB/IDBIndex.h
@@ -140,16 +140,17 @@ public:
                               IDBRequest** _retval);
 
   nsresult OpenCursorFromChildProcess(
                             IDBRequest* aRequest,
                             size_t aDirection,
                             const Key& aKey,
                             const Key& aObjectKey,
                             const SerializedStructuredCloneReadInfo& aCloneInfo,
+                            nsTArray<StructuredCloneFile>& aBlobs,
                             IDBCursor** _retval);
 
 private:
   IDBIndex();
   ~IDBIndex();
 
   nsRefPtr<IDBObjectStore> mObjectStore;
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -7,17 +7,20 @@
 #include "base/basictypes.h"
 
 #include "IDBObjectStore.h"
 
 #include "nsIJSContextStack.h"
 #include "nsIOutputStream.h"
 
 #include "jsfriendapi.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/StructuredCloneTags.h"
+#include "mozilla/dom/ipc/Blob.h"
 #include "mozilla/storage.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMFile.h"
 #include "nsDOMLists.h"
 #include "nsEventDispatcher.h"
 #include "nsJSUtils.h"
 #include "nsServiceManagerUtils.h"
@@ -40,16 +43,17 @@
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 #include "IndexedDatabaseInlines.h"
 
 #define FILE_COPY_BUFFER_SIZE 32768
 
 USING_INDEXEDDB_NAMESPACE
+using namespace mozilla::dom;
 using namespace mozilla::dom::indexedDB::ipc;
 
 namespace {
 
 inline
 bool
 IgnoreNothing(PRUnichar c)
 {
@@ -876,17 +880,18 @@ IDBObjectStore::GetStructuredCloneReadIn
     FileManager* fileManager = aDatabase->Manager();
 
     for (PRUint32 i = 0; i < array.Length(); i++) {
       const PRInt64& id = array[i];
 
       nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(id);
       NS_ASSERTION(fileInfo, "Null file info!");
 
-      aInfo.mFileInfos.AppendElement(fileInfo);
+      StructuredCloneFile* file = aInfo.mFiles.AppendElement();
+      file->mFileInfo.swap(fileInfo);
     }
   }
 
   aInfo.mDatabase = aDatabase;
 
   return NS_OK;
 }
 
@@ -949,19 +954,19 @@ IDBObjectStore::SerializeValue(JSContext
 
   return buffer.write(aCx, aValue, &callbacks, &aCloneWriteInfo);
 }
 
 static inline PRUint32
 SwapBytes(PRUint32 u)
 {
 #ifdef IS_BIG_ENDIAN
-  return ((u & 0x000000ffU) << 24) |                                          
-         ((u & 0x0000ff00U) << 8) |                                           
-         ((u & 0x00ff0000U) >> 8) |                                           
+  return ((u & 0x000000ffU) << 24) |
+         ((u & 0x0000ff00U) << 8) |
+         ((u & 0x00ff0000U) >> 8) |
          ((u & 0xff000000U) >> 24);
 #else
   return u;
 #endif
 }
 
 static inline double
 SwapBytes(PRUint64 u)
@@ -1000,34 +1005,38 @@ StructuredCloneReadString(JSStructuredCl
   if (!JS_ReadBytes(aReader, buffer, length)) {
     NS_WARNING("Failed to read type!");
     return false;
   }
 
   return true;
 }
 
+// static
 JSObject*
 IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
                                             JSStructuredCloneReader* aReader,
                                             uint32_t aTag,
                                             uint32_t aData,
                                             void* aClosure)
 {
   if (aTag == SCTAG_DOM_FILEHANDLE || aTag == SCTAG_DOM_BLOB ||
       aTag == SCTAG_DOM_FILE) {
     StructuredCloneReadInfo* cloneReadInfo =
       reinterpret_cast<StructuredCloneReadInfo*>(aClosure);
 
-    if (aData >= cloneReadInfo->mFileInfos.Length()) {
+    if (aData >= cloneReadInfo->mFiles.Length()) {
       NS_ERROR("Bad blob index!");
       return nullptr;
     }
 
-    nsRefPtr<FileInfo> fileInfo = cloneReadInfo->mFileInfos[aData];
+    nsresult rv;
+
+    StructuredCloneFile& file = cloneReadInfo->mFiles[aData];
+    nsRefPtr<FileInfo>& fileInfo = file.mFileInfo;
     IDBDatabase* database = cloneReadInfo->mDatabase;
 
     if (aTag == SCTAG_DOM_FILEHANDLE) {
       nsCString type;
       if (!StructuredCloneReadString(aReader, type)) {
         return nullptr;
       }
       NS_ConvertUTF8toUTF16 convType(type);
@@ -1037,85 +1046,102 @@ IDBObjectStore::StructuredCloneReadCallb
         return nullptr;
       }
       NS_ConvertUTF8toUTF16 convName(name);
 
       nsRefPtr<IDBFileHandle> fileHandle = IDBFileHandle::Create(database,
         convName, convType, fileInfo.forget());
 
       jsval wrappedFileHandle;
-      nsresult rv =
+      rv =
         nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx),
                                    static_cast<nsIDOMFileHandle*>(fileHandle),
                                    &NS_GET_IID(nsIDOMFileHandle),
                                    &wrappedFileHandle);
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to wrap native!");
         return nullptr;
       }
 
       return JSVAL_TO_OBJECT(wrappedFileHandle);
     }
 
-    FileManager* fileManager = database->Manager();
-
-    nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
-    if (!directory) {
-      NS_WARNING("Failed to get directory!");
-      return nullptr;
-    }
-
-    nsCOMPtr<nsIFile> nativeFile =
-      fileManager->GetFileForId(directory, fileInfo->Id());
-    if (!nativeFile) {
-      NS_WARNING("Failed to get file!");
-      return nullptr;
-    }
-
     PRUint64 size;
     if (!JS_ReadBytes(aReader, &size, sizeof(PRUint64))) {
       NS_WARNING("Failed to read size!");
       return nullptr;
     }
     size = SwapBytes(size);
 
     nsCString type;
     if (!StructuredCloneReadString(aReader, type)) {
       return nullptr;
     }
     NS_ConvertUTF8toUTF16 convType(type);
 
+    nsCOMPtr<nsIFile> nativeFile;
+    if (!file.mFile) {
+      FileManager* fileManager = database->Manager();
+        NS_ASSERTION(fileManager, "This should never be null!");
+
+      nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
+      if (!directory) {
+        NS_WARNING("Failed to get directory!");
+        return nullptr;
+      }
+
+      nativeFile = fileManager->GetFileForId(directory, fileInfo->Id());
+      if (!nativeFile) {
+        NS_WARNING("Failed to get file!");
+        return nullptr;
+      }
+    }
+
     if (aTag == SCTAG_DOM_BLOB) {
-      nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(convType, size,
-                                                    nativeFile, fileInfo);
+      nsCOMPtr<nsIDOMBlob> domBlob;
+      if (file.mFile) {
+        domBlob = file.mFile;
+      }
+      else {
+        domBlob = new nsDOMFileFile(convType, size, nativeFile, fileInfo);
+      }
 
       jsval wrappedBlob;
-      nsresult rv =
-        nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), blob,
+       rv =
+        nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domBlob,
                                    &NS_GET_IID(nsIDOMBlob), &wrappedBlob);
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to wrap native!");
         return nullptr;
       }
 
       return JSVAL_TO_OBJECT(wrappedBlob);
     }
 
+    NS_ASSERTION(aTag == SCTAG_DOM_FILE, "Huh?!");
+
     nsCString name;
     if (!StructuredCloneReadString(aReader, name)) {
       return nullptr;
     }
     NS_ConvertUTF8toUTF16 convName(name);
 
-    nsCOMPtr<nsIDOMFile> file = new nsDOMFileFile(convName, convType, size,
-                                                  nativeFile, fileInfo);
+    nsCOMPtr<nsIDOMFile> domFile;
+    if (file.mFile) {
+      domFile = do_QueryInterface(file.mFile);
+      NS_ASSERTION(domFile, "This should never fail!");
+    }
+    else {
+      domFile = new nsDOMFileFile(convName, convType, size, nativeFile,
+                                  fileInfo);
+    }
 
     jsval wrappedFile;
-    nsresult rv =
-      nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), file,
+    rv =
+      nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domFile,
                                  &NS_GET_IID(nsIDOMFile), &wrappedFile);
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to wrap native!");
       return nullptr;
     }
 
     return JSVAL_TO_OBJECT(wrappedFile);
   }
@@ -1125,16 +1151,17 @@ IDBObjectStore::StructuredCloneReadCallb
 
   if (runtimeCallbacks) {
     return runtimeCallbacks->read(aCx, aReader, aTag, aData, nullptr);
   }
 
   return nullptr;
 }
 
+// static
 JSBool
 IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
                                              JSStructuredCloneWriter* aWriter,
                                              JSObject* aObj,
                                              void* aClosure)
 {
   StructuredCloneWriteInfo* cloneWriteInfo =
     reinterpret_cast<StructuredCloneWriteInfo*>(aClosure);
@@ -1155,39 +1182,38 @@ IDBObjectStore::StructuredCloneWriteCall
   if (wrappedNative) {
     nsISupports* supports = wrappedNative->Native();
 
     IDBTransaction* transaction = cloneWriteInfo->mTransaction;
     FileManager* fileManager = transaction->Database()->Manager();
 
     nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
     if (blob) {
+      nsCOMPtr<nsIInputStream> inputStream;
+
       // Check if it is a blob created from this db or the blob was already
       // stored in this db
-
       nsRefPtr<FileInfo> fileInfo = transaction->GetFileInfo(blob);
-      nsCOMPtr<nsIInputStream> inputStream;
-
-      if (!fileInfo) {
+      if (!fileInfo && fileManager) {
         fileInfo = blob->GetFileInfo(fileManager);
-      }
-
-      if (!fileInfo) {
-        fileInfo = fileManager->GetNewFileInfo();
+
         if (!fileInfo) {
-          NS_WARNING("Failed to get new file info!");
-          return false;
+          fileInfo = fileManager->GetNewFileInfo();
+          if (!fileInfo) {
+            NS_WARNING("Failed to get new file info!");
+            return false;
+          }
+
+          if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
+            NS_WARNING("Failed to get internal steam!");
+            return false;
+          }
+
+          transaction->AddFileInfo(blob, fileInfo);
         }
-
-        if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
-          NS_WARNING("Failed to get internal steam!");
-          return false;
-        }
-
-        transaction->AddFileInfo(blob, fileInfo);
       }
 
       PRUint64 size;
       if (NS_FAILED(blob->GetSize(&size))) {
         NS_WARNING("Failed to get size!");
         return false;
       }
       size = SwapBytes(size);
@@ -1199,32 +1225,32 @@ IDBObjectStore::StructuredCloneWriteCall
       }
       NS_ConvertUTF16toUTF8 convType(type);
       PRUint32 convTypeLength = SwapBytes(convType.Length());
 
       nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob);
 
       if (!JS_WriteUint32Pair(aWriter, file ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
                               cloneWriteInfo->mFiles.Length()) ||
-          !JS_WriteBytes(aWriter, &size, sizeof(PRUint64)) ||
-          !JS_WriteBytes(aWriter, &convTypeLength, sizeof(PRUint32)) ||
+          !JS_WriteBytes(aWriter, &size, sizeof(size)) ||
+          !JS_WriteBytes(aWriter, &convTypeLength, sizeof(convTypeLength)) ||
           !JS_WriteBytes(aWriter, convType.get(), convType.Length())) {
         return false;
       }
 
       if (file) {
         nsString name;
         if (NS_FAILED(file->GetName(name))) {
           NS_WARNING("Failed to get name!");
           return false;
         }
         NS_ConvertUTF16toUTF8 convName(name);
         PRUint32 convNameLength = SwapBytes(convName.Length());
 
-        if (!JS_WriteBytes(aWriter, &convNameLength, sizeof(PRUint32)) ||
+        if (!JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
             !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
           return false;
         }
       }
 
       StructuredCloneFile* cloneFile = cloneWriteInfo->mFiles.AppendElement();
       cloneFile->mFile = blob.forget();
       cloneFile->mFileInfo = fileInfo.forget();
@@ -1280,16 +1306,17 @@ IDBObjectStore::StructuredCloneWriteCall
     js::GetContextStructuredCloneCallbacks(aCx);
   if (runtimeCallbacks) {
     return runtimeCallbacks->write(aCx, aWriter, aObj, nullptr);
   }
 
   return false;
 }
 
+// static
 nsresult
 IDBObjectStore::ConvertFileIdsToArray(const nsAString& aFileIds,
                                       nsTArray<PRInt64>& aResult)
 {
   nsCharSeparatedTokenizerTemplate<IgnoreNothing> tokenizer(aFileIds, ' ');
 
   while (tokenizer.hasMoreTokens()) {
     nsString token(tokenizer.nextToken());
@@ -1302,16 +1329,89 @@ IDBObjectStore::ConvertFileIdsToArray(co
     
     PRInt64* element = aResult.AppendElement();
     *element = id;
   }
 
   return NS_OK;
 }
 
+// static
+void
+IDBObjectStore::ConvertActorsToBlobs(
+                                   const InfallibleTArray<PBlobChild*>& aActors,
+                                   nsTArray<StructuredCloneFile>& aFiles)
+{
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(aFiles.IsEmpty(), "Should be empty!");
+
+  if (!aActors.IsEmpty()) {
+    ContentChild* contentChild = ContentChild::GetSingleton();
+    NS_ASSERTION(contentChild, "This should never be null!");
+
+    PRUint32 length = aActors.Length();
+    aFiles.SetCapacity(length);
+
+    for (PRUint32 index = 0; index < length; index++) {
+      BlobChild* actor = static_cast<BlobChild*>(aActors[index]);
+
+      StructuredCloneFile* file = aFiles.AppendElement();