Bug 1047483 - patch 1 - Porting DOMFile/DOMBlob to WebIDL, r=bz, r=bkelly, r=bholley
☠☠ backed out by 47a1219c6324 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 07 Oct 2014 15:20:52 +0100
changeset 209186 6238ff5d3ed0cdc42ec39ec772a1ffd705ed7846
parent 209185 c28b84a34465f2b870f4bef8dae364e6ae7efc01
child 209187 e087289ccfbb9db1a0b471b6baa665810d95edaf
push idunknown
push userunknown
push dateunknown
reviewersbz, bkelly, bholley
bugs1047483
milestone35.0a1
Bug 1047483 - patch 1 - Porting DOMFile/DOMBlob to WebIDL, r=bz, r=bkelly, r=bholley
b2g/components/FilePicker.js
browser/base/content/test/general/browser_blob-channelname.js
content/base/public/nsContentUtils.h
content/base/public/nsDOMFile.h
content/base/src/WebSocket.cpp
content/base/src/WebSocket.h
content/base/src/nsContentUtils.cpp
content/base/src/nsDOMBlobBuilder.cpp
content/base/src/nsDOMBlobBuilder.h
content/base/src/nsDOMDataChannel.cpp
content/base/src/nsDOMDataChannel.h
content/base/src/nsDOMFile.cpp
content/base/src/nsDOMFileReader.cpp
content/base/src/nsDOMFileReader.h
content/base/src/nsFormData.cpp
content/base/src/nsFormData.h
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsHostObjectProtocolHandler.cpp
content/base/src/nsXMLHttpRequest.cpp
content/base/src/nsXMLHttpRequest.h
content/base/test/chrome/test_bug914381.html
content/base/test/test_blobconstructor.html
content/base/test/test_bug403852.html
content/html/content/public/HTMLCanvasElement.h
content/html/content/src/HTMLCanvasElement.cpp
content/html/content/src/HTMLInputElement.cpp
content/html/content/src/HTMLInputElement.h
content/html/content/test/test_formData.html
content/media/EncodedBufferCache.cpp
content/media/EncodedBufferCache.h
content/media/MediaRecorder.cpp
content/media/imagecapture/CaptureTask.cpp
content/media/imagecapture/ImageCapture.cpp
content/media/imagecapture/ImageCapture.h
content/media/webrtc/MediaEngineDefault.cpp
content/media/webrtc/MediaEngineWebRTCVideo.cpp
dom/archivereader/ArchiveReader.cpp
dom/archivereader/ArchiveReader.h
dom/archivereader/ArchiveZipEvent.cpp
dom/archivereader/ArchiveZipFile.cpp
dom/archivereader/ArchiveZipFile.h
dom/base/ImageEncoder.cpp
dom/base/ImageEncoder.h
dom/base/MessagePort.cpp
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/base/URL.cpp
dom/base/URL.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/base/test/file_url.jsm
dom/base/test/test_messageChannel_post.html
dom/bindings/Bindings.conf
dom/bluetooth/BluetoothAdapter.cpp
dom/bluetooth/BluetoothAdapter.h
dom/bluetooth/bluedroid/BluetoothOppManager.cpp
dom/bluetooth/bluez/BluetoothOppManager.cpp
dom/browser-element/BrowserElementParent.jsm
dom/camera/DOMCameraControl.cpp
dom/camera/DOMCameraControlListener.cpp
dom/contacts/ContactManager.js
dom/contacts/tests/test_contacts_blobs.html
dom/devicestorage/DeviceStorageRequestChild.cpp
dom/devicestorage/DeviceStorageRequestParent.cpp
dom/devicestorage/nsDeviceStorage.cpp
dom/events/DataTransfer.cpp
dom/events/test/test_eventctors.html
dom/filehandle/FileHandle.cpp
dom/filehandle/FileHandle.h
dom/filesystem/CreateFileTask.cpp
dom/filesystem/CreateFileTask.h
dom/filesystem/DeviceStorageFileSystem.cpp
dom/filesystem/Directory.cpp
dom/filesystem/FileSystemTaskBase.cpp
dom/filesystem/GetFileOrDirectoryTask.cpp
dom/filesystem/RemoveTask.cpp
dom/indexedDB/ActorsChild.cpp
dom/indexedDB/FileSnapshot.cpp
dom/indexedDB/FileSnapshot.h
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBDatabase.h
dom/indexedDB/IDBMutableFile.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBRequest.cpp
dom/indexedDB/IDBTransaction.h
dom/indexedDB/IndexedDatabase.h
dom/indexedDB/IndexedDatabaseInlines.h
dom/indexedDB/IndexedDatabaseManager.cpp
dom/indexedDB/test/unit/test_temporary_storage.js
dom/ipc/Blob.cpp
dom/ipc/BlobChild.h
dom/ipc/BlobParent.h
dom/ipc/FilePickerParent.cpp
dom/ipc/StructuredCloneUtils.cpp
dom/ipc/StructuredCloneUtils.h
dom/ipc/nsIContentChild.cpp
dom/ipc/nsIContentChild.h
dom/ipc/nsIContentParent.cpp
dom/ipc/nsIContentParent.h
dom/mobilemessage/MmsMessage.cpp
dom/mobilemessage/MmsMessage.h
dom/mobilemessage/gonk/WspPduHelper.jsm
dom/mobilemessage/ipc/SmsParent.cpp
dom/network/UDPSocket.cpp
dom/settings/SettingsDB.jsm
dom/webidl/Blob.webidl
dom/webidl/BlobEvent.webidl
dom/webidl/Directory.webidl
dom/webidl/File.webidl
dom/webidl/FileList.webidl
dom/webidl/FileReaderSync.webidl
dom/webidl/HTMLCanvasElement.webidl
dom/webidl/XMLHttpRequest.webidl
dom/workers/File.cpp
dom/workers/File.h
dom/workers/FileReaderSync.cpp
dom/workers/FileReaderSync.h
dom/workers/RegisterBindings.cpp
dom/workers/URL.cpp
dom/workers/URL.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/XMLHttpRequest.cpp
dom/workers/XMLHttpRequest.h
dom/workers/moz.build
dom/workers/test/fileReaderSyncErrors_worker.js
ipc/glue/InputStreamUtils.cpp
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/src/ExportHelpers.cpp
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCShellImpl.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/tests/chrome/test_cloneInto.xul
js/xpconnect/tests/unit/component-blob.js
js/xpconnect/tests/unit/component-file.js
js/xpconnect/tests/unit/test_blob2.js
js/xpconnect/tests/unit/test_file2.js
layout/build/nsLayoutModule.cpp
testing/specialpowers/content/MockFilePicker.jsm
toolkit/components/thumbnails/content/backgroundPageThumbsContent.js
toolkit/crashreporter/CrashSubmit.jsm
toolkit/modules/PropertyListUtils.jsm
widget/xpwidgets/nsBaseFilePicker.cpp
widget/xpwidgets/nsBaseFilePicker.h
widget/xpwidgets/nsFilePickerProxy.cpp
widget/xpwidgets/nsFilePickerProxy.h
--- a/b2g/components/FilePicker.js
+++ b/b2g/components/FilePicker.js
@@ -202,19 +202,19 @@ FilePicker.prototype = {
         let mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
         let mimeInfo = mimeSvc.getFromTypeAndExtension(data.result.blob.type, '');
         if (mimeInfo) {
           name += '.' + mimeInfo.primaryExtension;
         }
       }
     }
 
-    let file = new this.mParent.File(data.result.blob,
-                                     { name: name,
-                                       type: data.result.blob.type });
+    let file = new this.mParent.File([data.result.blob],
+                                     name,
+                                     { type: data.result.blob.type });
 
     if (file) {
       this.fireSuccess(file);
     } else {
       this.fireError();
     }
   }
 };
--- a/browser/base/content/test/general/browser_blob-channelname.js
+++ b/browser/base/content/test/general/browser_blob-channelname.js
@@ -1,11 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 Cu.import("resource://gre/modules/NetUtil.jsm");
 
 function test() {
-    var file = new File(new Blob(['test'], {type: 'text/plain'}), {name: 'test-name'});
+    var file = new File([new Blob(['test'], {type: 'text/plain'})], "test-name");
     var url = URL.createObjectURL(file);
     var channel = NetUtil.newChannel(url);
 
     is(channel.contentDispositionFilename, 'test-name', "filename matches");
 }
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1664,16 +1664,17 @@ public:
 
   /**
    * Creates an arraybuffer from a binary string.
    */
   static nsresult CreateArrayBuffer(JSContext *aCx, const nsACString& aData,
                                     JSObject** aResult);
 
   static nsresult CreateBlobBuffer(JSContext* aCx,
+                                   nsISupports* aParent,
                                    const nsACString& aData,
                                    JS::MutableHandle<JS::Value> aBlob);
 
   static void StripNullChars(const nsAString& aInStr, nsAString& aOutStr);
 
   /**
    * Strip all \n, \r and nulls from the given string
    * @param aString the string to remove newlines from [in/out]
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -1,43 +1,38 @@
 /* -*- 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 nsDOMFile_h__
-#define nsDOMFile_h__
+#ifndef mozilla_dom_DOMFile_h
+#define mozilla_dom_DOMFile_h
 
 #include "mozilla/Attributes.h"
-#include "nsICharsetDetectionObserver.h"
-#include "nsIFile.h"
-#include "nsIDOMFile.h"
-#include "nsIDOMFileList.h"
-#include "nsIInputStream.h"
-#include "nsIJSNativeInitializer.h"
-#include "nsIMutable.h"
-#include "nsCOMArray.h"
-#include "nsCOMPtr.h"
-#include "nsString.h"
-#include "nsIXMLHttpRequest.h"
-#include "nsAutoPtr.h"
-#include "nsFileStreams.h"
-#include "nsTemporaryFileInputStream.h"
 
 #include "mozilla/GuardObjects.h"
 #include "mozilla/LinkedList.h"
-#include <stdint.h>
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
-#include "mozilla/dom/DOMError.h"
+#include "mozilla/dom/Date.h"
 #include "mozilla/dom/indexedDB/FileInfo.h"
 #include "mozilla/dom/indexedDB/FileManager.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
+#include "mozilla/dom/UnionTypes.h"
+#include "nsAutoPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsCOMPtr.h"
+#include "nsIDOMFile.h"
+#include "nsIDOMFileList.h"
+#include "nsIFile.h"
+#include "nsIMutable.h"
+#include "nsIXMLHttpRequest.h"
+#include "nsString.h"
+#include "nsTemporaryFileInputStream.h"
 #include "nsWrapperCache.h"
-#include "nsCycleCollectionParticipant.h"
 #include "nsWeakReference.h"
 
 class nsDOMMultipartFile;
 class nsIFile;
 class nsIInputStream;
 class nsIClassInfo;
 
 #define PIDOMFILEIMPL_IID \
@@ -54,86 +49,93 @@ NS_DEFINE_STATIC_IID_ACCESSOR(PIDOMFileI
 
 namespace mozilla {
 namespace dom {
 
 namespace indexedDB {
 class FileInfo;
 };
 
+struct BlobPropertyBag;
+struct FilePropertyBag;
 class DOMFileImpl;
 
+/* FOLLOWUP TODO:
+1. remove nsDOMBlobBuilder.h
+2. rename nsDOMFile.h/cpp to DOMFile.h/cpp
+3. rename nsDOMFileList to DOMFileList
+*/
 class DOMFile MOZ_FINAL : public nsIDOMFile
                         , public nsIXHRSendable
                         , public nsIMutable
-                        , public nsIJSNativeInitializer
                         , public nsSupportsWeakReference
+                        , public nsWrapperCache
 {
 public:
   NS_DECL_NSIDOMBLOB
   NS_DECL_NSIDOMFILE
   NS_DECL_NSIXHRSENDABLE
   NS_DECL_NSIMUTABLE
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DOMFile, nsIDOMFile)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(DOMFile, nsIDOMFile)
 
   static already_AddRefed<DOMFile>
-  Create(const nsAString& aName, const nsAString& aContentType,
-         uint64_t aLength, uint64_t aLastModifiedDate);
+  Create(nsISupports* aParent, const nsAString& aName,
+         const nsAString& aContentType, uint64_t aLength,
+         uint64_t aLastModifiedDate);
 
   static already_AddRefed<DOMFile>
-  Create(const nsAString& aName, const nsAString& aContentType,
+  Create(nsISupports* aParent, const nsAString& aName,
+         const nsAString& aContentType, uint64_t aLength);
+
+  static already_AddRefed<DOMFile>
+  Create(nsISupports* aParent, const nsAString& aContentType,
          uint64_t aLength);
 
   static already_AddRefed<DOMFile>
-  Create(const nsAString& aContentType, uint64_t aLength);
-
-  static already_AddRefed<DOMFile>
-  Create(const nsAString& aContentType, uint64_t aStart,
+  Create(nsISupports* aParent, const nsAString& aContentType, uint64_t aStart,
          uint64_t aLength);
 
   static already_AddRefed<DOMFile>
-  CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
+  CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
                    const nsAString& aName, const nsAString& aContentType,
                    uint64_t aLastModifiedDate);
 
   static already_AddRefed<DOMFile>
-  CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
+  CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
                    const nsAString& aContentType);
 
   static already_AddRefed<DOMFile>
-  CreateTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos,
-                          uint64_t aLength,
+  CreateTemporaryFileBlob(nsISupports* aParent, PRFileDesc* aFD,
+                          uint64_t aStartPos, uint64_t aLength,
                           const nsAString& aContentType);
 
   static already_AddRefed<DOMFile>
-  CreateFromFile(nsIFile* aFile);
+  CreateFromFile(nsISupports* aParent, nsIFile* aFile);
 
   static already_AddRefed<DOMFile>
-  CreateFromFile(const nsAString& aContentType, uint64_t aLength,
+  CreateFromFile(nsISupports* aParent, const nsAString& aContentType,
+                 uint64_t aLength, nsIFile* aFile,
+                 indexedDB::FileInfo* aFileInfo);
+
+  static already_AddRefed<DOMFile>
+  CreateFromFile(nsISupports* aParent, const nsAString& aName,
+                 const nsAString& aContentType, uint64_t aLength,
                  nsIFile* aFile, indexedDB::FileInfo* aFileInfo);
 
   static already_AddRefed<DOMFile>
-  CreateFromFile(const nsAString& aName, const nsAString& aContentType,
-                 uint64_t aLength, nsIFile* aFile,
-                    indexedDB::FileInfo* aFileInfo);
-
-  static already_AddRefed<DOMFile>
-  CreateFromFile(nsIFile* aFile, indexedDB::FileInfo* aFileInfo);
+  CreateFromFile(nsISupports* aParent, nsIFile* aFile,
+                 indexedDB::FileInfo* aFileInfo);
 
   static already_AddRefed<DOMFile>
-  CreateFromFile(nsIFile* aFile, const nsAString& aName,
+  CreateFromFile(nsISupports* aParent, nsIFile* aFile, const nsAString& aName,
                  const nsAString& aContentType);
 
-  explicit DOMFile(DOMFileImpl* aImpl)
-    : mImpl(aImpl)
-  {
-    MOZ_ASSERT(mImpl);
-  }
+  DOMFile(nsISupports* aParent, DOMFileImpl* aImpl);
 
   DOMFileImpl* Impl() const
   {
     return mImpl;
   }
 
   const nsTArray<nsRefPtr<DOMFileImpl>>* GetSubBlobImpls() const;
 
@@ -141,67 +143,127 @@ public:
 
   bool IsDateUnknown() const;
 
   bool IsFile() const;
 
   void SetLazyData(const nsAString& aName, const nsAString& aContentType,
                    uint64_t aLength, uint64_t aLastModifiedDate);
 
-  already_AddRefed<nsIDOMBlob>
-  CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType);
+  already_AddRefed<DOMFile>
+  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
+              ErrorResult& aRv);
+
+  // WebIDL methods
+  nsISupports* GetParentObject() const
+  {
+    return mParent;
+  }
+
+  // Blob constructor
+  static already_AddRefed<DOMFile>
+  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+
+  // Blob constructor
+  static already_AddRefed<DOMFile>
+  Constructor(const GlobalObject& aGlobal,
+              const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+              const BlobPropertyBag& aBag,
+              ErrorResult& aRv);
+
+  // File constructor
+  static already_AddRefed<DOMFile>
+  Constructor(const GlobalObject& aGlobal,
+              const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+              const nsAString& aName,
+              const FilePropertyBag& aBag,
+              ErrorResult& aRv);
 
-  // nsIJSNativeInitializer
-  NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
-                        const JS::CallArgs& aArgs) MOZ_OVERRIDE;
+  // File constructor - ChromeOnly
+  static already_AddRefed<DOMFile>
+  Constructor(const GlobalObject& aGlobal,
+              DOMFile& aData,
+              const FilePropertyBag& aBag,
+              ErrorResult& aRv);
+
+  // File constructor - ChromeOnly
+  static already_AddRefed<DOMFile>
+  Constructor(const GlobalObject& aGlobal,
+              const nsAString& aData,
+              const FilePropertyBag& aBag,
+              ErrorResult& aRv);
+
+  // File constructor - ChromeOnly
+  static already_AddRefed<DOMFile>
+  Constructor(const GlobalObject& aGlobal,
+              nsIFile* aData,
+              const FilePropertyBag& aBag,
+              ErrorResult& aRv);
+
+  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+  uint64_t GetSize(ErrorResult& aRv);
+
+  // XPCOM GetType is OK
+
+  // XPCOM GetName is OK
+
+  int64_t GetLastModified(ErrorResult& aRv);
+
+  Date GetLastModifiedDate(ErrorResult& aRv);
+
+  void GetMozFullPath(nsAString& aFilename, ErrorResult& aRv);
+
+  already_AddRefed<DOMFile> Slice(const Optional<int64_t>& aStart,
+                                  const Optional<int64_t>& aEnd,
+                                  const nsAString& aContentType,
+                                  ErrorResult& aRv);
 
 private:
   ~DOMFile() {};
 
   // The member is the real backend implementation of this DOMFile/DOMBlob.
   // It's thread-safe and not CC-able and it's the only element that is moved
   // between threads.
   // Note: we should not store any other state in this class!
   const nsRefPtr<DOMFileImpl> mImpl;
+
+  nsCOMPtr<nsISupports> mParent;
 };
 
 // This is the abstract class for any DOMFile backend. It must be nsISupports
 // because this class must be ref-counted and it has to work with IPC.
 class DOMFileImpl : public PIDOMFileImpl
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   DOMFileImpl() {}
 
-  virtual nsresult GetName(nsAString& aName) = 0;
+  virtual void GetName(nsAString& aName) = 0;
 
   virtual nsresult GetPath(nsAString& aName) = 0;
 
-  virtual nsresult
-  GetLastModifiedDate(JSContext* aCx,
-                      JS::MutableHandle<JS::Value> aDate) = 0;
+  virtual int64_t GetLastModified(ErrorResult& aRv) = 0;
 
-  virtual nsresult GetMozFullPath(nsAString& aName) = 0;
+  virtual void GetMozFullPath(nsAString& aName, ErrorResult& aRv) = 0;
 
-  virtual nsresult GetMozFullPathInternal(nsAString &aFileName) = 0;
+  virtual void GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) = 0;
 
-  virtual nsresult GetSize(uint64_t* aSize) = 0;
+  virtual uint64_t GetSize(ErrorResult& aRv) = 0;
 
-  virtual nsresult GetType(nsAString& aType) = 0;
+  virtual void GetType(nsAString& aType) = 0;
 
-  virtual nsresult GetMozLastModifiedDate(uint64_t* aDate) = 0;
-
-  nsresult Slice(int64_t aStart, int64_t aEnd, const nsAString& aContentType,
-                 uint8_t aArgc, DOMFileImpl** aBlobImpl);
+  already_AddRefed<DOMFileImpl>
+  Slice(const Optional<int64_t>& aStart, const Optional<int64_t>& aEnd,
+        const nsAString& aContentType, ErrorResult& aRv);
 
   virtual already_AddRefed<DOMFileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) = 0;
+              const nsAString& aContentType, ErrorResult& aRv) = 0;
 
   virtual const nsTArray<nsRefPtr<DOMFileImpl>>*
   GetSubBlobImpls() const = 0;
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) = 0;
 
   virtual int64_t GetFileId() = 0;
 
@@ -227,19 +289,16 @@ public:
   virtual bool IsMemoryFile() const = 0;
 
   virtual bool IsSizeUnknown() const = 0;
 
   virtual bool IsDateUnknown() const = 0;
 
   virtual bool IsFile() const = 0;
 
-  virtual nsresult Initialize(nsISupports* aOwner, JSContext* aCx,
-                              JSObject* aObj, const JS::CallArgs& aArgs) = 0;
-
   // These 2 methods are used when the implementation has to CC something.
   virtual void Unlink() = 0;
   virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) = 0;
 
   virtual bool IsCCed() const
   {
     return false;
   }
@@ -301,44 +360,51 @@ public:
     , mLastModificationDate(UINT64_MAX)
   {
     NS_ASSERTION(aLength != UINT64_MAX,
                  "Must know length when creating slice");
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
   }
 
-  virtual nsresult GetName(nsAString& aName) MOZ_OVERRIDE;
+  virtual void GetName(nsAString& aName) MOZ_OVERRIDE;
 
   virtual nsresult GetPath(nsAString& aName) MOZ_OVERRIDE;
 
-  virtual nsresult GetLastModifiedDate(JSContext* aCx,
-                               JS::MutableHandle<JS::Value> aDate) MOZ_OVERRIDE;
+  virtual int64_t GetLastModified(ErrorResult& aRv) MOZ_OVERRIDE;
 
-  virtual nsresult GetMozFullPath(nsAString& aName) MOZ_OVERRIDE;
+  virtual void GetMozFullPath(nsAString& aName, ErrorResult& aRv) MOZ_OVERRIDE;
+
+  virtual void GetMozFullPathInternal(nsAString& aFileName,
+                                      ErrorResult& aRv) MOZ_OVERRIDE;
 
-  virtual nsresult GetMozFullPathInternal(nsAString& aFileName) MOZ_OVERRIDE;
-
-  virtual nsresult GetSize(uint64_t* aSize) MOZ_OVERRIDE;
+  virtual uint64_t GetSize(ErrorResult& aRv) MOZ_OVERRIDE
+  {
+    return mLength;
+  }
 
-  virtual nsresult GetType(nsAString& aType) MOZ_OVERRIDE;
-
-  virtual nsresult GetMozLastModifiedDate(uint64_t* aDate) MOZ_OVERRIDE;
+  virtual void GetType(nsAString& aType) MOZ_OVERRIDE;
 
   virtual already_AddRefed<DOMFileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType, ErrorResult& aRv) MOZ_OVERRIDE
+  {
+    return nullptr;
+  }
 
   virtual const nsTArray<nsRefPtr<DOMFileImpl>>*
   GetSubBlobImpls() const MOZ_OVERRIDE
   {
     return nullptr;
   }
 
-  virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
+  virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE
+  {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
 
   virtual int64_t GetFileId() MOZ_OVERRIDE;
 
   virtual void AddFileInfo(indexedDB::FileInfo* aFileInfo) MOZ_OVERRIDE;
 
   virtual indexedDB::FileInfo*
   GetFileInfo(indexedDB::FileManager* aFileManager) MOZ_OVERRIDE;
 
@@ -395,22 +461,16 @@ public:
     return false;
   }
 
   virtual bool IsSizeUnknown() const
   {
     return mLength == UINT64_MAX;
   }
 
-  virtual nsresult Initialize(nsISupports* aOwner, JSContext* aCx,
-                              JSObject* aObj, const JS::CallArgs& aArgs)
-  {
-    return NS_OK;
-  }
-
   virtual void Unlink() {}
   virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) {}
 
 protected:
   virtual ~DOMFileImplBase() {}
 
   indexedDB::FileInfo* GetFileInfo() const
   {
@@ -463,17 +523,17 @@ public:
   {
     NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
   }
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
   virtual already_AddRefed<DOMFileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType, ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual bool IsMemoryFile() const MOZ_OVERRIDE
   {
     return true;
   }
 
   class DataOwner MOZ_FINAL : public mozilla::LinkedListElement<DataOwner> {
   public:
@@ -550,17 +610,17 @@ public:
   {
     mFileDescOwner = new nsTemporaryFileInputStream::FileDescOwner(aFD);
   }
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
   virtual already_AddRefed<DOMFileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType, ErrorResult& aRv) MOZ_OVERRIDE;
 
 private:
   DOMFileImplTemporaryFileBlob(const DOMFileImplTemporaryFileBlob* aOther,
                                uint64_t aStart, uint64_t aLength,
                                const nsAString& aContentType)
     : DOMFileImplBase(aContentType, aLength)
     , mLength(aLength)
     , mStartPos(aStart)
@@ -677,22 +737,21 @@ public:
     , mStoredFile(false)
   {
     // Lazily get the content type and size
     mContentType.SetIsVoid(true);
     mName.SetIsVoid(true);
   }
 
   // Overrides
-  virtual nsresult GetSize(uint64_t* aSize) MOZ_OVERRIDE;
-  virtual nsresult GetType(nsAString& aType) MOZ_OVERRIDE;
-  virtual nsresult GetLastModifiedDate(JSContext* aCx,
-                               JS::MutableHandle<JS::Value> aLastModifiedDate) MOZ_OVERRIDE;
-  virtual nsresult GetMozLastModifiedDate(uint64_t* aLastModifiedDate) MOZ_OVERRIDE;
-  virtual nsresult GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
+  virtual uint64_t GetSize(ErrorResult& aRv) MOZ_OVERRIDE;
+  virtual void GetType(nsAString& aType) MOZ_OVERRIDE;
+  virtual int64_t GetLastModified(ErrorResult& aRv) MOZ_OVERRIDE;
+  virtual void GetMozFullPathInternal(nsAString& aFullPath,
+                                      ErrorResult& aRv) MOZ_OVERRIDE;
   virtual nsresult GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
 
   void SetPath(const nsAString& aFullPath);
 
 protected:
   virtual ~DOMFileImplFile() {}
 
 private:
@@ -721,36 +780,33 @@ private:
       }
 
       mFileInfos.AppendElement(fileInfo);
     }
   }
 
   virtual already_AddRefed<DOMFileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType, ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual bool IsStoredFile() const MOZ_OVERRIDE
   {
     return mStoredFile;
   }
 
   virtual bool IsWholeFile() const MOZ_OVERRIDE
   {
     return mWholeFile;
   }
 
   nsCOMPtr<nsIFile> mFile;
   bool mWholeFile;
   bool mStoredFile;
 };
 
-} // dom namespace
-} // file namespace
-
 class nsDOMFileList MOZ_FINAL : public nsIDOMFileList,
                                 public nsWrapperCache
 {
   ~nsDOMFileList() {}
 
 public:
   explicit nsDOMFileList(nsISupports *aParent) : mParent(aParent)
   {
@@ -768,19 +824,27 @@ public:
     return mParent;
   }
 
   void Disconnect()
   {
     mParent = nullptr;
   }
 
-  bool Append(nsIDOMFile *aFile) { return mFiles.AppendObject(aFile); }
+  bool Append(DOMFile *aFile) { return mFiles.AppendElement(aFile); }
 
-  bool Remove(uint32_t aIndex) { return mFiles.RemoveObjectAt(aIndex); }
+  bool Remove(uint32_t aIndex) {
+    if (aIndex < mFiles.Length()) {
+      mFiles.RemoveElementAt(aIndex);
+      return true;
+    }
+
+    return false;
+  }
+
   void Clear() { return mFiles.Clear(); }
 
   static nsDOMFileList* FromSupports(nsISupports* aSupports)
   {
 #ifdef DEBUG
     {
       nsCOMPtr<nsIDOMFileList> list_qi = do_QueryInterface(aSupports);
 
@@ -790,28 +854,31 @@ public:
       NS_ASSERTION(list_qi == static_cast<nsIDOMFileList*>(aSupports),
                    "Uh, fix QI!");
     }
 #endif
 
     return static_cast<nsDOMFileList*>(aSupports);
   }
 
-  nsIDOMFile* Item(uint32_t aIndex)
+  DOMFile* Item(uint32_t aIndex)
   {
-    return mFiles.SafeObjectAt(aIndex);
+    return mFiles.SafeElementAt(aIndex);
   }
-  nsIDOMFile* IndexedGetter(uint32_t aIndex, bool& aFound)
+  DOMFile* IndexedGetter(uint32_t aIndex, bool& aFound)
   {
-    aFound = aIndex < static_cast<uint32_t>(mFiles.Count());
-    return aFound ? mFiles.ObjectAt(aIndex) : nullptr;
+    aFound = aIndex < mFiles.Length();
+    return aFound ? mFiles.ElementAt(aIndex) : nullptr;
   }
   uint32_t Length()
   {
-    return mFiles.Count();
+    return mFiles.Length();
   }
 
 private:
-  nsCOMArray<nsIDOMFile> mFiles;
+  nsTArray<nsRefPtr<DOMFile>> mFiles;
   nsISupports *mParent;
 };
 
-#endif
+} // dom namespace
+} // file namespace
+
+#endif // mozilla_dom_DOMFile_h
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -893,17 +893,17 @@ WebSocket::CreateAndDispatchMessageEvent
     return NS_ERROR_FAILURE;
   }
   JSContext* cx = jsapi.cx();
 
   // Create appropriate JS object for message
   JS::Rooted<JS::Value> jsData(cx);
   if (isBinary) {
     if (mBinaryType == dom::BinaryType::Blob) {
-      rv = nsContentUtils::CreateBlobBuffer(cx, aData, &jsData);
+      rv = nsContentUtils::CreateBlobBuffer(cx, GetOwner(), aData, &jsData);
       NS_ENSURE_SUCCESS(rv, rv);
     } else if (mBinaryType == dom::BinaryType::Arraybuffer) {
       JS::Rooted<JSObject*> arrayBuf(cx);
       rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
       NS_ENSURE_SUCCESS(rv, rv);
       jsData = OBJECT_TO_JSVAL(arrayBuf);
     } else {
       NS_RUNTIMEABORT("Unknown binary type!");
@@ -1189,30 +1189,30 @@ WebSocket::Send(const nsAString& aData,
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   NS_ConvertUTF16toUTF8 msgString(aData);
   Send(nullptr, msgString, msgString.Length(), false, aRv);
 }
 
 void
-WebSocket::Send(nsIDOMBlob* aData,
+WebSocket::Send(DOMFile& aData,
                 ErrorResult& aRv)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   nsCOMPtr<nsIInputStream> msgStream;
-  nsresult rv = aData->GetInternalStream(getter_AddRefs(msgStream));
+  nsresult rv = aData.GetInternalStream(getter_AddRefs(msgStream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   uint64_t msgLength;
-  rv = aData->GetSize(&msgLength);
+  rv = aData.GetSize(&msgLength);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   if (msgLength > UINT32_MAX) {
     aRv.Throw(NS_ERROR_FILE_TOO_BIG);
     return;
--- a/content/base/src/WebSocket.h
+++ b/content/base/src/WebSocket.h
@@ -27,16 +27,18 @@
 #include "nsWrapperCache.h"
 
 #define DEFAULT_WS_SCHEME_PORT  80
 #define DEFAULT_WSS_SCHEME_PORT 443
 
 namespace mozilla {
 namespace dom {
 
+class DOMFile;
+
 class WebSocket MOZ_FINAL : public DOMEventTargetHelper,
                             public nsIInterfaceRequestor,
                             public nsIWebSocketListener,
                             public nsIObserver,
                             public nsSupportsWeakReference,
                             public nsIRequest
 {
 friend class CallDispatchConnectionCloseEvents;
@@ -126,17 +128,17 @@ public: // WebIDL interface:
 
   // webIDL: attribute DOMString binaryType;
   dom::BinaryType BinaryType() const { return mBinaryType; }
   void SetBinaryType(dom::BinaryType aData) { mBinaryType = aData; }
 
   // webIDL: void send(DOMString|Blob|ArrayBufferView data);
   void Send(const nsAString& aData,
             ErrorResult& aRv);
-  void Send(nsIDOMBlob* aData,
+  void Send(DOMFile& aData,
             ErrorResult& aRv);
   void Send(const ArrayBuffer& aData,
             ErrorResult& aRv);
   void Send(const ArrayBufferView& aData,
             ErrorResult& aRv);
 
 private: // constructor && distructor
   explicit WebSocket(nsPIDOMWindow* aOwnerWindow);
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -85,16 +85,17 @@
 #include "nsGkAtoms.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsHtml5Module.h"
 #include "nsHtml5StringParser.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsICategoryManager.h"
 #include "nsIChannelEventSink.h"
 #include "nsIChannelPolicy.h"
+#include "nsICharsetDetectionObserver.h"
 #include "nsIChromeRegistry.h"
 #include "nsIConsoleService.h"
 #include "nsIContent.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIContentSink.h"
 #include "nsIContentViewer.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
@@ -5987,30 +5988,36 @@ nsContentUtils::CreateArrayBuffer(JSCont
 
   return NS_OK;
 }
 
 // Initial implementation: only stores to RAM, not file
 // TODO: bug 704447: large file support
 nsresult
 nsContentUtils::CreateBlobBuffer(JSContext* aCx,
+                                 nsISupports* aParent,
                                  const nsACString& aData,
                                  JS::MutableHandle<JS::Value> aBlob)
 {
   uint32_t blobLen = aData.Length();
   void* blobData = moz_malloc(blobLen);
-  nsCOMPtr<nsIDOMBlob> blob;
+  nsRefPtr<DOMFile> blob;
   if (blobData) {
     memcpy(blobData, aData.BeginReading(), blobLen);
-    blob = mozilla::dom::DOMFile::CreateMemoryFile(blobData, blobLen,
+    blob = mozilla::dom::DOMFile::CreateMemoryFile(aParent, blobData, blobLen,
                                                    EmptyString());
   } else {
     return NS_ERROR_OUT_OF_MEMORY;
   }
-  return nsContentUtils::WrapNative(aCx, blob, aBlob);
+
+  if (!WrapNewBindingObject(aCx, blob, aBlob)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
 }
 
 void
 nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr)
 {
   // In common cases where we don't have nulls in the
   // string we can simple simply bypass the checking code.
   int32_t firstNullPos = aInStr.FindChar('\0');
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -1,16 +1,15 @@
 /* -*- 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 "nsDOMBlobBuilder.h"
 #include "jsfriendapi.h"
-#include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/FileBinding.h"
 #include "nsAutoPtr.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsStringStream.h"
 #include "nsTArray.h"
 #include "nsJSUtils.h"
 #include "nsContentUtils.h"
@@ -19,23 +18,16 @@
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_ISUPPORTS_INHERITED0(DOMMultipartFileImpl, DOMFileImpl)
 
 nsresult
-DOMMultipartFileImpl::GetSize(uint64_t* aLength)
-{
-  *aLength = mLength;
-  return NS_OK;
-}
-
-nsresult
 DOMMultipartFileImpl::GetInternalStream(nsIInputStream** aStream)
 {
   nsresult rv;
   *aStream = nullptr;
 
   nsCOMPtr<nsIMultiplexInputStream> stream =
     do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
   NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);
@@ -52,225 +44,145 @@ DOMMultipartFileImpl::GetInternalStream(
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return CallQueryInterface(stream, aStream);
 }
 
 already_AddRefed<DOMFileImpl>
 DOMMultipartFileImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
-                                  const nsAString& aContentType)
+                                  const nsAString& aContentType,
+                                  ErrorResult& aRv)
 {
   // If we clamped to nothing we create an empty blob
   nsTArray<nsRefPtr<DOMFileImpl>> blobImpls;
 
   uint64_t length = aLength;
   uint64_t skipStart = aStart;
 
   // Prune the list of blobs if we can
   uint32_t i;
   for (i = 0; length && skipStart && i < mBlobImpls.Length(); i++) {
     DOMFileImpl* blobImpl = mBlobImpls[i].get();
 
-    uint64_t l;
-    nsresult rv = blobImpl->GetSize(&l);
-    NS_ENSURE_SUCCESS(rv, nullptr);
+    uint64_t l = blobImpl->GetSize(aRv);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
+    }
 
     if (skipStart < l) {
       uint64_t upperBound = std::min<uint64_t>(l - skipStart, length);
 
-      nsRefPtr<DOMFileImpl> firstImpl;
-      rv = blobImpl->Slice(skipStart, skipStart + upperBound, aContentType, 3,
-                           getter_AddRefs(firstImpl));
-      NS_ENSURE_SUCCESS(rv, nullptr);
+      nsRefPtr<DOMFileImpl> firstBlobImpl =
+        blobImpl->CreateSlice(skipStart, upperBound,
+                              aContentType, aRv);
+      if (NS_WARN_IF(aRv.Failed())) {
+        return nullptr;
+      }
 
       // Avoid wrapping a single blob inside an DOMMultipartFileImpl
       if (length == upperBound) {
-        return firstImpl.forget();
+        return firstBlobImpl.forget();
       }
 
-      blobImpls.AppendElement(firstImpl);
+      blobImpls.AppendElement(firstBlobImpl);
       length -= upperBound;
       i++;
       break;
     }
     skipStart -= l;
   }
 
   // Now append enough blobs until we're done
   for (; length && i < mBlobImpls.Length(); i++) {
     DOMFileImpl* blobImpl = mBlobImpls[i].get();
 
-    uint64_t l;
-    nsresult rv = blobImpl->GetSize(&l);
-    NS_ENSURE_SUCCESS(rv, nullptr);
+    uint64_t l = blobImpl->GetSize(aRv);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
+    }
 
     if (length < l) {
-      nsRefPtr<DOMFileImpl> lastBlob;
-      rv = blobImpl->Slice(0, length, aContentType, 3,
-                           getter_AddRefs(lastBlob));
-      NS_ENSURE_SUCCESS(rv, nullptr);
+      nsRefPtr<DOMFileImpl> lastBlobImpl =
+        blobImpl->CreateSlice(0, length, aContentType, aRv);
+      if (NS_WARN_IF(aRv.Failed())) {
+        return nullptr;
+      }
 
-      blobImpls.AppendElement(lastBlob);
+      blobImpls.AppendElement(lastBlobImpl);
     } else {
       blobImpls.AppendElement(blobImpl);
     }
     length -= std::min<uint64_t>(l, length);
   }
 
   // we can create our blob now
   nsRefPtr<DOMFileImpl> impl =
     new DOMMultipartFileImpl(blobImpls, aContentType);
   return impl.forget();
 }
 
-/* static */ nsresult
-DOMMultipartFileImpl::NewFile(const nsAString& aName, nsISupports** aNewObject)
+void
+DOMMultipartFileImpl::InitializeBlob()
 {
-  nsCOMPtr<nsISupports> file =
-    do_QueryObject(new DOMFile(new DOMMultipartFileImpl(aName)));
-  file.forget(aNewObject);
-  return NS_OK;
-}
-
-/* static */ nsresult
-DOMMultipartFileImpl::NewBlob(nsISupports** aNewObject)
-{
-  nsCOMPtr<nsISupports> file =
-    do_QueryObject(new DOMFile(new DOMMultipartFileImpl()));
-  file.forget(aNewObject);
-  return NS_OK;
+  SetLengthAndModifiedDate();
 }
 
-static nsIDOMBlob*
-GetXPConnectNative(JSContext* aCx, JSObject* aObj) {
-  nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(
-    nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, aObj));
-  return blob;
-}
-
-nsresult
-DOMMultipartFileImpl::Initialize(nsISupports* aOwner,
-                                 JSContext* aCx,
-                                 JSObject* aObj,
-                                 const JS::CallArgs& aArgs)
+void
+DOMMultipartFileImpl::InitializeBlob(
+       JSContext* aCx,
+       const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+       const nsAString& aContentType,
+       bool aNativeEOL,
+       ErrorResult& aRv)
 {
-  if (!mIsFile) {
-    return InitBlob(aCx, aArgs.length(), aArgs.array(), GetXPConnectNative);
-  }
+  mContentType = aContentType;
+  BlobSet blobSet;
+
+  for (uint32_t i = 0, len = aData.Length(); i < len; ++i) {
+    const OwningArrayBufferOrArrayBufferViewOrBlobOrString& data = aData[i];
 
-  if (!nsContentUtils::IsCallerChrome()) {
-    return InitFile(aCx, aArgs.length(), aArgs.array());
-  }
+    if (data.IsBlob()) {
+      nsRefPtr<DOMFile> file = data.GetAsBlob().get();
+      blobSet.AppendBlobImpl(file->Impl());
+    }
+
+    else if (data.IsString()) {
+      aRv = blobSet.AppendString(data.GetAsString(), aNativeEOL, aCx);
+      if (aRv.Failed()) {
+        return;
+      }
+    }
 
-  if (aArgs.length() > 0) {
-    JS::Value* argv = aArgs.array();
-    if (argv[0].isObject()) {
-      JS::Rooted<JSObject*> obj(aCx, &argv[0].toObject());
-      if (JS_IsArrayObject(aCx, obj)) {
-        return InitFile(aCx, aArgs.length(), aArgs.array());
+    else if (data.IsArrayBuffer()) {
+      const ArrayBuffer& buffer = data.GetAsArrayBuffer();
+      buffer.ComputeLengthAndData();
+      aRv = blobSet.AppendVoidPtr(buffer.Data(), buffer.Length());
+      if (aRv.Failed()) {
+        return;
       }
     }
+
+    else if (data.IsArrayBufferView()) {
+      const ArrayBufferView& buffer = data.GetAsArrayBufferView();
+      buffer.ComputeLengthAndData();
+      aRv = blobSet.AppendVoidPtr(buffer.Data(), buffer.Length());
+      if (aRv.Failed()) {
+        return;
+      }
+    }
+
+    else {
+      MOZ_CRASH("Impossible blob data type.");
+    }
   }
 
-  return InitChromeFile(aCx, aArgs.length(), aArgs.array());
-}
-
-nsresult
-DOMMultipartFileImpl::InitBlob(JSContext* aCx,
-                               uint32_t aArgc,
-                               JS::Value* aArgv,
-                               UnwrapFuncPtr aUnwrapFunc)
-{
-  bool nativeEOL = false;
-  if (aArgc > 1) {
-    BlobPropertyBag d;
-    if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]))) {
-      return NS_ERROR_TYPE_ERR;
-    }
-    mContentType = d.mType;
-    nativeEOL = d.mEndings == EndingTypes::Native;
-  }
-
-  if (aArgc > 0) {
-    return ParseBlobArrayArgument(aCx, aArgv[0], nativeEOL, aUnwrapFunc);
-  }
-
-  SetLengthAndModifiedDate();
-
-  return NS_OK;
-}
-
-nsresult
-DOMMultipartFileImpl::ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
-                                             bool aNativeEOL,
-                                             UnwrapFuncPtr aUnwrapFunc)
-{
-  if (!aValue.isObject()) {
-    return NS_ERROR_TYPE_ERR; // We're not interested
-  }
-
-  JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
-  if (!JS_IsArrayObject(aCx, obj)) {
-    return NS_ERROR_TYPE_ERR; // We're not interested
-  }
-
-  BlobSet blobSet;
-
-  uint32_t length;
-  MOZ_ALWAYS_TRUE(JS_GetArrayLength(aCx, obj, &length));
-  for (uint32_t i = 0; i < length; ++i) {
-    JS::Rooted<JS::Value> element(aCx);
-    if (!JS_GetElement(aCx, obj, i, &element))
-      return NS_ERROR_TYPE_ERR;
-
-    if (element.isObject()) {
-      JS::Rooted<JSObject*> obj(aCx, &element.toObject());
-      nsCOMPtr<nsIDOMBlob> blob = aUnwrapFunc(aCx, obj);
-      if (blob) {
-        nsRefPtr<DOMFileImpl> blobImpl =
-          static_cast<DOMFile*>(blob.get())->Impl();
-
-        // Flatten so that multipart blobs will never nest
-        const nsTArray<nsRefPtr<DOMFileImpl>>* subBlobImpls =
-          blobImpl->GetSubBlobImpls();
-        if (subBlobImpls) {
-          blobSet.AppendBlobImpls(*subBlobImpls);
-        } else {
-          blobSet.AppendBlobImpl(blobImpl);
-        }
-        continue;
-      }
-      if (JS_IsArrayBufferViewObject(obj)) {
-        nsresult rv = blobSet.AppendVoidPtr(
-                                          JS_GetArrayBufferViewData(obj),
-                                          JS_GetArrayBufferViewByteLength(obj));
-        NS_ENSURE_SUCCESS(rv, rv);
-        continue;
-      }
-      if (JS_IsArrayBufferObject(obj)) {
-        nsresult rv = blobSet.AppendArrayBuffer(obj);
-        NS_ENSURE_SUCCESS(rv, rv);
-        continue;
-      }
-    }
-
-    // coerce it to a string
-    JSString* str = JS::ToString(aCx, element);
-    NS_ENSURE_TRUE(str, NS_ERROR_TYPE_ERR);
-
-    nsresult rv = blobSet.AppendString(str, aNativeEOL, aCx);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
 
   mBlobImpls = blobSet.GetBlobImpls();
-
   SetLengthAndModifiedDate();
-
-  return NS_OK;
 }
 
 void
 DOMMultipartFileImpl::SetLengthAndModifiedDate()
 {
   MOZ_ASSERT(mLength == UINT64_MAX);
   MOZ_ASSERT(mLastModificationDate == UINT64_MAX);
 
@@ -279,184 +191,169 @@ DOMMultipartFileImpl::SetLengthAndModifi
   for (uint32_t index = 0, count = mBlobImpls.Length(); index < count; index++) {
     nsRefPtr<DOMFileImpl>& blob = mBlobImpls[index];
 
 #ifdef DEBUG
     MOZ_ASSERT(!blob->IsSizeUnknown());
     MOZ_ASSERT(!blob->IsDateUnknown());
 #endif
 
-    uint64_t subBlobLength;
-    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetSize(&subBlobLength)));
+    ErrorResult error;
+    uint64_t subBlobLength = blob->GetSize(error);
+    MOZ_ALWAYS_TRUE(!error.Failed());
 
     MOZ_ASSERT(UINT64_MAX - subBlobLength >= totalLength);
     totalLength += subBlobLength;
   }
 
   mLength = totalLength;
 
   if (mIsFile) {
-    mLastModificationDate = PR_Now();
+    // We cannot use PR_Now() because bug 493756 and, for this reason:
+    //   var x = new Date(); var f = new File(...);
+    //   x.getTime() < f.dateModified.getTime()
+    // could fail.
+    mLastModificationDate = JS_Now();
   }
 }
 
-nsresult
-DOMMultipartFileImpl::GetMozFullPathInternal(nsAString& aFilename)
+void
+DOMMultipartFileImpl::GetMozFullPathInternal(nsAString& aFilename,
+                                             ErrorResult& aRv)
 {
-  if (!mIsFromNsiFile || mBlobImpls.Length() == 0) {
-    return DOMFileImplBase::GetMozFullPathInternal(aFilename);
+  if (!mIsFromNsIFile || mBlobImpls.Length() == 0) {
+    DOMFileImplBase::GetMozFullPathInternal(aFilename, aRv);
+    return;
   }
 
   DOMFileImpl* blobImpl = mBlobImpls.ElementAt(0).get();
   if (!blobImpl) {
-    return DOMFileImplBase::GetMozFullPathInternal(aFilename);
+    DOMFileImplBase::GetMozFullPathInternal(aFilename, aRv);
+    return;
   }
 
-  return blobImpl->GetMozFullPathInternal(aFilename);
+  blobImpl->GetMozFullPathInternal(aFilename, aRv);
 }
 
-nsresult
-DOMMultipartFileImpl::InitChromeFile(JSContext* aCx,
-                                     uint32_t aArgc,
-                                     JS::Value* aArgv)
+void
+DOMMultipartFileImpl::InitializeChromeFile(DOMFile& aBlob,
+                                           const FilePropertyBag& aBag,
+                                           ErrorResult& aRv)
 {
-  nsresult rv;
+  NS_ASSERTION(!mImmutable, "Something went wrong ...");
 
-  NS_ASSERTION(!mImmutable, "Something went wrong ...");
-  NS_ENSURE_TRUE(!mImmutable, NS_ERROR_UNEXPECTED);
+  if (mImmutable) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+
   MOZ_ASSERT(nsContentUtils::IsCallerChrome());
-  NS_ENSURE_TRUE(aArgc > 0, NS_ERROR_UNEXPECTED);
 
-  if (aArgc > 1) {
-    FilePropertyBag d;
-    if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]))) {
-      return NS_ERROR_TYPE_ERR;
-    }
-    mName = d.mName;
-    mContentType = d.mType;
+  mName = aBag.mName;
+  mContentType = aBag.mType;
+  mIsFromNsIFile = true;
+
+  // XXXkhuey this is terrible
+  if (mContentType.IsEmpty()) {
+    aBlob.GetType(mContentType);
   }
 
 
-  // We expect to get a path to represent as a File object or
-  // Blob object, an nsIFile, or an nsIDOMFile.
-  nsCOMPtr<nsIFile> file;
-  nsCOMPtr<nsIDOMBlob> blob;
-  if (!aArgv[0].isString()) {
-    // Lets see if it's an nsIFile
-    if (!aArgv[0].isObject()) {
-      return NS_ERROR_UNEXPECTED; // We're not interested
-    }
+  BlobSet blobSet;
+  blobSet.AppendBlobImpl(aBlob.Impl());
+  mBlobImpls = blobSet.GetBlobImpls();
 
-    JSObject* obj = &aArgv[0].toObject();
-
-    nsISupports* supports =
-      nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, obj);
-    if (!supports) {
-      return NS_ERROR_UNEXPECTED;
-    }
+  SetLengthAndModifiedDate();
+}
 
-    blob = do_QueryInterface(supports);
-    file = do_QueryInterface(supports);
-    if (!blob && !file) {
-      return NS_ERROR_UNEXPECTED;
-    }
+void
+DOMMultipartFileImpl::InitializeChromeFile(nsPIDOMWindow* aWindow,
+                                           nsIFile* aFile,
+                                           const FilePropertyBag& aBag,
+                                           bool aIsFromNsIFile,
+                                           ErrorResult& aRv)
+{
+  NS_ASSERTION(!mImmutable, "Something went wrong ...");
+  if (mImmutable) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
 
-    mIsFromNsiFile = true;
-  } else {
-    // It's a string
-    JSString* str = JS::ToString(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[0]));
-    NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS);
+  MOZ_ASSERT(nsContentUtils::IsCallerChrome());
 
-    nsAutoJSString xpcomStr;
-    if (!xpcomStr.init(aCx, str)) {
-      return NS_ERROR_XPC_BAD_CONVERT_JS;
-    }
+  mName = aBag.mName;
+  mContentType = aBag.mType;
+  mIsFromNsIFile = aIsFromNsIFile;
 
-    rv = NS_NewLocalFile(xpcomStr, false, getter_AddRefs(file));
-    NS_ENSURE_SUCCESS(rv, rv);
+  bool exists;
+  aRv = aFile->Exists(&exists);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
   }
 
-  if (file) {
-    bool exists;
-    rv = file->Exists(&exists);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(exists, NS_ERROR_FILE_NOT_FOUND);
+  if (!exists) {
+    aRv.Throw(NS_ERROR_FILE_NOT_FOUND);
+    return;
+  }
 
-    bool isDir;
-    rv = file->IsDirectory(&isDir);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_FALSE(isDir, NS_ERROR_FILE_IS_DIRECTORY);
+  bool isDir;
+  aRv = aFile->IsDirectory(&isDir);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  if (isDir) {
+    aRv.Throw(NS_ERROR_FILE_IS_DIRECTORY);
+    return;
+  }
 
-    if (mName.IsEmpty()) {
-      file->GetLeafName(mName);
-    }
+  if (mName.IsEmpty()) {
+    aFile->GetLeafName(mName);
+  }
 
-    nsRefPtr<DOMFile> domFile = DOMFile::CreateFromFile(file);
+  nsRefPtr<DOMFile> blob = DOMFile::CreateFromFile(aWindow, aFile);
 
-    // Pre-cache size.
-    uint64_t unused;
-    rv = domFile->GetSize(&unused);
-    NS_ENSURE_SUCCESS(rv, rv);
+  // Pre-cache size.
+  uint64_t unused;
+  aRv = blob->GetSize(&unused);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
 
-    // Pre-cache modified date.
-    rv = domFile->GetMozLastModifiedDate(&unused);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    blob = domFile.forget();
+  // Pre-cache modified date.
+  aRv = blob->GetMozLastModifiedDate(&unused);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
   }
 
   // XXXkhuey this is terrible
   if (mContentType.IsEmpty()) {
     blob->GetType(mContentType);
   }
 
   BlobSet blobSet;
   blobSet.AppendBlobImpl(static_cast<DOMFile*>(blob.get())->Impl());
   mBlobImpls = blobSet.GetBlobImpls();
 
   SetLengthAndModifiedDate();
-
-  return NS_OK;
 }
 
-nsresult
-DOMMultipartFileImpl::InitFile(JSContext* aCx,
-                               uint32_t aArgc,
-                               JS::Value* aArgv)
+void
+DOMMultipartFileImpl::InitializeChromeFile(nsPIDOMWindow* aWindow,
+                                           const nsAString& aData,
+                                           const FilePropertyBag& aBag,
+                                           ErrorResult& aRv)
 {
-  NS_ASSERTION(!mImmutable, "Something went wrong ...");
-  NS_ENSURE_TRUE(!mImmutable, NS_ERROR_UNEXPECTED);
-
-  if (aArgc < 2) {
-    return NS_ERROR_TYPE_ERR;
+  nsCOMPtr<nsIFile> file;
+  aRv = NS_NewLocalFile(aData, false, getter_AddRefs(file));
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
   }
 
-  // File name
-  JSString* str = JS::ToString(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]));
-  NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS);
-
-  nsAutoJSString xpcomStr;
-  if (!xpcomStr.init(aCx, str)) {
-    return NS_ERROR_XPC_BAD_CONVERT_JS;
-  }
-
-  mName = xpcomStr;
-
-  // Optional params
-  bool nativeEOL = false;
-  if (aArgc > 2) {
-    BlobPropertyBag d;
-    if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[2]))) {
-      return NS_ERROR_TYPE_ERR;
-    }
-    mContentType = d.mType;
-    nativeEOL = d.mEndings == EndingTypes::Native;
-  }
-
-  return ParseBlobArrayArgument(aCx, aArgv[0], nativeEOL, GetXPConnectNative);
+  InitializeChromeFile(aWindow, file, aBag, false, aRv);
 }
 
 nsresult
 BlobSet::AppendVoidPtr(const void* aData, uint32_t aLength)
 {
   NS_ENSURE_ARG_POINTER(aData);
 
   uint64_t offset = mDataLen;
@@ -464,26 +361,21 @@ BlobSet::AppendVoidPtr(const void* aData
   if (!ExpandBufferSize(aLength))
     return NS_ERROR_OUT_OF_MEMORY;
 
   memcpy((char*)mData + offset, aData, aLength);
   return NS_OK;
 }
 
 nsresult
-BlobSet::AppendString(JSString* aString, bool nativeEOL, JSContext* aCx)
+BlobSet::AppendString(const nsAString& aString, bool aNativeEOL, JSContext* aCx)
 {
-  nsAutoJSString xpcomStr;
-  if (!xpcomStr.init(aCx, aString)) {
-    return NS_ERROR_XPC_BAD_CONVERT_JS;
-  }
+  NS_ConvertUTF16toUTF8 utf8Str(aString);
 
-  nsCString utf8Str = NS_ConvertUTF16toUTF8(xpcomStr);
-
-  if (nativeEOL) {
+  if (aNativeEOL) {
     if (utf8Str.FindChar('\r') != kNotFound) {
       utf8Str.ReplaceSubstring("\r\n", "\n");
       utf8Str.ReplaceSubstring("\r", "\n");
     }
 #ifdef XP_WIN
     utf8Str.ReplaceSubstring("\n", "\r\n");
 #endif
   }
@@ -506,15 +398,8 @@ BlobSet::AppendBlobImpl(DOMFileImpl* aBl
 nsresult
 BlobSet::AppendBlobImpls(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls)
 {
   Flush();
   mBlobImpls.AppendElements(aBlobImpls);
 
   return NS_OK;
 }
-
-nsresult
-BlobSet::AppendArrayBuffer(JSObject* aBuffer)
-{
-  return AppendVoidPtr(JS_GetArrayBufferData(aBuffer),
-                       JS_GetArrayBufferByteLength(aBuffer));
-}
--- a/content/base/src/nsDOMBlobBuilder.h
+++ b/content/base/src/nsDOMBlobBuilder.h
@@ -3,150 +3,151 @@
  * 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 nsDOMBlobBuilder_h
 #define nsDOMBlobBuilder_h
 
 #include "nsDOMFile.h"
 
+#include "mozilla/Attributes.h"
 #include "mozilla/CheckedInt.h"
-#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/BlobBinding.h"
+#include "mozilla/dom/FileBinding.h"
 #include <algorithm>
 
-#define NS_DOMMULTIPARTBLOB_CID { 0x47bf0b43, 0xf37e, 0x49ef, \
-  { 0x81, 0xa0, 0x18, 0xba, 0xc0, 0x57, 0xb5, 0xcc } }
-#define NS_DOMMULTIPARTBLOB_CONTRACTID "@mozilla.org/dom/multipart-blob;1"
-
-#define NS_DOMMULTIPARTFILE_CID { 0xc3361f77, 0x60d1, 0x4ea9, \
-  { 0x94, 0x96, 0xdf, 0x5d, 0x6f, 0xcd, 0xd7, 0x8f } }
-#define NS_DOMMULTIPARTFILE_CONTRACTID "@mozilla.org/dom/multipart-file;1"
-
+using namespace mozilla;
 using namespace mozilla::dom;
 
 class DOMMultipartFileImpl MOZ_FINAL : public DOMFileImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // Create as a file
   DOMMultipartFileImpl(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls,
                        const nsAString& aName,
                        const nsAString& aContentType)
     : DOMFileImplBase(aName, aContentType, UINT64_MAX),
       mBlobImpls(aBlobImpls),
-      mIsFromNsiFile(false)
+      mIsFromNsIFile(false)
   {
     SetLengthAndModifiedDate();
   }
 
   // Create as a blob
   DOMMultipartFileImpl(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls,
                        const nsAString& aContentType)
     : DOMFileImplBase(aContentType, UINT64_MAX),
       mBlobImpls(aBlobImpls),
-      mIsFromNsiFile(false)
+      mIsFromNsIFile(false)
   {
     SetLengthAndModifiedDate();
   }
 
   // Create as a file to be later initialized
   explicit DOMMultipartFileImpl(const nsAString& aName)
     : DOMFileImplBase(aName, EmptyString(), UINT64_MAX),
-      mIsFromNsiFile(false)
+      mIsFromNsIFile(false)
   {
   }
 
   // Create as a blob to be later initialized
   DOMMultipartFileImpl()
     : DOMFileImplBase(EmptyString(), UINT64_MAX),
-      mIsFromNsiFile(false)
+      mIsFromNsIFile(false)
   {
   }
 
-  virtual nsresult
-  Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
-             const JS::CallArgs& aArgs) MOZ_OVERRIDE;
+  void InitializeBlob();
+
+  void InitializeBlob(
+       JSContext* aCx,
+       const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+       const nsAString& aContentType,
+       bool aNativeEOL,
+       ErrorResult& aRv);
 
-  typedef nsIDOMBlob* (*UnwrapFuncPtr)(JSContext*, JSObject*);
-  nsresult InitBlob(JSContext* aCx,
-                    uint32_t aArgc,
-                    JS::Value* aArgv,
-                    UnwrapFuncPtr aUnwrapFunc);
-  nsresult InitFile(JSContext* aCx,
-                    uint32_t aArgc,
-                    JS::Value* aArgv);
-  nsresult InitChromeFile(JSContext* aCx,
-                          uint32_t aArgc,
-                          JS::Value* aArgv);
+  void InitializeChromeFile(DOMFile& aData,
+                            const FilePropertyBag& aBag,
+                            ErrorResult& aRv);
+
+  void InitializeChromeFile(nsPIDOMWindow* aWindow,
+                            const nsAString& aData,
+                            const FilePropertyBag& aBag,
+                            ErrorResult& aRv);
+
+  void InitializeChromeFile(nsPIDOMWindow* aWindow,
+                            nsIFile* aData,
+                            const FilePropertyBag& aBag,
+                            bool aIsFromNsIFile,
+                            ErrorResult& aRv);
 
   virtual already_AddRefed<DOMFileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType,
+              ErrorResult& aRv) MOZ_OVERRIDE;
 
-  virtual nsresult GetSize(uint64_t* aSize) MOZ_OVERRIDE;
+  virtual uint64_t GetSize(ErrorResult& aRv) MOZ_OVERRIDE
+  {
+    return mLength;
+  }
 
   virtual nsresult GetInternalStream(nsIInputStream** aInputStream) MOZ_OVERRIDE;
 
-  static nsresult NewFile(const nsAString& aName, nsISupports** aNewObject);
-
-  // DOMClassInfo constructor (for Blob([b1, "foo"], { type: "image/png" }))
-  static nsresult NewBlob(nsISupports* *aNewObject);
-
-  // DOMClassInfo constructor (for File([b1, "foo"], { type: "image/png",
-  //                                                   name: "foo.png" }))
-  inline static nsresult NewFile(nsISupports** aNewObject)
-  {
-    // Initialization will set the filename, so we can pass in an empty string
-    // for now.
-    return NewFile(EmptyString(), aNewObject);
-  }
-
   virtual const nsTArray<nsRefPtr<DOMFileImpl>>* GetSubBlobImpls() const MOZ_OVERRIDE
   {
     return &mBlobImpls;
   }
 
-  virtual nsresult GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
+  virtual void GetMozFullPathInternal(nsAString& aFullPath,
+                                      ErrorResult& aRv) MOZ_OVERRIDE;
+
+  void SetName(const nsAString& aName)
+  {
+    mName = aName;
+  }
+
+  void SetFromNsIFile(bool aValue)
+  {
+    mIsFromNsIFile = aValue;
+  }
 
 protected:
   virtual ~DOMMultipartFileImpl() {}
 
-  nsresult ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
-                                  bool aNativeEOL, UnwrapFuncPtr aUnwrapFunc);
-
   void SetLengthAndModifiedDate();
 
   nsTArray<nsRefPtr<DOMFileImpl>> mBlobImpls;
-  bool mIsFromNsiFile;
+  bool mIsFromNsIFile;
 };
 
 class BlobSet {
 public:
   BlobSet()
     : mData(nullptr), mDataLen(0), mDataBufferLen(0)
   {}
 
   ~BlobSet()
   {
     moz_free(mData);
   }
 
   nsresult AppendVoidPtr(const void* aData, uint32_t aLength);
-  nsresult AppendString(JSString* aString, bool nativeEOL, JSContext* aCx);
+  nsresult AppendString(const nsAString& aString, bool nativeEOL, JSContext* aCx);
   nsresult AppendBlobImpl(DOMFileImpl* aBlobImpl);
-  nsresult AppendArrayBuffer(JSObject* aBuffer);
   nsresult AppendBlobImpls(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls);
 
   nsTArray<nsRefPtr<DOMFileImpl>>& GetBlobImpls() { Flush(); return mBlobImpls; }
 
-  already_AddRefed<nsIDOMBlob>
-  GetBlobInternal(const nsACString& aContentType)
+  already_AddRefed<DOMFile>
+  GetBlobInternal(nsISupports* aParent, const nsACString& aContentType)
   {
-    nsCOMPtr<nsIDOMBlob> blob = new DOMFile(
+    nsRefPtr<DOMFile> blob = new DOMFile(aParent,
       new DOMMultipartFileImpl(GetBlobImpls(), NS_ConvertASCIItoUTF16(aContentType)));
     return blob.forget();
   }
 
 protected:
   bool ExpandBufferSize(uint64_t aSize)
   {
     using mozilla::CheckedUint32;
--- a/content/base/src/nsDOMDataChannel.cpp
+++ b/content/base/src/nsDOMDataChannel.cpp
@@ -17,17 +17,17 @@
 extern PRLogModuleInfo* GetDataChannelLog();
 #endif
 #undef LOG
 #define LOG(args) PR_LOG(GetDataChannelLog(), PR_LOG_DEBUG, args)
 
 
 #include "nsDOMDataChannelDeclarations.h"
 #include "nsDOMDataChannel.h"
-#include "nsIDOMFile.h"
+#include "nsDOMFile.h"
 #include "nsIDOMDataChannel.h"
 #include "nsIDOMMessageEvent.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 #include "nsError.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
@@ -267,29 +267,29 @@ nsDOMDataChannel::Close()
 void
 nsDOMDataChannel::Send(const nsAString& aData, ErrorResult& aRv)
 {
   NS_ConvertUTF16toUTF8 msgString(aData);
   Send(nullptr, msgString, msgString.Length(), false, aRv);
 }
 
 void
-nsDOMDataChannel::Send(nsIDOMBlob* aData, ErrorResult& aRv)
+nsDOMDataChannel::Send(DOMFile& aData, ErrorResult& aRv)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   nsCOMPtr<nsIInputStream> msgStream;
-  nsresult rv = aData->GetInternalStream(getter_AddRefs(msgStream));
+  nsresult rv = aData.GetInternalStream(getter_AddRefs(msgStream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   uint64_t msgLength;
-  rv = aData->GetSize(&msgLength);
+  rv = aData.GetSize(&msgLength);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   if (msgLength > UINT32_MAX) {
     aRv.Throw(NS_ERROR_FILE_TOO_BIG);
     return;
@@ -388,17 +388,17 @@ nsDOMDataChannel::DoOnMessageAvailable(c
     return NS_ERROR_FAILURE;
   }
   JSContext* cx = jsapi.cx();
 
   JS::Rooted<JS::Value> jsData(cx);
 
   if (aBinary) {
     if (mBinaryType == DC_BINARY_TYPE_BLOB) {
-      rv = nsContentUtils::CreateBlobBuffer(cx, aData, &jsData);
+      rv = nsContentUtils::CreateBlobBuffer(cx, GetOwner(), aData, &jsData);
       NS_ENSURE_SUCCESS(rv, rv);
     } else if (mBinaryType == DC_BINARY_TYPE_ARRAYBUFFER) {
       JS::Rooted<JSObject*> arrayBuf(cx);
       rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
       NS_ENSURE_SUCCESS(rv, rv);
       jsData = OBJECT_TO_JSVAL(arrayBuf);
     } else {
       NS_RUNTIMEABORT("Unknown binary type!");
--- a/content/base/src/nsDOMDataChannel.h
+++ b/content/base/src/nsDOMDataChannel.h
@@ -12,16 +12,20 @@
 #include "mozilla/dom/DataChannelBinding.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/net/DataChannelListener.h"
 #include "nsIDOMDataChannel.h"
 #include "nsIInputStream.h"
 
 
 namespace mozilla {
+namespace dom {
+class DOMFile;
+}
+
 class DataChannel;
 };
 
 class nsDOMDataChannel : public mozilla::DOMEventTargetHelper,
                          public nsIDOMDataChannel,
                          public mozilla::DataChannelListener
 {
 public:
@@ -61,17 +65,17 @@ public:
       static_cast<int>(mBinaryType));
   }
   void SetBinaryType(mozilla::dom::RTCDataChannelType aType)
   {
     mBinaryType = static_cast<DataChannelBinaryType>(
       static_cast<int>(aType));
   }
   void Send(const nsAString& aData, mozilla::ErrorResult& aRv);
-  void Send(nsIDOMBlob* aData, mozilla::ErrorResult& aRv);
+  void Send(mozilla::dom::DOMFile& aData, mozilla::ErrorResult& aRv);
   void Send(const mozilla::dom::ArrayBuffer& aData, mozilla::ErrorResult& aRv);
   void Send(const mozilla::dom::ArrayBufferView& aData,
             mozilla::ErrorResult& aRv);
 
   // Uses XPIDL GetProtocol.
   bool Ordered() const;
   uint16_t Id() const;
   uint16_t Stream() const; // deprecated
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -4,20 +4,19 @@
  * 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 "nsDOMFile.h"
 
 #include "nsCExternalHandlerService.h"
 #include "nsContentCID.h"
 #include "nsContentUtils.h"
-#include "nsDOMClassInfoID.h"
+#include "nsDOMBlobBuilder.h"
 #include "nsError.h"
 #include "nsICharsetDetector.h"
-#include "nsIClassInfo.h"
 #include "nsIConverterInputStream.h"
 #include "nsIDocument.h"
 #include "nsIFileStreams.h"
 #include "nsIInputStream.h"
 #include "nsIIPCSerializableInputStream.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMIMEService.h"
 #include "nsISeekableStream.h"
@@ -30,23 +29,24 @@
 #include "nsHostObjectProtocolHandler.h"
 #include "nsStringStream.h"
 #include "nsJSUtils.h"
 #include "nsPrintfCString.h"
 #include "mozilla/SHA1.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/BlobBinding.h"
+#include "mozilla/dom/DOMError.h"
+#include "mozilla/dom/FileBinding.h"
+#include "mozilla/dom/WorkerPrivate.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/dom/FileListBinding.h"
 
-DOMCI_DATA(File, mozilla::dom::DOMFile)
-DOMCI_DATA(Blob, mozilla::dom::DOMFile)
-
 namespace mozilla {
 namespace dom {
 
 // XXXkhuey the input stream that we pass out of a DOMFile
 // can outlive the actual DOMFile object.  Thus, we must
 // ensure that the buffer underlying the stream we get
 // from NS_NewByteInputStream is held alive as long as the
 // stream is.  We do that by passing back this class instead.
@@ -125,150 +125,178 @@ nsresult DataOwnerAdapter::Create(DataOw
 ////////////////////////////////////////////////////////////////////////////
 // mozilla::dom::DOMFile implementation
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMFile)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMFile)
   MOZ_ASSERT(tmp->mImpl);
   tmp->mImpl->Unlink();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMFile)
   MOZ_ASSERT(tmp->mImpl);
   tmp->mImpl->Traverse(cb);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMFile)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMFile)
   // This class should not receive any nsIRemoteBlob QI!
   MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsIRemoteBlob)));
 
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, IsFile())
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY(nsIMutable)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, IsFile())
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !(IsFile()))
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMFile)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMFile)
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::Create(const nsAString& aName, const nsAString& aContentType,
-                uint64_t aLength, uint64_t aLastModifiedDate)
+DOMFile::Create(nsISupports* aParent, const nsAString& aName,
+                const nsAString& aContentType, uint64_t aLength,
+                uint64_t aLastModifiedDate)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
+  nsRefPtr<DOMFile> file = new DOMFile(aParent,
     new DOMFileImplBase(aName, aContentType, aLength, aLastModifiedDate));
   return file.forget();
 }
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::Create(const nsAString& aName, const nsAString& aContentType,
-                uint64_t aLength)
+DOMFile::Create(nsISupports* aParent, const nsAString& aName,
+                const nsAString& aContentType, uint64_t aLength)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
+  nsRefPtr<DOMFile> file = new DOMFile(aParent,
     new DOMFileImplBase(aName, aContentType, aLength));
   return file.forget();
 }
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::Create(const nsAString& aContentType, uint64_t aLength)
+DOMFile::Create(nsISupports* aParent, const nsAString& aContentType,
+                uint64_t aLength)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
+  nsRefPtr<DOMFile> file = new DOMFile(aParent,
     new DOMFileImplBase(aContentType, aLength));
   return file.forget();
 }
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::Create(const nsAString& aContentType, uint64_t aStart,
-                uint64_t aLength)
+DOMFile::Create(nsISupports* aParent, const nsAString& aContentType,
+                uint64_t aStart, uint64_t aLength)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
+  nsRefPtr<DOMFile> file = new DOMFile(aParent,
     new DOMFileImplBase(aContentType, aStart, aLength));
   return file.forget();
 }
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
-                          const nsAString& aName,
+DOMFile::CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer,
+                          uint64_t aLength, const nsAString& aName,
                           const nsAString& aContentType,
                           uint64_t aLastModifiedDate)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
+  nsRefPtr<DOMFile> file = new DOMFile(aParent,
     new DOMFileImplMemory(aMemoryBuffer, aLength, aName,
                           aContentType, aLastModifiedDate));
   return file.forget();
 }
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
-                          const nsAString& aContentType)
+DOMFile::CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer,
+                          uint64_t aLength, const nsAString& aContentType)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
+  nsRefPtr<DOMFile> file = new DOMFile(aParent,
     new DOMFileImplMemory(aMemoryBuffer, aLength, aContentType));
   return file.forget();
 }
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::CreateTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos,
-                                 uint64_t aLength,
-                                      const nsAString& aContentType)
+DOMFile::CreateTemporaryFileBlob(nsISupports* aParent, PRFileDesc* aFD,
+                                 uint64_t aStartPos, uint64_t aLength,
+                                 const nsAString& aContentType)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
+  nsRefPtr<DOMFile> file = new DOMFile(aParent,
     new DOMFileImplTemporaryFileBlob(aFD, aStartPos, aLength, aContentType));
   return file.forget();
 }
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::CreateFromFile(nsIFile* aFile)
+DOMFile::CreateFromFile(nsISupports* aParent, nsIFile* aFile)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(new DOMFileImplFile(aFile));
+  nsRefPtr<DOMFile> file = new DOMFile(aParent, new DOMFileImplFile(aFile));
   return file.forget();
 }
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::CreateFromFile(const nsAString& aContentType, uint64_t aLength,
-                        nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
+DOMFile::CreateFromFile(nsISupports* aParent, const nsAString& aContentType,
+                        uint64_t aLength, nsIFile* aFile,
+                        indexedDB::FileInfo* aFileInfo)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
+  nsRefPtr<DOMFile> file = new DOMFile(aParent,
     new DOMFileImplFile(aContentType, aLength, aFile, aFileInfo));
   return file.forget();
 }
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::CreateFromFile(const nsAString& aName,
+DOMFile::CreateFromFile(nsISupports* aParent, const nsAString& aName,
                         const nsAString& aContentType,
                         uint64_t aLength, nsIFile* aFile,
                         indexedDB::FileInfo* aFileInfo)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
+  nsRefPtr<DOMFile> file = new DOMFile(aParent,
     new DOMFileImplFile(aName, aContentType, aLength, aFile, aFileInfo));
   return file.forget();
 }
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::CreateFromFile(nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
+DOMFile::CreateFromFile(nsISupports* aParent, nsIFile* aFile,
+                        indexedDB::FileInfo* aFileInfo)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(new DOMFileImplFile(aFile, aFileInfo));
+  nsRefPtr<DOMFile> file = new DOMFile(aParent,
+    new DOMFileImplFile(aFile, aFileInfo));
   return file.forget();
 }
 
 /* static */ already_AddRefed<DOMFile>
-DOMFile::CreateFromFile(nsIFile* aFile, const nsAString& aName,
-                        const nsAString& aContentType)
+DOMFile::CreateFromFile(nsISupports* aParent, nsIFile* aFile,
+                        const nsAString& aName, const nsAString& aContentType)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
+  nsRefPtr<DOMFile> file = new DOMFile(aParent,
     new DOMFileImplFile(aFile, aName, aContentType));
   return file.forget();
 }
 
+DOMFile::DOMFile(nsISupports* aParent, DOMFileImpl* aImpl)
+  : mImpl(aImpl)
+  , mParent(aParent)
+{
+  MOZ_ASSERT(mImpl);
+  SetIsDOMBinding();
+
+#ifdef DEBUG
+  {
+    nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aParent);
+    if (win) {
+      MOZ_ASSERT(win->IsInnerWindow());
+    }
+  }
+#endif
+}
+
 const nsTArray<nsRefPtr<DOMFileImpl>>*
 DOMFile::GetSubBlobImpls() const
 {
   return mImpl->GetSubBlobImpls();
 }
 
 bool
 DOMFile::IsSizeUnknown() const
@@ -290,80 +318,131 @@ DOMFile::IsFile() const
 
 void
 DOMFile::SetLazyData(const nsAString& aName, const nsAString& aContentType,
                      uint64_t aLength, uint64_t aLastModifiedDate)
 {
   return mImpl->SetLazyData(aName, aContentType, aLength, aLastModifiedDate);
 }
 
-already_AddRefed<nsIDOMBlob>
+already_AddRefed<DOMFile>
 DOMFile::CreateSlice(uint64_t aStart, uint64_t aLength,
-                     const nsAString& aContentType)
+                     const nsAString& aContentType,
+                     ErrorResult& aRv)
 {
-  nsRefPtr<DOMFileImpl> impl =
-    mImpl->CreateSlice(aStart, aLength, aContentType);
-  nsRefPtr<DOMFile> slice = new DOMFile(impl);
-  return slice.forget();
-}
+  nsRefPtr<DOMFileImpl> impl = mImpl->CreateSlice(aStart, aLength,
+                                                  aContentType, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
 
-NS_IMETHODIMP
-DOMFile::Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
-                    const JS::CallArgs& aArgs)
-{
-  return mImpl->Initialize(aOwner, aCx, aObj, aArgs);
+  nsRefPtr<DOMFile> file = new DOMFile(mParent, impl);
+  return file.forget();
 }
 
 NS_IMETHODIMP
 DOMFile::GetName(nsAString& aFileName)
 {
-  return mImpl->GetName(aFileName);
+  mImpl->GetName(aFileName);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMFile::GetPath(nsAString& aPath)
 {
   return mImpl->GetPath(aPath);
 }
 
 NS_IMETHODIMP
 DOMFile::GetLastModifiedDate(JSContext* aCx,
                              JS::MutableHandle<JS::Value> aDate)
 {
-  return mImpl->GetLastModifiedDate(aCx, aDate);
+  ErrorResult rv;
+  Date value = GetLastModifiedDate(rv);
+  if (rv.Failed()) {
+    return rv.ErrorCode();
+  }
+
+  if (!value.ToDateObject(aCx, aDate)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  return NS_OK;
+}
+
+Date
+DOMFile::GetLastModifiedDate(ErrorResult& aRv)
+{
+  int64_t value = GetLastModified(aRv);
+  if (aRv.Failed()) {
+    return Date();
+  }
+
+  return Date(value);
+}
+
+int64_t
+DOMFile::GetLastModified(ErrorResult& aRv)
+{
+  return mImpl->GetLastModified(aRv);
 }
 
 NS_IMETHODIMP
-DOMFile::GetMozFullPath(nsAString &aFileName)
+DOMFile::GetMozFullPath(nsAString& aFileName)
 {
-  return mImpl->GetMozFullPath(aFileName);
+  ErrorResult rv;
+  GetMozFullPath(aFileName, rv);
+  return rv.ErrorCode();
+}
+
+void
+DOMFile::GetMozFullPath(nsAString& aFilename, ErrorResult& aRv)
+{
+  mImpl->GetMozFullPath(aFilename, aRv);
 }
 
 NS_IMETHODIMP
-DOMFile::GetMozFullPathInternal(nsAString &aFileName)
+DOMFile::GetMozFullPathInternal(nsAString& aFileName)
 {
-  return mImpl->GetMozFullPathInternal(aFileName);
+  ErrorResult rv;
+  mImpl->GetMozFullPathInternal(aFileName, rv);
+  return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 DOMFile::GetSize(uint64_t* aSize)
 {
-  return mImpl->GetSize(aSize);
+  MOZ_ASSERT(aSize);
+
+  ErrorResult rv;
+  *aSize = GetSize(rv);
+  return rv.ErrorCode();
+}
+
+uint64_t
+DOMFile::GetSize(ErrorResult& aRv)
+{
+  return mImpl->GetSize(aRv);
 }
 
 NS_IMETHODIMP
 DOMFile::GetType(nsAString &aType)
 {
-  return mImpl->GetType(aType);
+  mImpl->GetType(aType);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMFile::GetMozLastModifiedDate(uint64_t* aDate)
 {
-  return mImpl->GetMozLastModifiedDate(aDate);
+  MOZ_ASSERT(aDate);
+
+  ErrorResult rv;
+  *aDate = GetLastModified(rv);
+  return rv.ErrorCode();
 }
 
 // Makes sure that aStart and aEnd is less then or equal to aSize and greater
 // than 0
 static void
 ParseSize(int64_t aSize, int64_t& aStart, int64_t& aEnd)
 {
   CheckedInt64 newStartOffset = aStart;
@@ -398,28 +477,50 @@ ParseSize(int64_t aSize, int64_t& aStart
   }
 }
 
 NS_IMETHODIMP
 DOMFile::Slice(int64_t aStart, int64_t aEnd,
                const nsAString& aContentType, uint8_t aArgc,
                nsIDOMBlob **aBlob)
 {
-  MOZ_ASSERT(mImpl);
-  nsRefPtr<DOMFileImpl> impl;
-  nsresult rv = mImpl->Slice(aStart, aEnd, aContentType, aArgc,
-                             getter_AddRefs(impl));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+  Optional<int64_t> start;
+  if (aArgc > 0) {
+    start.Construct(aStart);
+  }
+
+  Optional<int64_t> end;
+  if (aArgc > 1) {
+    end.Construct(aEnd);
+  }
+
+  ErrorResult rv;
+  nsRefPtr<DOMFile> file = Slice(start, end, aContentType, rv);
+  if (rv.Failed()) {
+    return rv.ErrorCode();
   }
 
-  nsRefPtr<DOMFile> blob = new DOMFile(impl);
-  blob.forget(aBlob);
+  file.forget(aBlob);
+  return NS_OK;
+}
 
-  return NS_OK;
+already_AddRefed<DOMFile>
+DOMFile::Slice(const Optional<int64_t>& aStart,
+               const Optional<int64_t>& aEnd,
+               const nsAString& aContentType,
+               ErrorResult& aRv)
+{
+  nsRefPtr<DOMFileImpl> impl =
+    mImpl->Slice(aStart, aEnd, aContentType, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  nsRefPtr<DOMFile> file = new DOMFile(mParent, impl);
+  return file.forget();
 }
 
 NS_IMETHODIMP
 DOMFile::GetInternalStream(nsIInputStream** aStream)
 {
  return mImpl->GetInternalStream(aStream);
 }
 
@@ -463,151 +564,244 @@ DOMFile::SetMutable(bool aMutable)
 }
 
 NS_IMETHODIMP_(bool)
 DOMFile::IsMemoryFile()
 {
   return mImpl->IsMemoryFile();
 }
 
+JSObject*
+DOMFile::WrapObject(JSContext* aCx)
+{
+  return IsFile() ? FileBinding::Wrap(aCx, this)
+                  : BlobBinding::Wrap(aCx, this);
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  nsRefPtr<DOMMultipartFileImpl> impl = new DOMMultipartFileImpl();
+
+  impl->InitializeBlob();
+  MOZ_ASSERT(!impl->IsFile());
+
+  nsRefPtr<DOMFile> file = new DOMFile(aGlobal.GetAsSupports(), impl);
+  return file.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::Constructor(
+        const GlobalObject& aGlobal,
+        const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+        const BlobPropertyBag& aBag,
+        ErrorResult& aRv)
+{
+  nsRefPtr<DOMMultipartFileImpl> impl = new DOMMultipartFileImpl();
+
+  impl->InitializeBlob(aGlobal.Context(), aData, aBag.mType,
+                       aBag.mEndings == EndingTypes::Native, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+  MOZ_ASSERT(!impl->IsFile());
+
+  nsRefPtr<DOMFile> file = new DOMFile(aGlobal.GetAsSupports(), impl);
+  return file.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::Constructor(
+        const GlobalObject& aGlobal,
+        const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+        const nsAString& aName,
+        const FilePropertyBag& aBag,
+        ErrorResult& aRv)
+{
+  nsRefPtr<DOMMultipartFileImpl> impl = new DOMMultipartFileImpl(aName);
+
+  impl->InitializeBlob(aGlobal.Context(), aData, aBag.mType, false, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+  MOZ_ASSERT(impl->IsFile());
+
+  nsRefPtr<DOMFile> file = new DOMFile(aGlobal.GetAsSupports(), impl);
+  return file.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::Constructor(const GlobalObject& aGlobal,
+                     DOMFile& aData,
+                     const FilePropertyBag& aBag,
+                     ErrorResult& aRv)
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<DOMMultipartFileImpl> impl = new DOMMultipartFileImpl(EmptyString());
+  impl->InitializeChromeFile(aData, aBag, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+  MOZ_ASSERT(impl->IsFile());
+
+  nsRefPtr<DOMFile> domFile = new DOMFile(aGlobal.GetAsSupports(), impl);
+  return domFile.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::Constructor(const GlobalObject& aGlobal,
+                     nsIFile* aData,
+                     const FilePropertyBag& aBag,
+                     ErrorResult& aRv)
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+
+  nsRefPtr<DOMMultipartFileImpl> impl = new DOMMultipartFileImpl(EmptyString());
+  impl->InitializeChromeFile(window, aData, aBag, true, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+  MOZ_ASSERT(impl->IsFile());
+
+  nsRefPtr<DOMFile> domFile = new DOMFile(aGlobal.GetAsSupports(), impl);
+  return domFile.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::Constructor(const GlobalObject& aGlobal,
+                     const nsAString& aData,
+                     const FilePropertyBag& aBag,
+                     ErrorResult& aRv)
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+
+  nsRefPtr<DOMMultipartFileImpl> impl = new DOMMultipartFileImpl(EmptyString());
+  impl->InitializeChromeFile(window, aData, aBag, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+  MOZ_ASSERT(impl->IsFile());
+
+  nsRefPtr<DOMFile> domFile = new DOMFile(aGlobal.GetAsSupports(), impl);
+  return domFile.forget();
+}
+
 ////////////////////////////////////////////////////////////////////////////
 // mozilla::dom::DOMFileImpl implementation
 
-nsresult
-DOMFileImpl::Slice(int64_t aStart, int64_t aEnd,
-                   const nsAString& aContentType, uint8_t aArgc,
-                   DOMFileImpl** aBlobImpl)
+already_AddRefed<DOMFileImpl>
+DOMFileImpl::Slice(const Optional<int64_t>& aStart,
+                   const Optional<int64_t>& aEnd,
+                   const nsAString& aContentType,
+                   ErrorResult& aRv)
 {
-  *aBlobImpl = nullptr;
-
   // Truncate aStart and aEnd so that we stay within this file.
-  uint64_t thisLength;
-  nsresult rv = GetSize(&thisLength);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (aArgc < 2) {
-    aEnd = (int64_t)thisLength;
+  uint64_t thisLength = GetSize(aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
   }
 
-  ParseSize((int64_t)thisLength, aStart, aEnd);
-
-  nsRefPtr<DOMFileImpl> impl =
-    CreateSlice((uint64_t)aStart, (uint64_t)(aEnd - aStart), aContentType);
+  int64_t start = aStart.WasPassed() ? aStart.Value() : 0;
+  int64_t end = aEnd.WasPassed() ? aEnd.Value() : (int64_t)thisLength;
 
-  if (!impl) {
-    return NS_ERROR_UNEXPECTED;
-  }
+  ParseSize((int64_t)thisLength, start, end);
 
-  impl.forget(aBlobImpl);
-  return NS_OK;
+  return CreateSlice((uint64_t)start, (uint64_t)(end - start),
+                     aContentType, aRv);
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // DOMFileImpl implementation
 
 NS_IMPL_ISUPPORTS(DOMFileImpl, PIDOMFileImpl)
 
 ////////////////////////////////////////////////////////////////////////////
 // DOMFileImplFile implementation
 
 NS_IMPL_ISUPPORTS_INHERITED0(DOMFileImplFile, DOMFileImpl)
 
-nsresult
+void
 DOMFileImplBase::GetName(nsAString& aName)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   aName = mName;
-  return NS_OK;
 }
 
 nsresult
 DOMFileImplBase::GetPath(nsAString& aPath)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   aPath = mPath;
   return NS_OK;
 }
 
-nsresult
-DOMFileImplBase::GetLastModifiedDate(JSContext* aCx,
-                                     JS::MutableHandle<JS::Value> aDate)
-{
-  JS::Rooted<JSObject*> date(aCx, JS_NewDateObjectMsec(aCx, JS_Now() / PR_USEC_PER_MSEC));
-  if (!date) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  aDate.setObject(*date);
-  return NS_OK;
-}
-
-nsresult
-DOMFileImplBase::GetMozFullPath(nsAString &aFileName)
+void
+DOMFileImplBase::GetMozFullPath(nsAString& aFileName, ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
 
-  // It is unsafe to call IsCallerChrome on a non-main thread. If
-  // you hit the following assertion you need to figure out some other way to
-  // determine privileges and call GetMozFullPathInternal.
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  aFileName.Truncate();
+
+  if (NS_IsMainThread()) {
+    if (nsContentUtils::IsCallerChrome()) {
+      GetMozFullPathInternal(aFileName, aRv);
+    }
 
-  if (nsContentUtils::IsCallerChrome()) {
-    return GetMozFullPathInternal(aFileName);
+    return;
   }
-  aFileName.Truncate();
-  return NS_OK;
+
+  workers::WorkerPrivate* workerPrivate =
+    workers::GetCurrentThreadWorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
+
+  if (workerPrivate->UsesSystemPrincipal()) {
+    GetMozFullPathInternal(aFileName, aRv);
+  }
 }
 
-nsresult
-DOMFileImplBase::GetMozFullPathInternal(nsAString& aFileName)
+void
+DOMFileImplBase::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv)
 {
   if (!mIsFile) {
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
   }
 
   aFileName.Truncate();
-  return NS_OK;
 }
 
-nsresult
-DOMFileImplBase::GetSize(uint64_t* aSize)
-{
-  *aSize = mLength;
-  return NS_OK;
-}
-
-nsresult
+void
 DOMFileImplBase::GetType(nsAString& aType)
 {
   aType = mContentType;
-  return NS_OK;
 }
 
-nsresult
-DOMFileImplBase::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
+int64_t
+DOMFileImplBase::GetLastModified(ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   if (IsDateUnknown()) {
     mLastModificationDate = PR_Now();
   }
-  *aLastModifiedDate = mLastModificationDate;
-  return NS_OK;
-}
 
-already_AddRefed<DOMFileImpl>
-DOMFileImplBase::CreateSlice(uint64_t aStart, uint64_t aLength,
-                             const nsAString& aContentType)
-{
-  return nullptr;
-}
-
-nsresult
-DOMFileImplBase::GetInternalStream(nsIInputStream** aStream)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
+  return mLastModificationDate / PR_USEC_PER_MSEC;
 }
 
 int64_t
 DOMFileImplBase::GetFileId()
 {
   int64_t id = -1;
 
   if (IsStoredFile() && IsWholeFile() && !IsSnapshot()) {
@@ -683,28 +877,32 @@ DOMFileImplBase::GetFileInfo(indexedDB::
 }
 
 nsresult
 DOMFileImplBase::GetSendInfo(nsIInputStream** aBody,
                              uint64_t* aContentLength,
                              nsACString& aContentType,
                              nsACString& aCharset)
 {
+  MOZ_ASSERT(aContentLength);
+
   nsresult rv;
 
   nsCOMPtr<nsIInputStream> stream;
-  rv = this->GetInternalStream(getter_AddRefs(stream));
+  rv = GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = this->GetSize(aContentLength);
-  NS_ENSURE_SUCCESS(rv, rv);
+  ErrorResult error;
+  *aContentLength = GetSize(error);
+  if (NS_WARN_IF(error.Failed())) {
+    return error.ErrorCode();
+  }
 
-  nsString contentType;
-  rv = this->GetType(contentType);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsAutoString contentType;
+  GetType(contentType);
 
   CopyUTF16toUTF8(contentType, aContentType);
 
   aCharset.Truncate();
 
   stream.forget(aBody);
   return NS_OK;
 }
@@ -720,135 +918,115 @@ nsresult
 DOMFileImplBase::SetMutable(bool aMutable)
 {
   nsresult rv = NS_OK;
 
   NS_ENSURE_ARG(!mImmutable || !aMutable);
 
   if (!mImmutable && !aMutable) {
     // Force the content type and size to be cached
-    nsString dummyString;
-    rv = this->GetType(dummyString);
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsAutoString dummyString;
+    GetType(dummyString);
 
-    uint64_t dummyInt;
-    rv = this->GetSize(&dummyInt);
-    NS_ENSURE_SUCCESS(rv, rv);
+    ErrorResult error;
+    GetSize(error);
+    if (NS_WARN_IF(error.Failed())) {
+      return error.ErrorCode();
+    }
   }
 
   mImmutable = !aMutable;
   return rv;
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // DOMFileImplFile implementation
 
 already_AddRefed<DOMFileImpl>
 DOMFileImplFile::CreateSlice(uint64_t aStart, uint64_t aLength,
-                             const nsAString& aContentType)
+                             const nsAString& aContentType,
+                             ErrorResult& aRv)
 {
   nsRefPtr<DOMFileImpl> impl =
     new DOMFileImplFile(this, aStart, aLength, aContentType);
   return impl.forget();
 }
 
-nsresult
-DOMFileImplFile::GetMozFullPathInternal(nsAString& aFilename)
-{
-  NS_ASSERTION(mIsFile, "Should only be called on files");
-  return mFile->GetPath(aFilename);
-}
-
-nsresult
-DOMFileImplFile::GetLastModifiedDate(JSContext* aCx,
-                                     JS::MutableHandle<JS::Value> aLastModifiedDate)
+void
+DOMFileImplFile::GetMozFullPathInternal(nsAString& aFilename, ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
-
-  PRTime msecs;
-  if (IsDateUnknown()) {
-    nsresult rv = mFile->GetLastModifiedTime(&msecs);
-    NS_ENSURE_SUCCESS(rv, rv);
-    mLastModificationDate = msecs;
-  } else {
-    msecs = mLastModificationDate;
-  }
-
-  JSObject* date = JS_NewDateObjectMsec(aCx, msecs);
-  if (date) {
-    aLastModifiedDate.setObject(*date);
-  }
-  else {
-    date = JS_NewDateObjectMsec(aCx, JS_Now() / PR_USEC_PER_MSEC);
-    aLastModifiedDate.setObject(*date);
-  }
-
-  return NS_OK;
+  aRv = mFile->GetPath(aFilename);
 }
 
-nsresult
-DOMFileImplFile::GetSize(uint64_t* aFileSize)
+uint64_t
+DOMFileImplFile::GetSize(ErrorResult& aRv)
 {
   if (IsSizeUnknown()) {
     NS_ASSERTION(mWholeFile,
                  "Should only use lazy size when using the whole file");
     int64_t fileSize;
-    nsresult rv = mFile->GetFileSize(&fileSize);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aRv = mFile->GetFileSize(&fileSize);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return 0;
+    }
 
     if (fileSize < 0) {
-      return NS_ERROR_FAILURE;
+      aRv.Throw(NS_ERROR_FAILURE);
+      return 0;
     }
 
     mLength = fileSize;
   }
 
-  *aFileSize = mLength;
-
-  return NS_OK;
+  return mLength;
 }
 
-nsresult
+void
 DOMFileImplFile::GetType(nsAString& aType)
 {
   if (mContentType.IsVoid()) {
     NS_ASSERTION(mWholeFile,
                  "Should only use lazy ContentType when using the whole file");
     nsresult rv;
     nsCOMPtr<nsIMIMEService> mimeService =
       do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      aType.Truncate();
+      return;
+    }
 
     nsAutoCString mimeType;
     rv = mimeService->GetTypeFromFile(mFile, mimeType);
     if (NS_FAILED(rv)) {
       mimeType.Truncate();
     }
 
     AppendUTF8toUTF16(mimeType, mContentType);
     mContentType.SetIsVoid(false);
   }
 
   aType = mContentType;
-
-  return NS_OK;
 }
 
-nsresult
-DOMFileImplFile::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
+int64_t
+DOMFileImplFile::GetLastModified(ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   if (IsDateUnknown()) {
     PRTime msecs;
-    nsresult rv = mFile->GetLastModifiedTime(&msecs);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aRv = mFile->GetLastModifiedTime(&msecs);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return 0;
+    }
+
     mLastModificationDate = msecs;
   }
-  *aLastModifiedDate = mLastModificationDate;
-  return NS_OK;
+
+  return mLastModificationDate;
 }
 
 const uint32_t sFileStreamFlags =
   nsIFileInputStream::CLOSE_ON_EOF |
   nsIFileInputStream::REOPEN_ON_REWIND |
   nsIFileInputStream::DEFER_OPEN |
   nsIFileInputStream::SHARE_DELETE;
 
@@ -872,17 +1050,18 @@ DOMFileImplFile::SetPath(const nsAString
 
 ////////////////////////////////////////////////////////////////////////////
 // DOMFileImplMemory implementation
 
 NS_IMPL_ISUPPORTS_INHERITED0(DOMFileImplMemory, DOMFileImpl)
 
 already_AddRefed<DOMFileImpl>
 DOMFileImplMemory::CreateSlice(uint64_t aStart, uint64_t aLength,
-                               const nsAString& aContentType)
+                               const nsAString& aContentType,
+                               ErrorResult& aRv)
 {
   nsRefPtr<DOMFileImpl> impl =
     new DOMFileImplMemory(this, aStart, aLength, aContentType);
   return impl.forget();
 }
 
 nsresult
 DOMFileImplMemory::GetInternalStream(nsIInputStream** aStream)
@@ -997,43 +1176,43 @@ DOMFileImplMemory::DataOwner::EnsureMemo
 
 ////////////////////////////////////////////////////////////////////////////
 // DOMFileImplTemporaryFileBlob implementation
 
 NS_IMPL_ISUPPORTS_INHERITED0(DOMFileImplTemporaryFileBlob, DOMFileImpl)
 
 already_AddRefed<DOMFileImpl>
 DOMFileImplTemporaryFileBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
-                                          const nsAString& aContentType)
+                                          const nsAString& aContentType,
+                                          ErrorResult& aRv)
 {
-  if (aStart + aLength > mLength)
+  if (aStart + aLength > mLength) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
+  }
 
   nsRefPtr<DOMFileImpl> impl =
-    new DOMFileImplTemporaryFileBlob(this, aStart + mStartPos, aLength,
-                                     aContentType);
+    new DOMFileImplTemporaryFileBlob(this, aStart + mStartPos,
+                                     aLength, aContentType);
   return impl.forget();
 }
 
 nsresult
 DOMFileImplTemporaryFileBlob::GetInternalStream(nsIInputStream** aStream)
 {
   nsCOMPtr<nsIInputStream> stream =
     new nsTemporaryFileInputStream(mFileDescOwner, mStartPos, mStartPos + mLength);
   stream.forget(aStream);
   return NS_OK;
 }
 
-} // dom namespace
-} // mozilla namespace
-
 ////////////////////////////////////////////////////////////////////////////
 // nsDOMFileList implementation
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsDOMFileList)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMFileList, mFiles)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileList)
   NS_INTERFACE_MAP_ENTRY(nsIDOMFileList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileList)
@@ -1051,12 +1230,15 @@ nsDOMFileList::GetLength(uint32_t* aLeng
   *aLength = Length();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMFileList::Item(uint32_t aIndex, nsIDOMFile **aFile)
 {
-  NS_IF_ADDREF(*aFile = Item(aIndex));
-
+  nsRefPtr<DOMFile> file = Item(aIndex);
+  file.forget(aFile);
   return NS_OK;
 }
+
+} // dom namespace
+} // mozilla namespace
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -181,45 +181,49 @@ nsDOMFileReader::GetError(nsISupports** 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::ReadAsArrayBuffer(nsIDOMBlob* aFile, JSContext* aCx)
 {
   NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  ReadAsArrayBuffer(aCx, aFile, rv);
+  nsRefPtr<DOMFile> file = static_cast<DOMFile*>(aFile);
+  ReadAsArrayBuffer(aCx, *file, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::ReadAsBinaryString(nsIDOMBlob* aFile)
 {
   NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  ReadAsBinaryString(aFile, rv);
+  nsRefPtr<DOMFile> file = static_cast<DOMFile*>(aFile);
+  ReadAsBinaryString(*file, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::ReadAsText(nsIDOMBlob* aFile,
                             const nsAString &aCharset)
 {
   NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  ReadAsText(aFile, aCharset, rv);
+  nsRefPtr<DOMFile> file = static_cast<DOMFile*>(aFile);
+  ReadAsText(*file, aCharset, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::ReadAsDataURL(nsIDOMBlob* aFile)
 {
   NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  ReadAsDataURL(aFile, rv);
+  nsRefPtr<DOMFile> file = static_cast<DOMFile*>(aFile);
+  ReadAsDataURL(*file, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::Abort()
 {
   ErrorResult rv;
   FileIOObject::Abort(rv);
@@ -361,33 +365,31 @@ nsDOMFileReader::DoReadData(nsIAsyncInpu
   mDataLen += aCount;
   return NS_OK;
 }
 
 // Helper methods
 
 void
 nsDOMFileReader::ReadFileContent(JSContext* aCx,
-                                 nsIDOMBlob* aFile,
+                                 DOMFile& aFile,
                                  const nsAString &aCharset,
                                  eDataFormat aDataFormat,
                                  ErrorResult& aRv)
 {
-  MOZ_ASSERT(aFile);
-
   //Implicit abort to clear any other activity going on
   Abort();
   mError = nullptr;
   SetDOMStringToNull(mResult);
   mTransferred = 0;
   mTotal = 0;
   mReadyState = nsIDOMFileReader::EMPTY;
   FreeFileData();
 
-  mFile = aFile;
+  mFile = &aFile;
   mDataFormat = aDataFormat;
   CopyUTF16toUTF8(aCharset, mCharset);
 
   nsresult rv;
 
   nsCOMPtr<nsIStreamTransportService> sts =
     do_GetService(kStreamTransportServiceCID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/content/base/src/nsDOMFileReader.h
+++ b/content/base/src/nsDOMFileReader.h
@@ -14,30 +14,36 @@
 #include "nsIInterfaceRequestor.h"
 #include "nsJSUtils.h"
 #include "nsTArray.h"
 #include "nsIJSNativeInitializer.h"
 #include "prtime.h"
 #include "nsITimer.h"
 #include "nsIAsyncInputStream.h"
 
-#include "nsIDOMFile.h"
 #include "nsIDOMFileReader.h"
 #include "nsIDOMFileList.h"
 #include "nsCOMPtr.h"
 
 #include "FileIOObject.h"
 
+namespace mozilla {
+namespace dom {
+class DOMFile;
+}
+}
+
 class nsDOMFileReader : public mozilla::dom::FileIOObject,
                         public nsIDOMFileReader,
                         public nsIInterfaceRequestor,
                         public nsSupportsWeakReference
 {
   typedef mozilla::ErrorResult ErrorResult;
   typedef mozilla::dom::GlobalObject GlobalObject;
+  typedef mozilla::dom::DOMFile DOMFile;
 public:
   nsDOMFileReader();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMFILEREADER
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(mozilla::DOMEventTargetHelper)
@@ -57,31 +63,28 @@ public:
   {
     return GetOwner();
   }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   // WebIDL
   static already_AddRefed<nsDOMFileReader>
   Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
-  void ReadAsArrayBuffer(JSContext* aCx, nsIDOMBlob* aBlob, ErrorResult& aRv)
+  void ReadAsArrayBuffer(JSContext* aCx, DOMFile& aBlob, ErrorResult& aRv)
   {
-    MOZ_ASSERT(aBlob);
     ReadFileContent(aCx, aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
   }
 
-  void ReadAsText(nsIDOMBlob* aBlob, const nsAString& aLabel, ErrorResult& aRv)
+  void ReadAsText(DOMFile& aBlob, const nsAString& aLabel, ErrorResult& aRv)
   {
-    MOZ_ASSERT(aBlob);
     ReadFileContent(nullptr, aBlob, aLabel, FILE_AS_TEXT, aRv);
   }
 
-  void ReadAsDataURL(nsIDOMBlob* aBlob, ErrorResult& aRv)
+  void ReadAsDataURL(DOMFile& aBlob, ErrorResult& aRv)
   {
-    MOZ_ASSERT(aBlob);
     ReadFileContent(nullptr, aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
   }
 
   using FileIOObject::Abort;
 
   // Inherited ReadyState().
 
   void GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
@@ -94,19 +97,18 @@ public:
   using FileIOObject::SetOnprogress;
   IMPL_EVENT_HANDLER(load)
   using FileIOObject::GetOnabort;
   using FileIOObject::SetOnabort;
   using FileIOObject::GetOnerror;
   using FileIOObject::SetOnerror;
   IMPL_EVENT_HANDLER(loadend)
 
-  void ReadAsBinaryString(nsIDOMBlob* aBlob, ErrorResult& aRv)
+  void ReadAsBinaryString(DOMFile& aBlob, ErrorResult& aRv)
   {
-    MOZ_ASSERT(aBlob);
     ReadFileContent(nullptr, aBlob, EmptyString(), FILE_AS_BINARY, aRv);
   }
 
 
   nsresult Init();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsDOMFileReader,
                                                          FileIOObject)
@@ -117,17 +119,17 @@ protected:
 
   enum eDataFormat {
     FILE_AS_ARRAYBUFFER,
     FILE_AS_BINARY,
     FILE_AS_TEXT,
     FILE_AS_DATAURL
   };
 
-  void ReadFileContent(JSContext* aCx, nsIDOMBlob* aBlob,
+  void ReadFileContent(JSContext* aCx, DOMFile& aBlob,
                        const nsAString &aCharset, eDataFormat aDataFormat,
                        ErrorResult& aRv);
   nsresult GetAsText(nsIDOMBlob *aFile, const nsACString &aCharset,
                      const char *aFileData, uint32_t aDataLen, nsAString &aResult);
   nsresult GetAsDataURL(nsIDOMBlob *aFile, const char *aFileData, uint32_t aDataLen, nsAString &aResult);
 
   void FreeFileData() {
     moz_free(mFileData);
--- a/content/base/src/nsFormData.cpp
+++ b/content/base/src/nsFormData.cpp
@@ -1,34 +1,59 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "nsDOMFile.h"
 #include "nsFormData.h"
 #include "nsIVariant.h"
 #include "nsIInputStream.h"
-#include "nsIDOMFile.h"
 #include "mozilla/dom/HTMLFormElement.h"
 #include "mozilla/dom/FormDataBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsFormData::nsFormData(nsISupports* aOwner)
   : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr)
   , mOwner(aOwner)
 {
 }
 
 // -------------------------------------------------------------------------
 // nsISupports
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsFormData, mOwner)
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsFormData)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormData)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
+
+  for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
+    ImplCycleCollectionUnlink(tmp->mFormData[i].fileValue);
+  }
+
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFormData)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
+
+  for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
+   ImplCycleCollectionTraverse(cb,tmp->mFormData[i].fileValue,
+                               "mFormData[i].fileValue", 0);
+  }
+
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsFormData)
+
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFormData)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFormData)
+
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFormData)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsIDOMFormData)
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFormData)
 NS_INTERFACE_MAP_END
 
 // -------------------------------------------------------------------------
@@ -43,26 +68,26 @@ nsFormData::GetEncodedSubmission(nsIURI*
 
 void
 nsFormData::Append(const nsAString& aName, const nsAString& aValue)
 {
   AddNameValuePair(aName, aValue);
 }
 
 void
-nsFormData::Append(const nsAString& aName, nsIDOMBlob* aBlob,
+nsFormData::Append(const nsAString& aName, DOMFile& aBlob,
                    const Optional<nsAString>& aFilename)
 {
   nsString filename;
   if (aFilename.WasPassed()) {
     filename = aFilename.Value();
   } else {
     filename.SetIsVoid(true);
   }
-  AddNameFilePair(aName, aBlob, filename);
+  AddNameFilePair(aName, &aBlob, filename);
 }
 
 // -------------------------------------------------------------------------
 // nsIDOMFormData
 
 NS_IMETHODIMP
 nsFormData::Append(const nsAString& aName, nsIVariant* aValue)
 {
@@ -75,19 +100,20 @@ nsFormData::Append(const nsAString& aNam
     nsCOMPtr<nsISupports> supports;
     nsID *iid;
     rv = aValue->GetAsInterface(&iid, getter_AddRefs(supports));
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsMemory::Free(iid);
 
     nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(supports);
+    nsRefPtr<DOMFile> blob = static_cast<DOMFile*>(domBlob.get());
     if (domBlob) {
       Optional<nsAString> temp;
-      Append(aName, domBlob, temp);
+      Append(aName, *blob, temp);
       return NS_OK;
     }
   }
 
   char16_t* stringData = nullptr;
   uint32_t stringLen = 0;
   rv = aValue->GetAsWStringWithSize(&stringLen, &stringData);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/content/base/src/nsFormData.h
+++ b/content/base/src/nsFormData.h
@@ -1,31 +1,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsFormData_h__
 #define nsFormData_h__
 
 #include "mozilla/Attributes.h"
-#include "nsIDOMFile.h"
 #include "nsIDOMFormData.h"
 #include "nsIXMLHttpRequest.h"
 #include "nsFormSubmission.h"
 #include "nsWrapperCache.h"
 #include "nsTArray.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 
-class nsIDOMFile;
-
 namespace mozilla {
 class ErrorResult;
 
 namespace dom {
+class DOMFile;
 class HTMLFormElement;
 class GlobalObject;
 } // namespace dom
 } // namespace mozilla
 
 class nsFormData MOZ_FINAL : public nsIDOMFormData,
                              public nsIXHRSendable,
                              public nsFormSubmission,
@@ -52,17 +50,17 @@ public:
   {
     return mOwner;
   }
   static already_AddRefed<nsFormData>
   Constructor(const mozilla::dom::GlobalObject& aGlobal,
               const mozilla::dom::Optional<mozilla::dom::NonNull<mozilla::dom::HTMLFormElement> >& aFormElement,
               mozilla::ErrorResult& aRv);
   void Append(const nsAString& aName, const nsAString& aValue);
-  void Append(const nsAString& aName, nsIDOMBlob* aBlob,
+  void Append(const nsAString& aName, mozilla::dom::DOMFile& aBlob,
               const mozilla::dom::Optional<nsAString>& aFilename);
 
   // nsFormSubmission
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream) MOZ_OVERRIDE;
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) MOZ_OVERRIDE
   {
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -199,17 +199,17 @@ template<ActorFlavorEnum Flavor>
 static bool
 BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType* aManager,
                        const StructuredCloneData& aData,
                        ClonedMessageData& aClonedData)
 {
   SerializedStructuredCloneBuffer& buffer = aClonedData.data();
   buffer.data = aData.mData;
   buffer.dataLength = aData.mDataLength;
-  const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
+  const nsTArray<nsRefPtr<DOMFile>>& blobs = aData.mClosure.mBlobs;
   if (!blobs.IsEmpty()) {
     typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
     InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
     uint32_t length = blobs.Length();
     blobList.SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       typename BlobTraits<Flavor>::BlobType* protocolActor =
         aManager->GetOrCreateActorForBlob(blobs[i]);
@@ -250,18 +250,23 @@ UnpackClonedMessageData(const ClonedMess
   cloneData.mDataLength = buffer.dataLength;
   if (!blobs.IsEmpty()) {
     uint32_t length = blobs.Length();
     cloneData.mClosure.mBlobs.SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       auto* blob =
         static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
       MOZ_ASSERT(blob);
-      nsCOMPtr<nsIDOMBlob> domBlob = blob->GetBlob();
-      MOZ_ASSERT(domBlob);
+
+      nsRefPtr<DOMFileImpl> blobImpl = blob->GetBlobImpl();
+      MOZ_ASSERT(blobImpl);
+
+      // This object will be duplicated with a correct parent before being
+      // exposed to JS.
+      nsRefPtr<DOMFile> domBlob = new DOMFile(nullptr, blobImpl);
       cloneData.mClosure.mBlobs.AppendElement(domBlob);
     }
   }
   return cloneData;
 }
 
 StructuredCloneData
 mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aData)
--- a/content/base/src/nsHostObjectProtocolHandler.cpp
+++ b/content/base/src/nsHostObjectProtocolHandler.cpp
@@ -13,16 +13,17 @@
 #include "nsDOMFile.h"
 #include "DOMMediaStream.h"
 #include "mozilla/dom/MediaSource.h"
 #include "nsIMemoryReporter.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/LoadInfo.h"
 
 using mozilla::dom::DOMFileImpl;
+using mozilla::ErrorResult;
 using mozilla::LoadInfo;
 
 // -----------------------------------------------------------------------
 // Hash table
 struct DataInfo
 {
   // mObject is expected to be an nsIDOMBlob, DOMMediaStream, or MediaSource
   nsCOMPtr<nsISupports> mObject;
@@ -517,29 +518,29 @@ nsHostObjectProtocolHandler::NewChannel(
 
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
                                 uri,
                                 stream);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsString type;
-  rv = blob->GetType(type);
-  NS_ENSURE_SUCCESS(rv, rv);
+  blob->GetType(type);
 
   if (blob->IsFile()) {
     nsString filename;
-    rv = blob->GetName(filename);
-    NS_ENSURE_SUCCESS(rv, rv);
+    blob->GetName(filename);
     channel->SetContentDispositionFilename(filename);
   }
 
-  uint64_t size;
-  rv = blob->GetSize(&size);
-  NS_ENSURE_SUCCESS(rv, rv);
+  ErrorResult error;
+  uint64_t size = blob->GetSize(error);
+  if (NS_WARN_IF(error.Failed())) {
+    return error.ErrorCode();
+  }
 
   nsCOMPtr<nsILoadInfo> loadInfo =
     new mozilla::LoadInfo(info->mPrincipal,
                           nullptr,
                           nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
                           nsIContentPolicy::TYPE_OTHER);
   channel->SetLoadInfo(loadInfo);
   channel->SetOriginalURI(uri);
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -779,33 +779,34 @@ nsXMLHttpRequest::CreatePartialBlob()
 {
   if (mDOMFile) {
     // Use progress info to determine whether load is complete, but use
     // mDataAvailable to ensure a slice is created based on the uncompressed
     // data count.
     if (mLoadTotal == mLoadTransferred) {
       mResponseBlob = mDOMFile;
     } else {
-      mResponseBlob =
-        mDOMFile->CreateSlice(0, mDataAvailable, EmptyString());
+      ErrorResult rv;
+      mResponseBlob = mDOMFile->CreateSlice(0, mDataAvailable,
+                                            EmptyString(), rv);
     }
     return;
   }
 
   // mBlobSet can be null if the request has been canceled
   if (!mBlobSet) {
     return;
   }
 
   nsAutoCString contentType;
   if (mLoadTotal == mLoadTransferred) {
     mChannel->GetContentType(contentType);
   }
 
-  mResponseBlob = mBlobSet->GetBlobInternal(contentType);
+  mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType);
 }
 
 /* attribute AString responseType; */
 NS_IMETHODIMP nsXMLHttpRequest::GetResponseType(nsAString& aResponseType)
 {
   switch (mResponseType) {
   case XML_HTTP_RESPONSE_TYPE_DEFAULT:
     aResponseType.Truncate();
@@ -1002,17 +1003,17 @@ nsXMLHttpRequest::GetResponse(JSContext*
       }
     }
 
     if (!mResponseBlob) {
       aResponse.setNull();
       return;
     }
 
-    aRv = nsContentUtils::WrapNative(aCx, mResponseBlob, aResponse);
+    WrapNewBindingObject(aCx, mResponseBlob, aResponse);
     return;
   }
   case XML_HTTP_RESPONSE_TYPE_DOCUMENT:
   {
     if (!(mState & XML_HTTP_REQUEST_DONE) || !mResponseXML) {
       aResponse.setNull();
       return;
     }
@@ -1893,17 +1894,17 @@ bool nsXMLHttpRequest::CreateDOMFile(nsI
 
   if (!file)
     return false;
 
   nsAutoCString contentType;
   mChannel->GetContentType(contentType);
 
   mDOMFile =
-    DOMFile::CreateFromFile(file, EmptyString(),
+    DOMFile::CreateFromFile(GetOwner(), file, EmptyString(),
                             NS_ConvertASCIItoUTF16(contentType));
 
   mBlobSet = nullptr;
   NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
   return true;
 }
 
 NS_IMETHODIMP
@@ -2238,17 +2239,17 @@ nsXMLHttpRequest::OnStopRequest(nsIReque
       // and if the response length is zero.
       if (!mBlobSet) {
         mBlobSet = new BlobSet();
       }
       // Smaller files may be written in cache map instead of separate files.
       // Also, no-store response cannot be written in persistent cache.
       nsAutoCString contentType;
       mChannel->GetContentType(contentType);
-      mResponseBlob = mBlobSet->GetBlobInternal(contentType);
+      mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType);
       mBlobSet = nullptr;
     }
     NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
     NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty");
   } else if (NS_SUCCEEDED(status) &&
              ((mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER &&
                !mIsMappedArrayBuffer) ||
               mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER)) {
@@ -2613,17 +2614,18 @@ nsXMLHttpRequest::GetRequestBody(nsIVari
       const ArrayBufferView* view = value.mArrayBufferView;
       view->ComputeLengthAndData();
       return ::GetRequestBody(view->Data(), view->Length(), aResult,
                               aContentLength, aContentType, aCharset);
     }
     case nsXMLHttpRequest::RequestBody::Blob:
     {
       nsresult rv;
-      nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(value.mBlob, &rv);
+      nsCOMPtr<nsIDOMBlob> blob = value.mBlob;
+      nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(blob, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
 
       return ::GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
     }
     case nsXMLHttpRequest::RequestBody::Document:
     {
       nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(value.mDocument);
       return ::GetRequestBody(document, aResult, aContentLength, aContentType, aCharset);
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -345,19 +345,19 @@ private:
     explicit RequestBody(const mozilla::dom::ArrayBuffer* aArrayBuffer) : mType(ArrayBuffer)
     {
       mValue.mArrayBuffer = aArrayBuffer;
     }
     explicit RequestBody(const mozilla::dom::ArrayBufferView* aArrayBufferView) : mType(ArrayBufferView)
     {
       mValue.mArrayBufferView = aArrayBufferView;
     }
-    explicit RequestBody(nsIDOMBlob* aBlob) : mType(Blob)
+    explicit RequestBody(mozilla::dom::DOMFile& aBlob) : mType(Blob)
     {
-      mValue.mBlob = aBlob;
+      mValue.mBlob = &aBlob;
     }
     explicit RequestBody(nsIDocument* aDocument) : mType(Document)
     {
       mValue.mDocument = aDocument;
     }
     explicit RequestBody(const nsAString& aString) : mType(DOMString)
     {
       mValue.mString = &aString;
@@ -379,17 +379,17 @@ private:
       Document,
       DOMString,
       FormData,
       InputStream
     };
     union Value {
       const mozilla::dom::ArrayBuffer* mArrayBuffer;
       const mozilla::dom::ArrayBufferView* mArrayBufferView;
-      nsIDOMBlob* mBlob;
+      mozilla::dom::DOMFile* mBlob;
       nsIDocument* mDocument;
       const nsAString* mString;
       nsFormData* mFormData;
       nsIInputStream* mStream;
     };
 
     Type GetType() const
     {
@@ -435,19 +435,18 @@ public:
   {
     aRv = Send(RequestBody(&aArrayBuffer));
   }
   void Send(const mozilla::dom::ArrayBufferView& aArrayBufferView,
             ErrorResult& aRv)
   {
     aRv = Send(RequestBody(&aArrayBufferView));
   }
-  void Send(nsIDOMBlob* aBlob, ErrorResult& aRv)
+  void Send(mozilla::dom::DOMFile& aBlob, ErrorResult& aRv)
   {
-    NS_ASSERTION(aBlob, "Null should go to string version");
     aRv = Send(RequestBody(aBlob));
   }
   void Send(nsIDocument& aDoc, ErrorResult& aRv)
   {
     aRv = Send(RequestBody(&aDoc));
   }
   void Send(const nsAString& aString, ErrorResult& aRv)
   {
@@ -667,17 +666,17 @@ protected:
   };
 
   void SetResponseType(nsXMLHttpRequest::ResponseTypeEnum aType, ErrorResult& aRv);
 
   ResponseTypeEnum mResponseType;
 
   // It is either a cached blob-response from the last call to GetResponse,
   // but is also explicitly set in OnStopRequest.
-  nsCOMPtr<nsIDOMBlob> mResponseBlob;
+  nsRefPtr<mozilla::dom::DOMFile> mResponseBlob;
   // Non-null only when we are able to get a os-file representation of the
   // response, i.e. when loading from a file.
   nsRefPtr<mozilla::dom::DOMFile> mDOMFile;
   // We stream data to mBlobSet when response type is "blob" or "moz-blob"
   // and mDOMFile is null.
   nsAutoPtr<BlobSet> mBlobSet;
 
   nsString mOverrideMimeType;
--- a/content/base/test/chrome/test_bug914381.html
+++ b/content/base/test/chrome/test_bug914381.html
@@ -30,19 +30,19 @@ function createFileWithData(fileData) {
   outStream.write(fileData, fileData.length);
   outStream.close();
 
   return testFile;
 }
 
 /** Test for Bug 914381. DOMFile's created in JS using an nsIFile should allow mozGetFullPathInternal calls to succeed **/
 var file = createFileWithData("Test bug 914381");
-var f = File(file);
+var f = new File(file);
 is(f.mozFullPathInternal, undefined, "mozFullPathInternal is undefined from js");
 is(f.mozFullPath, file.path, "mozFullPath returns path if created with nsIFile");
 
-f = File(file.path);
+f = new File(file.path);
 is(f.mozFullPathInternal, undefined, "mozFullPathInternal is undefined from js");
 is(f.mozFullPath, "", "mozFullPath returns blank if created with a string");
 </script>
 </pre>
 </body>
 </html>
--- a/content/base/test/test_blobconstructor.html
+++ b/content/base/test/test_blobconstructor.html
@@ -15,75 +15,75 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript;version=1.7">
 "use strict";
 /** Test for Bug 721569 **/
-var blob = Blob();
+var blob = new Blob();
 ok(blob, "Blob should exist");
 
 ok(blob.size !== undefined, "Blob should have a size property");
 ok(blob.type !== undefined, "Blob should have a type property");
 ok(blob.slice, "Blob should have a slice method");
 
-blob = Blob([], {type: null});
+blob = new Blob([], {type: null});
 ok(blob, "Blob should exist");
 is(blob.type, "null", "Blob type should be stringified");
 
-blob = Blob([], {type: undefined});
+blob = new Blob([], {type: undefined});
 ok(blob, "Blob should exist");
 is(blob.type, "", "Blob type should be treated as missing");
 
 try {
-blob = Blob([]);
+blob = new Blob([]);
 ok(true, "an empty blobParts argument should not throw");
 } catch(e) {
 ok(false, "NOT REACHED");
 }
 
 try {
-blob = Blob(null);
+blob = new Blob(null);
 ok(false, "NOT REACHED");
 } catch(e) {
 ok(true, "a null blobParts member should throw");
 }
 
 try {
-blob = Blob([], null);
+blob = new Blob([], null);
 ok(true, "a null options member should not throw");
 } catch(e) {
 ok(false, "NOT REACHED");
 }
 
 try {
-blob = Blob([], undefined);
+blob = new Blob([], undefined);
 ok(true, "an undefined options member should not throw");
 } catch(e) {
 ok(false, "NOT REACHED");
 }
 
 try {
-blob = Blob([], false);
+blob = new Blob([], false);
 ok(false, "NOT REACHED");
 } catch(e) {
 ok(true, "a boolean options member should throw");
 }
 
 try {
-blob = Blob([], 0);
+blob = new Blob([], 0);
 ok(false, "NOT REACHED");
 } catch(e) {
 ok(true, "a numeric options member should throw");
 }
 
 try {
-blob = Blob([], "");
+blob = new Blob([], "");
 ok(false, "NOT REACHED");
 } catch(e) {
 ok(true, "a string options member should throw");
 }
 
 /** Test for dictionary initialization order **/
 (function() {
   var o = {};
@@ -95,23 +95,23 @@ ok(true, "a string options member should
   }
   ["type", "endings"].forEach(function(n) {
     Object.defineProperty(o, n, { get: add_to_called.bind(null, n) });
   });
   var b = new Blob([], o);
   is(JSON.stringify(called), JSON.stringify(["endings", "type"]), "dictionary members should be get in lexicographical order");
 })();
 
-let blob1 = Blob(["squiggle"]);
+let blob1 = new Blob(["squiggle"]);
 ok(blob1 instanceof Blob, "Blob constructor should produce Blobs");
 ok(!(blob1 instanceof File), "Blob constructor should not produce Files");
 is(blob1.type, "", "Blob constructor with no options should return Blob with empty type");
 is(blob1.size, 8, "Blob constructor should return Blob with correct size");
 
-let blob2 = Blob(["steak"], {type: "content/type"});
+let blob2 = new Blob(["steak"], {type: "content/type"});
 ok(blob2 instanceof Blob, "Blob constructor should produce Blobs");
 ok(!(blob2 instanceof File), "Blob constructor should not produce Files");
 is(blob2.type, "content/type", "Blob constructor with a type option should return Blob with the type");
 is(blob2.size, 5, "Blob constructor should return Blob with correct size");
 
 
 let aB = new ArrayBuffer(16);
 var int8View = new Int8Array(aB);
--- a/content/base/test/test_bug403852.html
+++ b/content/base/test/test_bug403852.html
@@ -8,17 +8,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=403852">Mozilla Bug 403852</a>
 <p id="display">
   <input id="fileList" type="file"></input>
-  <canvas id="canvas"></canvas>
 </p>
 <div id="content" style="display: none">
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 var testFile = SpecialPowers.Services.dirsvc.get("ProfD", SpecialPowers.Ci.nsIFile);
@@ -32,19 +31,23 @@ var domFile = fileList.files[0];
 
 is(domFile.name, "prefs.js", "fileName should be prefs.js");
 
 ok("lastModifiedDate" in domFile, "lastModifiedDate must be present");
 
 var d = new Date(testFile.lastModifiedTime);
 ok(d.getTime() == domFile.lastModifiedDate.getTime(), "lastModifiedDate should be the same.");
 
-var cf = document.getElementById("canvas").mozGetAsFile("canvFile");
+var x = new Date();
 
-var x = new Date();
-var y = cf.lastModifiedDate;
+// In our implementation of File object, lastModifiedDate is unknown only for new objects.
+// Using canvas or input[type=file] elements, we 'often' have a valid lastModifiedDate values.
+// For canvas we use memory files and the lastModifiedDate is now().
+var f = new File([new Blob(['test'], {type: 'text/plain'})], "test-name");
+
+var y = f.lastModifiedDate;
 var z = new Date();
 
 ok((x.getTime() <= y.getTime()) && (y.getTime() <= z.getTime()), "lastModifiedDate of file which does not have last modified date should be current time");
 
 </script>
 </pre>
 </body> </html>
--- a/content/html/content/public/HTMLCanvasElement.h
+++ b/content/html/content/public/HTMLCanvasElement.h
@@ -11,31 +11,31 @@
 #include "nsGenericHTMLElement.h"
 #include "nsGkAtoms.h"
 #include "nsSize.h"
 #include "nsError.h"
 
 #include "mozilla/gfx/Rect.h"
 
 class nsICanvasRenderingContextInternal;
-class nsIDOMFile;
 class nsITimerCallback;
 
 namespace mozilla {
 
 namespace layers {
 class CanvasLayer;
 class LayerManager;
 }
 namespace gfx {
 class SourceSurface;
 }
 
 namespace dom {
 
+class DOMFile;
 class FileCallback;
 class HTMLCanvasPrintState;
 class PrintCallback;
 
 class HTMLCanvasElement MOZ_FINAL : public nsGenericHTMLElement,
                                     public nsIDOMHTMLCanvasElement
 {
   enum {
@@ -97,19 +97,19 @@ public:
   bool MozOpaque() const
   {
     return GetBoolAttr(nsGkAtoms::moz_opaque);
   }
   void SetMozOpaque(bool aValue, ErrorResult& aRv)
   {
     SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv);
   }
-  already_AddRefed<nsIDOMFile> MozGetAsFile(const nsAString& aName,
-                                            const nsAString& aType,
-                                            ErrorResult& aRv);
+  already_AddRefed<DOMFile> MozGetAsFile(const nsAString& aName,
+                                         const nsAString& aType,
+                                         ErrorResult& aRv);
   already_AddRefed<nsISupports> MozGetIPCContext(const nsAString& aContextId,
                                                  ErrorResult& aRv)
   {
     nsCOMPtr<nsISupports> context;
     aRv = MozGetIPCContext(aContextId, getter_AddRefs(context));
     return context.forget();
   }
   void MozFetchAsStream(nsIInputStreamCallback* aCallback,
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -555,18 +555,20 @@ HTMLCanvasElement::ToBlob(JSContext* aCx
       uint64_t size;
       nsresult rv = blob->GetSize(&size);
       if (NS_SUCCEEDED(rv)) {
         AutoJSAPI jsapi;
         jsapi.Init(mGlobal);
         JS_updateMallocCounter(jsapi.cx(), size);
       }
 
+      nsRefPtr<DOMFile> newBlob = new DOMFile(mGlobal, blob->Impl());
+
       mozilla::ErrorResult error;
-      mFileCallback->Call(blob, error);
+      mFileCallback->Call(*newBlob, error);
 
       mGlobal = nullptr;
       mFileCallback = nullptr;
 
       return error.ErrorCode();
     }
 
     nsCOMPtr<nsIGlobalObject> mGlobal;
@@ -580,24 +582,25 @@ HTMLCanvasElement::ToBlob(JSContext* aCx
                                        params,
                                        usingCustomParseOptions,
                                        imageBuffer,
                                        format,
                                        GetSize(),
                                        callback);
 }
 
-already_AddRefed<nsIDOMFile>
+already_AddRefed<DOMFile>
 HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
                                 const nsAString& aType,
                                 ErrorResult& aRv)
 {
   nsCOMPtr<nsIDOMFile> file;
   aRv = MozGetAsFile(aName, aType, getter_AddRefs(file));
-  return file.forget();
+  nsRefPtr<DOMFile> tmp = static_cast<DOMFile*>(file.get());
+  return tmp.forget();
 }
 
 NS_IMETHODIMP
 HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
                                 const nsAString& aType,
                                 nsIDOMFile** aResult)
 {
   OwnerDoc()->WarnOnceAbout(nsIDocument::eMozGetAsFile);
@@ -630,19 +633,21 @@ HTMLCanvasElement::MozGetAsFileImpl(cons
   rv = NS_ReadInputStreamToBuffer(stream, &imgData, (uint32_t)imgSize);
   NS_ENSURE_SUCCESS(rv, rv);
 
   JSContext* cx = nsContentUtils::GetCurrentJSContext();
   if (cx) {
     JS_updateMallocCounter(cx, imgSize);
   }
 
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(OwnerDoc()->GetScopeObject());
+
   // The DOMFile takes ownership of the buffer
   nsRefPtr<DOMFile> file =
-    DOMFile::CreateMemoryFile(imgData, (uint32_t)imgSize, aName, type,
+    DOMFile::CreateMemoryFile(win, imgData, (uint32_t)imgSize, aName, type,
                               PR_Now());
 
   file.forget(aResult);
   return NS_OK;
 }
 
 nsresult
 HTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -231,36 +231,36 @@ class HTMLInputElementState MOZ_FINAL : 
     const nsString& GetValue() {
       return mValue;
     }
 
     void SetValue(const nsAString& aValue) {
       mValue = aValue;
     }
 
-    const nsTArray<nsCOMPtr<nsIDOMFile> >& GetFiles() {
+    const nsTArray<nsRefPtr<DOMFile>>& GetFiles() {
       return mFiles;
     }
 
-    void SetFiles(const nsTArray<nsCOMPtr<nsIDOMFile> >& aFiles) {
+    void SetFiles(const nsTArray<nsRefPtr<DOMFile>>& aFiles) {
       mFiles.Clear();
       mFiles.AppendElements(aFiles);
     }
 
     HTMLInputElementState()
       : mValue()
       , mChecked(false)
       , mCheckedSet(false)
     {};
 
   protected:
     ~HTMLInputElementState() {}
 
     nsString mValue;
-    nsTArray<nsCOMPtr<nsIDOMFile> > mFiles;
+    nsTArray<nsRefPtr<DOMFile>> mFiles;
     bool mChecked;
     bool mCheckedSet;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(HTMLInputElementState, NS_INPUT_ELEMENT_STATE_IID)
 
 NS_IMPL_ISUPPORTS(HTMLInputElementState, HTMLInputElementState)
 
@@ -311,17 +311,17 @@ UploadLastDir::ContentPrefCallback::Hand
   // HandleCompletion is always called (even with HandleError was called),
   // so we don't need to do anything special here.
   return NS_OK;
 }
 
 namespace {
 
 /**
- * This enumerator returns nsDOMFileFile objects after wrapping a single
+ * This enumerator returns DOMFile objects after wrapping a single
  * nsIFile representing a directory. It enumerates the files under that
  * directory and its subdirectories as a flat list of files, ignoring/skipping
  * over symbolic links.
  *
  * The enumeration involves I/O, so this class must NOT be used on the main
  * thread or else the main thread could be blocked for a very long time.
  *
  * This enumerator does not walk the directory tree breadth-first, but it also
@@ -369,17 +369,19 @@ public:
   {
     MOZ_ASSERT(!NS_IsMainThread(),
                "Walking the directory tree involves I/O, so using this "
                "enumerator can block a thread for a long time!");
 
     if (!mNextFile) {
       return NS_ERROR_FAILURE;
     }
-    nsRefPtr<DOMFile> domFile = DOMFile::CreateFromFile(mNextFile);
+
+    // The parent for this object will be set on the main thread.
+    nsRefPtr<DOMFile> domFile = DOMFile::CreateFromFile(nullptr, mNextFile);
     nsCString relDescriptor;
     nsresult rv =
       mNextFile->GetRelativeDescriptor(mTopDirsParent, relDescriptor);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ConvertUTF8toUTF16 path(relDescriptor);
     nsAutoString leafName;
     mNextFile->GetLeafName(leafName);
     MOZ_ASSERT(leafName.Length() <= path.Length());
@@ -507,26 +509,26 @@ public:
     , mInput(aInput)
     , mTopDir(aTopDir)
     , mFileListLength(0)
     , mCanceled(false)
   {}
 
   NS_IMETHOD Run() {
     if (!NS_IsMainThread()) {
-      // Build up list of nsDOMFileFile objects on this dedicated thread:
+      // Build up list of DOMFile objects on this dedicated thread:
       nsCOMPtr<nsISimpleEnumerator> iter =
         new DirPickerRecursiveFileEnumerator(mTopDir);
       bool hasMore = true;
       nsCOMPtr<nsISupports> tmp;
       while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
         iter->GetNext(getter_AddRefs(tmp));
         nsCOMPtr<nsIDOMFile> domFile = do_QueryInterface(tmp);
         MOZ_ASSERT(domFile);
-        mFileList.AppendElement(domFile);
+        mFileList.AppendElement(static_cast<DOMFile*>(domFile.get()));
         mFileListLength = mFileList.Length();
         if (mCanceled) {
           MOZ_ASSERT(!mInput, "This is bad - how did this happen?");
           // There's no point dispatching to the main thread (that doesn't
           // guarantee that we'll be destroyed there).
           return NS_OK;
         }
       }
@@ -546,16 +548,23 @@ public:
 
     mInput->MaybeDispatchProgressEvent(true);        // Last progress event.
     mInput->mDirPickerFileListBuilderTask = nullptr; // Now null out.
 
     if (mCanceled) { // The last progress event may have canceled us
       return NS_OK;
     }
 
+    // Recreate DOMFile with the correct parent object.
+    nsCOMPtr<nsIGlobalObject> global = mInput->OwnerDoc()->GetScopeObject();
+    for (uint32_t i = 0; i < mFileList.Length(); ++i) {
+      MOZ_ASSERT(!mFileList[i]->GetParentObject());
+      mFileList[i] = new DOMFile(global, mFileList[i]->Impl());
+    }
+
     // The text control frame (if there is one) isn't going to send a change
     // event because it will think this is done by a script.
     // So, we can safely send one by ourself.
     mInput->SetFiles(mFileList, true);
     nsresult rv =
       nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
                                            static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
                                            NS_LITERAL_STRING("change"), true,
@@ -589,17 +598,17 @@ public:
    * we don't increase the size of HTMLInputElement for something that's rarely
    * used.
    */
   uint32_t mPreviousFileListLength;
 
 private:
   nsRefPtr<HTMLInputElement> mInput;
   nsCOMPtr<nsIFile> mTopDir;
-  nsTArray<nsCOMPtr<nsIDOMFile> > mFileList;
+  nsTArray<nsRefPtr<DOMFile>> mFileList;
 
   // We access the list length on both threads, so we need the indirection of
   // this atomic member to make the access thread safe:
   mozilla::Atomic<uint32_t> mFileListLength;
 
   mozilla::Atomic<bool> mCanceled;
 };
 
@@ -615,17 +624,17 @@ HTMLInputElement::nsFilePickerShownCallb
 
   mInput->CancelDirectoryPickerScanIfRunning();
 
   int16_t mode;
   mFilePicker->GetMode(&mode);
 
   if (mode == static_cast<int16_t>(nsIFilePicker::modeGetFolder)) {
     // Directory picking is different, since we still need to do more I/O to
-    // build up the list of nsDOMFileFile objects. Since this may block for a
+    // build up the list of DOMFile objects. Since this may block for a
     // long time, we need to build the list off on another dedicated thread to
     // avoid blocking any other activities that the browser is carrying out.
 
     // The user selected this directory, so we always save this dir, even if
     // no files are found under it.
     nsCOMPtr<nsIFile> pickedDir;
     mFilePicker->GetFile(getter_AddRefs(pickedDir));
 
@@ -650,42 +659,42 @@ HTMLInputElement::nsFilePickerShownCallb
     // dispatching the "change" event.
     mInput->mDirPickerFileListBuilderTask =
       new DirPickerFileListBuilderTask(mInput.get(), pickedDir.get());
     return target->Dispatch(mInput->mDirPickerFileListBuilderTask,
                             NS_DISPATCH_NORMAL);
   }
 
   // Collect new selected filenames
-  nsTArray<nsCOMPtr<nsIDOMFile> > newFiles;
+  nsTArray<nsRefPtr<DOMFile>> newFiles;
   if (mode == static_cast<int16_t>(nsIFilePicker::modeOpenMultiple)) {
     nsCOMPtr<nsISimpleEnumerator> iter;
     nsresult rv = mFilePicker->GetDomfiles(getter_AddRefs(iter));
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!iter) {
       return NS_OK;
     }
 
     nsCOMPtr<nsISupports> tmp;
     bool hasMore = true;
 
     while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
       iter->GetNext(getter_AddRefs(tmp));
       nsCOMPtr<nsIDOMFile> domFile = do_QueryInterface(tmp);
       MOZ_ASSERT(domFile);
-      newFiles.AppendElement(domFile);
+      newFiles.AppendElement(static_cast<DOMFile*>(domFile.get()));
     }
   } else {
     MOZ_ASSERT(mode == static_cast<int16_t>(nsIFilePicker::modeOpen));
     nsCOMPtr<nsIDOMFile> domFile;
     nsresult rv = mFilePicker->GetDomfile(getter_AddRefs(domFile));
     NS_ENSURE_SUCCESS(rv, rv);
     if (domFile) {
-      newFiles.AppendElement(domFile);
+      newFiles.AppendElement(static_cast<DOMFile*>(domFile.get()));
     }
   }
 
   if (newFiles.IsEmpty()) {
     return NS_OK;
   }
 
   // Store the last used directory using the content pref service:
@@ -931,17 +940,17 @@ HTMLInputElement::InitFilePicker(FilePic
     SetFilePickerFiltersFromAccept(filePicker);
   } else {
     filePicker->AppendFilters(nsIFilePicker::filterAll);
   }
 
   // Set default directry and filename
   nsAutoString defaultName;
 
-  const nsTArray<nsCOMPtr<nsIDOMFile> >& oldFiles = GetFilesInternal();
+  const nsTArray<nsRefPtr<DOMFile>>& oldFiles = GetFilesInternal();
 
   nsCOMPtr<nsIFilePickerShownCallback> callback =
     new HTMLInputElement::nsFilePickerShownCallback(this, filePicker);
 
   if (!oldFiles.IsEmpty() &&
       aType != FILE_PICKER_DIRECTORY) {
     nsString path;
 
@@ -1711,17 +1720,17 @@ HTMLInputElement::IsValueEmpty() const
   GetValueInternal(value);
 
   return value.IsEmpty();
 }
 
 void
 HTMLInputElement::ClearFiles(bool aSetValueChanged)
 {
-  nsTArray<nsCOMPtr<nsIDOMFile> > files;
+  nsTArray<nsRefPtr<DOMFile>> files;
   SetFiles(files, aSetValueChanged);
 }
 
 /* static */ Decimal
 HTMLInputElement::StringToDecimal(const nsAString& aValue)
 {
   if (!IsASCII(aValue)) {
     return Decimal::nan();
@@ -2305,17 +2314,17 @@ HTMLInputElement::MozGetFileNameArray(ui
   *aFileNames = ret;
 
   return NS_OK;
 }
 
 void
 HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames)
 {
-  nsTArray<nsCOMPtr<nsIDOMFile> > files;
+  nsTArray<nsRefPtr<DOMFile>> files;
   for (uint32_t i = 0; i < aFileNames.Length(); ++i) {
     nsCOMPtr<nsIFile> file;
 
     if (StringBeginsWith(aFileNames[i], NS_LITERAL_STRING("file:"),
                          nsASCIICaseInsensitiveStringComparator())) {
       // Converts the URL string into the corresponding nsIFile if possible
       // A local file will be created if the URL string begins with file://
       NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(aFileNames[i]),
@@ -2323,17 +2332,18 @@ HTMLInputElement::MozSetFileNameArray(co
     }
 
     if (!file) {
       // this is no "file://", try as local file
       NS_NewLocalFile(aFileNames[i], false, getter_AddRefs(file));
     }
 
     if (file) {
-      nsCOMPtr<nsIDOMFile> domFile = DOMFile::CreateFromFile(file);
+      nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
+      nsRefPtr<DOMFile> domFile = DOMFile::CreateFromFile(global, file);
       files.AppendElement(domFile);
     } else {
       continue; // Not much we can do if the file doesn't exist
     }
 
   }
 
   SetFiles(files, true);
@@ -2559,37 +2569,37 @@ HTMLInputElement::GetDisplayFileName(nsA
     nsContentUtils::FormatLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
                                           "XFilesSelected", params, value);
   }
 
   aValue = value;
 }
 
 void
-HTMLInputElement::SetFiles(const nsTArray<nsCOMPtr<nsIDOMFile> >& aFiles,
+HTMLInputElement::SetFiles(const nsTArray<nsRefPtr<DOMFile>>& aFiles,
                            bool aSetValueChanged)
 {
   mFiles.Clear();
   mFiles.AppendElements(aFiles);
 
   AfterSetFiles(aSetValueChanged);
 }
 
 void
 HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
                            bool aSetValueChanged)
 {
+  nsRefPtr<nsDOMFileList> files = static_cast<nsDOMFileList*>(aFiles);
   mFiles.Clear();
 
   if (aFiles) {
     uint32_t listLength;
     aFiles->GetLength(&listLength);
     for (uint32_t i = 0; i < listLength; i++) {
-      nsCOMPtr<nsIDOMFile> file;
-      aFiles->Item(i, getter_AddRefs(file));
+      nsRefPtr<DOMFile> file = files->Item(i);
       mFiles.AppendElement(file);
     }
   }
 
   AfterSetFiles(aSetValueChanged);
 }
 
 void
@@ -2779,17 +2789,17 @@ HTMLInputElement::DispatchProgressEvent(
 }
 
 nsresult
 HTMLInputElement::UpdateFileList()
 {
   if (mFileList) {
     mFileList->Clear();
 
-    const nsTArray<nsCOMPtr<nsIDOMFile> >& files = GetFilesInternal();
+    const nsTArray<nsRefPtr<DOMFile>>& files = GetFilesInternal();
     for (uint32_t i = 0; i < files.Length(); ++i) {
       if (!mFileList->Append(files[i])) {
         return NS_ERROR_FAILURE;
       }
     }
   }
 
   return NS_OK;
@@ -5629,17 +5639,17 @@ HTMLInputElement::SubmitNamesValues(nsFo
   }
 
   //
   // Submit file if its input type=file and this encoding method accepts files
   //
   if (mType == NS_FORM_INPUT_FILE) {
     // Submit files
 
-    const nsTArray<nsCOMPtr<nsIDOMFile> >& files = GetFilesInternal();
+    const nsTArray<nsRefPtr<DOMFile>>& files = GetFilesInternal();
 
     for (uint32_t i = 0; i < files.Length(); ++i) {
       aFormSubmission->AddNameFilePair(name, files[i], NullString());
     }
 
     if (files.IsEmpty()) {
       // If no file was selected, pretend we had an empty file with an
       // empty filename.
@@ -5877,17 +5887,17 @@ HTMLInputElement::RestoreState(nsPresSta
       case VALUE_MODE_DEFAULT_ON:
         if (inputState->IsCheckedSet()) {
           restoredCheckedState = true;
           DoSetChecked(inputState->GetChecked(), true, true);
         }
         break;
       case VALUE_MODE_FILENAME:
         {
-          const nsTArray<nsCOMPtr<nsIDOMFile> >& files = inputState->GetFiles();
+          const nsTArray<nsRefPtr<DOMFile>>& files = inputState->GetFiles();
           SetFiles(files, true);
         }
         break;
       case VALUE_MODE_VALUE:
       case VALUE_MODE_DEFAULT:
         if (GetValueMode() == VALUE_MODE_DEFAULT &&
             mType != NS_FORM_INPUT_HIDDEN) {
           break;
@@ -6387,17 +6397,17 @@ HTMLInputElement::IsValueMissing() const
     return false;
   }
 
   switch (GetValueMode()) {
     case VALUE_MODE_VALUE:
       return IsValueEmpty();
     case VALUE_MODE_FILENAME:
     {
-      const nsTArray<nsCOMPtr<nsIDOMFile> >& files = GetFilesInternal();
+      const nsTArray<nsRefPtr<DOMFile>>& files = GetFilesInternal();
       return files.IsEmpty();
     }
     case VALUE_MODE_DEFAULT_ON:
       // This should not be used for type radio.
       // See the MOZ_ASSERT at the beginning of the method.
       return !mChecked;
     case VALUE_MODE_DEFAULT:
     default:
--- a/content/html/content/src/HTMLInputElement.h
+++ b/content/html/content/src/HTMLInputElement.h
@@ -19,30 +19,31 @@
 #include "mozilla/dom/HTMLFormElement.h" // for HasEverTriedInvalidSubmit()
 #include "mozilla/dom/HTMLInputElementBinding.h"
 #include "nsIFilePicker.h"
 #include "nsIContentPrefService2.h"
 #include "mozilla/Decimal.h"
 #include "nsContentUtils.h"
 #include "nsTextEditorState.h"
 
-class nsDOMFileList;
 class nsIRadioGroupContainer;
 class nsIRadioGroupVisitor;
 class nsIRadioVisitor;
 
 namespace mozilla {
 
 class EventChainPostVisitor;
 class EventChainPreVisitor;
 
 namespace dom {
 
 class Date;
 class DirPickerFileListBuilderTask;
+class DOMFile;
+class nsDOMFileList;
 
 class UploadLastDir MOZ_FINAL : public nsIObserver, public nsSupportsWeakReference {
 
   ~UploadLastDir() {}
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
@@ -205,22 +206,22 @@ public:
   NS_IMETHOD_(void) UpdatePlaceholderVisibility(bool aNotify) MOZ_OVERRIDE;
   NS_IMETHOD_(bool) GetPlaceholderVisibility() MOZ_OVERRIDE;
   NS_IMETHOD_(void) InitializeKeyboardEventListeners() MOZ_OVERRIDE;
   NS_IMETHOD_(void) OnValueChanged(bool aNotify) MOZ_OVERRIDE;
   NS_IMETHOD_(bool) HasCachedSelection() MOZ_OVERRIDE;
 
   void GetDisplayFileName(nsAString& aFileName) const;
 
-  const nsTArray<nsCOMPtr<nsIDOMFile> >& GetFilesInternal() const
+  const nsTArray<nsRefPtr<DOMFile>>& GetFilesInternal() const
   {
     return mFiles;
   }
 
-  void SetFiles(const nsTArray<nsCOMPtr<nsIDOMFile> >& aFiles, bool aSetValueChanged);
+  void SetFiles(const nsTArray<nsRefPtr<DOMFile>>& aFiles, bool aSetValueChanged);
   void SetFiles(nsIDOMFileList* aFiles, bool aSetValueChanged);
 
   // Called when a nsIFilePicker or a nsIColorPicker terminate.
   void PickerClosed();
 
   void SetCheckedChangedInternal(bool aCheckedChanged);
   bool GetCheckedChanged() const {
     return mCheckedChanged;
@@ -1246,17 +1247,17 @@ protected:
    * used when uploading a file. It is vital that this is kept separate from
    * mValue so that it won't be possible to 'leak' the value from a text-input
    * to a file-input. Additionally, the logic for this value is kept as simple
    * as possible to avoid accidental errors where the wrong filename is used.
    * Therefor the list of filenames is always owned by this member, never by
    * the frame. Whenever the frame wants to change the filename it has to call
    * SetFileNames to update this member.
    */
-  nsTArray<nsCOMPtr<nsIDOMFile> >   mFiles;
+  nsTArray<nsRefPtr<DOMFile>> mFiles;
 
   nsRefPtr<nsDOMFileList>  mFileList;
 
   nsRefPtr<DirPickerFileListBuilderTask> mDirPickerFileListBuilderTask;
 
   nsString mStaticDocFileList;
   
   /** 
--- a/content/html/content/test/test_formData.html
+++ b/content/html/content/test/test_formData.html
@@ -47,22 +47,22 @@ function runTest() {
     }
 
     var file, blob = new Blob(['hey'], {type: 'text/plain'});
 
     var fd = new FormData();
     fd.append("empty", blob);
     fd.append("explicit", blob, "explicit-file-name");
     fd.append("explicit-empty", blob, "");
-    file = SpecialPowers.unwrap(SpecialPowers.wrap(window).File(blob, {name: 'testname'}));
+    file = new File([blob], 'testname',  {type: 'text/plain'});
     fd.append("file-name", file);
-    file = SpecialPowers.unwrap(SpecialPowers.wrap(window).File(blob, {name: ''}));
+    file = new File([blob], '',  {type: 'text/plain'});
     fd.append("empty-file-name", file);
-    file = SpecialPowers.unwrap(SpecialPowers.wrap(window).File(blob, {name: 'testname'}));
+    file = new File([blob], 'testname',  {type: 'text/plain'});
     fd.append("file-name-overwrite", file, "overwrite");
     xhr.responseType = 'json';
     xhr.send(fd);
 }
 
 runTest()
 </script>
 </body>
-</html>
\ No newline at end of file
+</html>
--- a/content/media/EncodedBufferCache.cpp
+++ b/content/media/EncodedBufferCache.cpp
@@ -34,40 +34,42 @@ EncodedBufferCache::AppendBuffer(nsTArra
         NS_WARNING("Failed to write media cache block!");
       }
     }
     mEncodedBuffers.Clear();
   }
 
 }
 
-already_AddRefed<nsIDOMBlob>
-EncodedBufferCache::ExtractBlob(const nsAString &aContentType)
+already_AddRefed<dom::DOMFile>
+EncodedBufferCache::ExtractBlob(nsISupports* aParent,
+                                const nsAString &aContentType)
 {
   MutexAutoLock lock(mMutex);
-  nsCOMPtr<nsIDOMBlob> blob;
+  nsRefPtr<dom::DOMFile> blob;
   if (mTempFileEnabled) {
     // generate new temporary file to write
-    blob = dom::DOMFile::CreateTemporaryFileBlob(mFD, 0, mDataSize,
+    blob = dom::DOMFile::CreateTemporaryFileBlob(aParent, mFD, 0, mDataSize,
                                                  aContentType);
     // fallback to memory blob
     mTempFileEnabled = false;
     mDataSize = 0;
     mFD = nullptr;
   } else {
     void* blobData = moz_malloc(mDataSize);
     NS_ASSERTION(blobData, "out of memory!!");
 
     if (blobData) {
       for (uint32_t i = 0, offset = 0; i < mEncodedBuffers.Length(); i++) {
         memcpy((uint8_t*)blobData + offset, mEncodedBuffers.ElementAt(i).Elements(),
                mEncodedBuffers.ElementAt(i).Length());
         offset += mEncodedBuffers.ElementAt(i).Length();
       }
-      blob = dom::DOMFile::CreateMemoryFile(blobData, mDataSize, aContentType);
+      blob = dom::DOMFile::CreateMemoryFile(aParent, blobData, mDataSize,
+                                            aContentType);
       mEncodedBuffers.Clear();
     } else
       return nullptr;
   }
   mDataSize = 0;
   return blob.forget();
 }
 
--- a/content/media/EncodedBufferCache.h
+++ b/content/media/EncodedBufferCache.h
@@ -11,16 +11,20 @@
 #include "nsTArray.h"
 #include "mozilla/Mutex.h"
 
 struct PRFileDesc;
 class nsIDOMBlob;
 
 namespace mozilla {
 
+namespace dom {
+class DOMFile;
+}
+
 class ReentrantMonitor;
 /**
  * Data is moved into a temporary file when it grows beyond
  * the maximal size passed in the Init function.
  * The AppendBuffer and ExtractBlob methods are thread-safe and can be called on
  * different threads at the same time.
  */
 class EncodedBufferCache
@@ -34,17 +38,17 @@ public:
     mTempFileEnabled(false) { }
   ~EncodedBufferCache()
   {
   }
   // Append buffers in cache, check if the queue is too large then switch to write buffer to file system
   // aBuf will append to mEncodedBuffers or temporary File, aBuf also be cleared
   void AppendBuffer(nsTArray<uint8_t> & aBuf);
   // Read all buffer from memory or file System, also Remove the temporary file or clean the buffers in memory.
-  already_AddRefed<nsIDOMBlob> ExtractBlob(const nsAString &aContentType);
+  already_AddRefed<dom::DOMFile> ExtractBlob(nsISupports* aParent, const nsAString &aContentType);
 
 private:
   //array for storing the encoded data.
   nsTArray<nsTArray<uint8_t> > mEncodedBuffers;
   // File handle for the temporary file
   PRFileDesc* mFD;
   // Used to protect the mEncodedBuffer for avoiding AppendBuffer/Consume on different thread at the same time.
   Mutex mMutex;
--- a/content/media/MediaRecorder.cpp
+++ b/content/media/MediaRecorder.cpp
@@ -384,17 +384,18 @@ public:
     mTrackUnionStream->ChangeExplicitBlockerCount(-1);
 
     return NS_OK;
   }
 
   already_AddRefed<nsIDOMBlob> GetEncodedData()
   {
     MOZ_ASSERT(NS_IsMainThread());
-    return mEncodedBufferCache->ExtractBlob(mMimeType);
+    return mEncodedBufferCache->ExtractBlob(mRecorder->GetParentObject(),
+                                            mMimeType);
   }
 
   bool IsEncoderError()
   {
     if (mEncoder && mEncoder->HasError()) {
       return true;
     }
     return false;
@@ -915,17 +916,20 @@ MediaRecorder::CreateAndDispatchBlobEven
   if (!CheckPrincipal()) {
     // Media is not same-origin, don't allow the data out.
     nsRefPtr<nsIDOMBlob> blob = aBlob;
     return NS_ERROR_DOM_SECURITY_ERR;
   }
   BlobEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
-  init.mData = aBlob;
+
+  nsCOMPtr<nsIDOMBlob> blob = aBlob;
+  init.mData = static_cast<DOMFile*>(blob.get());
+
   nsRefPtr<BlobEvent> event =
     BlobEvent::Constructor(this,
                            NS_LITERAL_STRING("dataavailable"),
                            init);
   event->SetTrusted(true);
   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
--- a/content/media/imagecapture/CaptureTask.cpp
+++ b/content/media/imagecapture/CaptureTask.cpp
@@ -18,16 +18,22 @@ nsresult
 CaptureTask::TaskComplete(already_AddRefed<dom::DOMFile> aBlob, nsresult aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   DetachStream();
 
   nsresult rv;
   nsRefPtr<dom::DOMFile> blob(aBlob);
+
+  // We have to set the parent because the blob has been generated with a valid one.
+  if (blob) {
+    blob = new dom::DOMFile(mImageCapture->GetParentObject(), blob->Impl());
+  }
+
   if (mPrincipalChanged) {
     aRv = NS_ERROR_DOM_SECURITY_ERR;
     IC_LOG("MediaStream principal should not change during TakePhoto().");
   }
 
   if (NS_SUCCEEDED(aRv)) {
     rv = mImageCapture->PostBlobEvent(blob);
   } else {
--- a/content/media/imagecapture/ImageCapture.cpp
+++ b/content/media/imagecapture/ImageCapture.cpp
@@ -167,17 +167,17 @@ ImageCapture::TakePhoto(ErrorResult& aRe
 
     // It adds itself into MediaStreamGraph, so ImageCapture doesn't need to hold
     // the reference.
     task->AttachStream();
   }
 }
 
 nsresult
-ImageCapture::PostBlobEvent(nsIDOMBlob* aBlob)
+ImageCapture::PostBlobEvent(DOMFile* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!CheckPrincipal()) {
     // Media is not same-origin, don't allow the data out.
     return PostErrorEvent(ImageCaptureError::PHOTO_ERROR, NS_ERROR_DOM_SECURITY_ERR);
   }
 
   BlobEventInit init;
--- a/content/media/imagecapture/ImageCapture.h
+++ b/content/media/imagecapture/ImageCapture.h
@@ -27,16 +27,17 @@ PRLogModuleInfo* GetICLog();
 #ifndef IC_LOG
 #define IC_LOG(...)
 #endif
 
 #endif // PR_LOGGING
 
 namespace dom {
 
+class DOMFile;
 class VideoStreamTrack;
 
 /**
  *  Implementation of https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-
  *  capture/ImageCapture.html.
  *  The ImageCapture accepts a VideoStreamTrack as input source. The image will
  *  be sent back as a JPG format via Blob event.
  *
@@ -74,17 +75,17 @@ public:
 
   static already_AddRefed<ImageCapture> Constructor(const GlobalObject& aGlobal,
                                                     VideoStreamTrack& aTrack,
                                                     ErrorResult& aRv);
 
   ImageCapture(VideoStreamTrack* aVideoStreamTrack, nsPIDOMWindow* aOwnerWindow);
 
   // Post a Blob event to script.
-  nsresult PostBlobEvent(nsIDOMBlob* aBlob);
+  nsresult PostBlobEvent(DOMFile* aBlob);
 
   // Post an error event to script.
   // aErrorCode should be one of error codes defined in ImageCaptureError.h.
   // aReason is the nsresult which maps to a error string in dom/base/domerr.msg.
   nsresult PostErrorEvent(uint16_t aErrorCode, nsresult aReason = NS_OK);
 
   bool CheckPrincipal();
 
--- a/content/media/webrtc/MediaEngineDefault.cpp
+++ b/content/media/webrtc/MediaEngineDefault.cpp
@@ -203,17 +203,17 @@ MediaEngineDefaultVideoSource::Snapshot(
   nsCOMPtr<nsIFile> localFile;
   filePicker->GetFile(getter_AddRefs(localFile));
 
   if (!localFile) {
     *aFile = nullptr;
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMFile> domFile = dom::DOMFile::CreateFromFile(localFile);
+  nsCOMPtr<nsIDOMFile> domFile = dom::DOMFile::CreateFromFile(nullptr, localFile);
   domFile.forget(aFile);
   return NS_OK;
 #endif
 }
 
 NS_IMETHODIMP
 MediaEngineDefaultVideoSource::Notify(nsITimer* aTimer)
 {
--- a/content/media/webrtc/MediaEngineWebRTCVideo.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCVideo.cpp
@@ -939,17 +939,17 @@ MediaEngineWebRTCVideoSource::OnTakePict
       mCallbacks.SwapElements(aCallbacks);
       mPhoto.AppendElements(aData, aLength);
       mMimeType = aMimeType;
     }
 
     NS_IMETHOD Run()
     {
       nsRefPtr<dom::DOMFile> blob =
-        dom::DOMFile::CreateMemoryFile(mPhoto.Elements(), mPhoto.Length(), mMimeType);
+        dom::DOMFile::CreateMemoryFile(nullptr, mPhoto.Elements(), mPhoto.Length(), mMimeType);
       uint32_t callbackCounts = mCallbacks.Length();
       for (uint8_t i = 0; i < callbackCounts; i++) {
         nsRefPtr<dom::DOMFile> tempBlob = blob;
         mCallbacks[i]->PhotoComplete(tempBlob.forget());
       }
       // PhotoCallback needs to dereference on main thread.
       mCallbacks.Clear();
       return NS_OK;
--- a/dom/archivereader/ArchiveReader.cpp
+++ b/dom/archivereader/ArchiveReader.cpp
@@ -4,36 +4,35 @@
  * 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 "ArchiveReader.h"
 #include "ArchiveRequest.h"
 #include "ArchiveEvent.h"
 #include "ArchiveZipEvent.h"
 
+#include "nsDOMFile.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 
 #include "mozilla/dom/ArchiveReaderBinding.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/EncodingUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 USING_ARCHIVEREADER_NAMESPACE
 
 /* static */ already_AddRefed<ArchiveReader>
 ArchiveReader::Constructor(const GlobalObject& aGlobal,
-                           nsIDOMBlob* aBlob,
+                           DOMFile& aBlob,
                            const ArchiveReaderOptions& aOptions,
                            ErrorResult& aError)
 {
-  MOZ_ASSERT(aBlob);
-
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aError.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsAutoCString encoding;
   if (!EncodingUtils::FindEncodingForLabelNoReplacement(aOptions.mEncoding,
@@ -42,24 +41,23 @@ ArchiveReader::Constructor(const GlobalO
     return nullptr;
   }
 
   nsRefPtr<ArchiveReader> reader =
     new ArchiveReader(aBlob, window, encoding);
   return reader.forget();
 }
 
-ArchiveReader::ArchiveReader(nsIDOMBlob* aBlob, nsPIDOMWindow* aWindow,
+ArchiveReader::ArchiveReader(DOMFile& aBlob, nsPIDOMWindow* aWindow,
                              const nsACString& aEncoding)
-  : mBlob(aBlob)
+  : mBlob(&aBlob)
   , mWindow(aWindow)
   , mStatus(NOT_STARTED)
   , mEncoding(aEncoding)
 {
-  MOZ_ASSERT(aBlob);
   MOZ_ASSERT(aWindow);
 }
 
 ArchiveReader::~ArchiveReader()
 {
 }
 
 /* virtual */ JSObject*
--- a/dom/archivereader/ArchiveReader.h
+++ b/dom/archivereader/ArchiveReader.h
@@ -14,16 +14,17 @@
 #include "nsCOMArray.h"
 #include "nsIChannel.h"
 #include "nsIDOMFile.h"
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
 namespace dom {
 struct ArchiveReaderOptions;
+class DOMFile;
 class GlobalObject;
 } // namespace dom
 } // namespace mozilla
 
 BEGIN_ARCHIVEREADER_NAMESPACE
 
 class ArchiveRequest;
 
@@ -33,20 +34,20 @@ class ArchiveRequest;
 class ArchiveReader MOZ_FINAL : public nsISupports,
                                 public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ArchiveReader)
 
   static already_AddRefed<ArchiveReader>
-  Constructor(const GlobalObject& aGlobal, nsIDOMBlob* aBlob,
+  Constructor(const GlobalObject& aGlobal, DOMFile& aBlob,
               const ArchiveReaderOptions& aOptions, ErrorResult& aError);
 
-  ArchiveReader(nsIDOMBlob* aBlob, nsPIDOMWindow* aWindow,
+  ArchiveReader(DOMFile& aBlob, nsPIDOMWindow* aWindow,
                 const nsACString& aEncoding);
 
   nsIDOMWindow* GetParentObject() const
   {
     return mWindow;
   }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
@@ -70,17 +71,17 @@ private:
   already_AddRefed<ArchiveRequest> GenerateArchiveRequest();
 
   nsresult OpenArchive();
 
   void RequestReady(ArchiveRequest* aRequest);
 
 protected:
   // The archive blob/file
-  nsCOMPtr<nsIDOMBlob> mBlob;
+  nsRefPtr<DOMFile> mBlob;
 
   // The window is needed by the requests
   nsCOMPtr<nsPIDOMWindow> mWindow;
 
   // Are we ready to return data?
   enum {
     NOT_STARTED = 0,
     WORKING,
--- a/dom/archivereader/ArchiveZipEvent.cpp
+++ b/dom/archivereader/ArchiveZipEvent.cpp
@@ -79,17 +79,17 @@ nsIDOMFile*
 ArchiveZipItem::File(ArchiveReader* aArchiveReader)
 {
   nsString filename;
 
   if (NS_FAILED(GetFilename(filename))) {
     return nullptr;
   }
 
-  return new DOMFile(
+  return new DOMFile(aArchiveReader,
     new ArchiveZipFileImpl(filename,
                            NS_ConvertUTF8toUTF16(GetType()),
                            StrToInt32(mCentralStruct.orglen),
                            mCentralStruct, aArchiveReader));
 }
 
 uint32_t
 ArchiveZipItem::StrToInt32(const uint8_t* aStr)
--- a/dom/archivereader/ArchiveZipFile.cpp
+++ b/dom/archivereader/ArchiveZipFile.cpp
@@ -2,20 +2,22 @@
 /* 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 "ArchiveZipFile.h"
 #include "ArchiveZipEvent.h"
 
+#include "nsDOMFile.h"
 #include "nsIInputStream.h"
 #include "zlib.h"
 #include "mozilla/Attributes.h"
 
+using namespace mozilla::dom;
 USING_ARCHIVEREADER_NAMESPACE
 
 #define ZIP_CHUNK 16384
 
 /**
  * Input stream object for zip files
  */
 class ArchiveInputStream MOZ_FINAL : public nsIInputStream,
@@ -394,17 +396,18 @@ ArchiveZipFileImpl::Traverse(nsCycleColl
 {
   ArchiveZipFileImpl* tmp = this;
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArchiveReader);
 }
 
 already_AddRefed<mozilla::dom::DOMFileImpl>
 ArchiveZipFileImpl::CreateSlice(uint64_t aStart,
                                 uint64_t aLength,
-                                const nsAString& aContentType)
+                                const nsAString& aContentType,
+                                ErrorResult& aRv)
 {
   nsRefPtr<DOMFileImpl> impl =
     new ArchiveZipFileImpl(mFilename, mContentType, aStart, mLength, mCentral,
                            mArchiveReader);
   return impl.forget();
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(ArchiveZipFileImpl, DOMFileImpl)
--- a/dom/archivereader/ArchiveZipFile.h
+++ b/dom/archivereader/ArchiveZipFile.h
@@ -66,19 +66,19 @@ public:
   }
 
 protected:
   virtual ~ArchiveZipFileImpl()
   {
     MOZ_COUNT_DTOR(ArchiveZipFileImpl);
   }
 
-  virtual already_AddRefed<DOMFileImpl> CreateSlice(uint64_t aStart,
-                                                    uint64_t aLength,
-                                                    const nsAString& aContentType) MOZ_OVERRIDE;
+  virtual already_AddRefed<DOMFileImpl>
+  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
+              ErrorResult& aRv) MOZ_OVERRIDE;
 
 private: // Data
   ZipCentral mCentral;
   nsRefPtr<ArchiveReader> mArchiveReader;
 
   nsString mFilename;
 };
 
--- a/dom/base/ImageEncoder.cpp
+++ b/dom/base/ImageEncoder.cpp
@@ -83,18 +83,20 @@ public:
   {}
 
   NS_IMETHOD Run()
   {
     nsresult rv = NS_OK;
     MOZ_ASSERT(NS_IsMainThread());
 
     if (!mFailed) {
+      // The correct parentObject has to be set by the mEncodeCompleteCallback.
       nsRefPtr<DOMFile> blob =
-        DOMFile::CreateMemoryFile(mImgData, mImgSize, mType);
+        DOMFile::CreateMemoryFile(nullptr, mImgData, mImgSize, mType);
+      MOZ_ASSERT(blob);
 
       rv = mEncodeCompleteCallback->ReceiveBlob(blob.forget());
     }
 
     mEncodeCompleteCallback = nullptr;
 
     mEncoderThread->Shutdown();
     return rv;
--- a/dom/base/ImageEncoder.h
+++ b/dom/base/ImageEncoder.h
@@ -46,27 +46,31 @@ public:
   // fall back to a PNG encoder. aOptions are the options to be passed to the
   // encoder and aUsingCustomOptions specifies whether custom parse options were
   // used (i.e. by using -moz-parse-options). If there are any unrecognized
   // custom parse options, we fall back to the default values for the encoder
   // without any options at all. A return value of NS_OK only implies
   // successful dispatching of the extraction step to the encoding thread.
   // aEncodeCallback will be called on main thread when encoding process is
   // success.
+  // Note: The callback has to set a valid parent for content for the generated
+  // Blob object.
   static nsresult ExtractDataAsync(nsAString& aType,
                                    const nsAString& aOptions,
                                    bool aUsingCustomOptions,
                                    uint8_t* aImageBuffer,
                                    int32_t aFormat,
                                    const nsIntSize aSize,
                                    EncodeCompleteCallback* aEncodeCallback);
 
   // Extract an Image asynchronously. Its function is same as ExtractDataAsync
   // except for the parameters. aImage is the uncompressed data. aEncodeCallback
   // will be called on main thread when encoding process is success.
+  // Note: The callback has to set a valid parent for content for the generated
+  // Blob object.
   static nsresult ExtractDataFromLayersImageAsync(nsAString& aType,
                                                   const nsAString& aOptions,
                                                   bool aUsingCustomOptions,
                                                   layers::Image* aImage,
                                                   EncodeCompleteCallback* aEncodeCallback);
 
   // Gives you a stream containing the image represented by aImageBuffer.
   // The format is given in aFormat, for example
--- a/dom/base/MessagePort.cpp
+++ b/dom/base/MessagePort.cpp
@@ -1,27 +1,28 @@
 /* -*- 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 "MessagePort.h"
 #include "MessageEvent.h"
+#include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/MessageChannel.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/MessagePortList.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "nsContentUtils.h"
+#include "nsDOMFile.h"
 #include "nsGlobalWindow.h"
 #include "nsPresContext.h"
 #include "ScriptSettings.h"
 
 #include "nsIDocument.h"
-#include "nsIDOMFile.h"
 #include "nsIDOMFileList.h"
 #include "nsIPresShell.h"
 
 namespace mozilla {
 namespace dom {
 
 class DispatchEventRunnable : public nsRunnable
 {
@@ -98,17 +99,47 @@ struct StructuredCloneInfo
 
 static JSObject*
 PostMessageReadStructuredClone(JSContext* cx,
                                JSStructuredCloneReader* reader,
                                uint32_t tag,
                                uint32_t data,
                                void* closure)
 {
-  if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
+  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
+  NS_ASSERTION(scInfo, "Must have scInfo!");
+
+  if (tag == SCTAG_DOM_BLOB) {
+    NS_ASSERTION(!data, "Data should be empty");
+
+    // What we get back from the reader is a DOMFileImpl.
+    // From that we create a new DOMFile.
+    DOMFileImpl* blobImpl;
+    if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) {
+      MOZ_ASSERT(blobImpl);
+
+      // nsRefPtr<DOMFile> needs to go out of scope before toObjectOrNull() is
+      // called because the static analysis thinks dereferencing XPCOM objects
+      // can GC (because in some cases it can!), and a return statement with a
+      // JSObject* type means that JSObject* is on the stack as a raw pointer
+      // while destructors are running.
+      JS::Rooted<JS::Value> val(cx);
+      {
+        nsRefPtr<DOMFile> blob = new DOMFile(scInfo->mPort->GetParentObject(),
+                                             blobImpl);
+        if (!WrapNewBindingObject(cx, blob, &val)) {
+          return nullptr;
+        }
+      }
+
+      return &val.toObject();
+    }
+  }
+
+  if (tag == SCTAG_DOM_FILELIST) {
     NS_ASSERTION(!data, "Data should be empty");
 
     nsISupports* supports;
     if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
       JS::Rooted<JS::Value> val(cx);
       if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) {
         return val.toObjectOrNull();
       }
@@ -129,28 +160,36 @@ static bool
 PostMessageWriteStructuredClone(JSContext* cx,
                                 JSStructuredCloneWriter* writer,
                                 JS::Handle<JSObject*> obj,
                                 void *closure)
 {
   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
   NS_ASSERTION(scInfo, "Must have scInfo!");
 
+  // See if this is a File/Blob object.
+  {
+    DOMFile* blob = nullptr;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
+      DOMFileImpl* blobImpl = blob->Impl();
+      if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
+          JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
+        scInfo->mEvent->StoreISupports(blobImpl);
+        return true;
+      }
+    }
+  }
+
   nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
   nsContentUtils::XPConnect()->
     GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
   if (wrappedNative) {
     uint32_t scTag = 0;
     nsISupports* supports = wrappedNative->Native();
 
-    nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
-    if (blob) {
-      scTag = SCTAG_DOM_BLOB;
-    }
-
     nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
     if (list) {
       scTag = SCTAG_DOM_FILELIST;
     }
 
     if (scTag) {
       return JS_WriteUint32Pair(writer, scTag, 0) &&
              JS_WriteBytes(writer, &supports, sizeof(supports)) &&
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -8,16 +8,17 @@
 #include "base/basictypes.h"
 
 #include "Navigator.h"
 #include "nsIXULAppInfo.h"
 #include "nsPluginArray.h"
 #include "nsMimeTypeArray.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/DesktopNotification.h"
+#include "nsDOMFile.h"
 #include "nsGeolocation.h"
 #include "nsIHttpProtocolHandler.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsISupportsPriority.h"
 #include "nsICachingChannel.h"
@@ -1150,24 +1151,24 @@ Navigator::SendBeacon(const nsAString& a
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       mimeType.AssignLiteral("application/octet-stream");
       in = strStream;
 
     } else if (aData.Value().IsBlob()) {
-      nsCOMPtr<nsIDOMBlob> blob = aData.Value().GetAsBlob();
-      rv = blob->GetInternalStream(getter_AddRefs(in));
+      DOMFile& blob = aData.Value().GetAsBlob();
+      rv = blob.GetInternalStream(getter_AddRefs(in));
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       nsAutoString type;
-      rv = blob->GetType(type);
+      rv = blob.GetType(type);
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       mimeType = NS_ConvertUTF16toUTF8(type);
 
     } else if (aData.Value().IsFormData()) {
       nsFormData& form = aData.Value().GetAsFormData();
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -20,17 +20,16 @@
 #include "nsTArray.h"
 
 class nsPluginArray;
 class nsMimeTypeArray;
 class nsPIDOMWindow;
 class nsIDOMNavigatorSystemMessages;
 class nsDOMCameraManager;
 class nsDOMDeviceStorage;
-class nsIDOMBlob;
 class nsIPrincipal;
 class nsIURI;
 
 namespace mozilla {
 namespace dom {
 class Geolocation;
 class systemMessageCallback;
 struct MediaStreamConstraints;
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -106,25 +106,22 @@ URL::Constructor(const GlobalObject& aGl
   }
 
   nsRefPtr<URL> url = new URL(uri);
   return url.forget();
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal,
-                     nsIDOMBlob* aBlob,
+                     DOMFile& aBlob,
                      const objectURLOptions& aOptions,
                      nsString& aResult,
                      ErrorResult& aError)
 {
-  DOMFile* blob = static_cast<DOMFile*>(aBlob);
-  MOZ_ASSERT(blob);
-
-  CreateObjectURLInternal(aGlobal, blob->Impl(),
+  CreateObjectURLInternal(aGlobal, aBlob.Impl(),
                           NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult,
                           aError);
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
                      const mozilla::dom::objectURLOptions& aOptions,
                      nsString& aResult,
--- a/dom/base/URL.h
+++ b/dom/base/URL.h
@@ -18,16 +18,17 @@ class nsIURI;
 
 namespace mozilla {
 
 class ErrorResult;
 class DOMMediaStream;
 
 namespace dom {
 
+class DOMFile;
 class MediaSource;
 class GlobalObject;
 struct objectURLOptions;
 
 namespace workers {
 class URLProxy;
 }
 
@@ -48,17 +49,17 @@ public:
   static already_AddRefed<URL>
   Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
               URL& aBase, ErrorResult& aRv);
   static already_AddRefed<URL>
   Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
               const nsAString& aBase, ErrorResult& aRv);
 
   static void CreateObjectURL(const GlobalObject& aGlobal,
-                              nsIDOMBlob* aBlob,
+                              DOMFile& aBlob,
                               const objectURLOptions& aOptions,
                               nsString& aResult,
                               ErrorResult& aError);
   static void CreateObjectURL(const GlobalObject& aGlobal,
                               DOMMediaStream& aStream,
                               const objectURLOptions& aOptions,
                               nsString& aResult,
                               ErrorResult& aError);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -96,20 +96,16 @@
 #include "nsITreeSelection.h"
 #include "nsITreeContentView.h"
 #include "nsITreeView.h"
 #include "nsIXULTemplateBuilder.h"
 #include "nsITreeColumns.h"
 #endif
 #include "nsIDOMXPathNSResolver.h"
 
-// Drag and drop
-#include "nsIDOMFile.h"
-#include "nsDOMBlobBuilder.h" // nsDOMMultipartFile
-
 #include "nsIEventListenerService.h"
 #include "nsIMessageManager.h"
 
 #include "mozilla/dom/TouchEvent.h"
 
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 
@@ -289,21 +285,16 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(XSLTProcessor, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(XPathNSResolver, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(Blob, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(File, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
   NS_DEFINE_CLASSINFO_DATA(MozSmsMessage, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MozMmsMessage, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MozMobileMessageThread, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -367,18 +358,16 @@ struct nsConstructorFuncMapData
   nsDOMConstructorFunc mConstructorFunc;
 };
 
 #define NS_DEFINE_CONSTRUCTOR_FUNC_DATA(_class, _func)                        \
   { eDOMClassInfo_##_class##_id, _func },
 
 static const nsConstructorFuncMapData kConstructorFuncMap[] =
 {
-  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Blob, DOMMultipartFileImpl::NewBlob)
-  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, DOMMultipartFileImpl::NewFile)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XSLTProcessor, XSLTProcessorCtor)
 };
 #undef NS_DEFINE_CONSTRUCTOR_FUNC_DATA
 
 nsIXPConnect *nsDOMClassInfo::sXPConnect = nullptr;
 bool nsDOMClassInfo::sIsInitialized = false;
 
 
@@ -790,25 +779,16 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessor)
     DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessorPrivate)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(XPathNSResolver, nsIDOMXPathNSResolver)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathNSResolver)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(Blob, nsIDOMBlob)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBlob)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(File, nsIDOMFile)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBlob)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMFile)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(MozSmsMessage, nsIDOMMozSmsMessage)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsMessage)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozMmsMessage, nsIDOMMozMmsMessage)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozMmsMessage)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -38,19 +38,16 @@ DOMCI_CLASS(CSSMozDocumentRule)
 DOMCI_CLASS(CSSSupportsRule)
 
 // XSLTProcessor
 DOMCI_CLASS(XSLTProcessor)
 
 // DOM Level 3 XPath objects
 DOMCI_CLASS(XPathNSResolver)
 
-DOMCI_CLASS(Blob)
-DOMCI_CLASS(File)
-
 DOMCI_CLASS(MozSmsMessage)
 DOMCI_CLASS(MozMmsMessage)
 DOMCI_CLASS(MozMobileMessageThread)
 
 // @font-face in CSS
 DOMCI_CLASS(CSSFontFaceRule)
 
 DOMCI_CLASS(ContentFrameMessageManager)
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2848,17 +2848,25 @@ nsDOMWindowUtils::WrapDOMFile(nsIFile *a
                               nsIDOMFile **aDOMFile)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   if (!aFile) {
     return NS_ERROR_FAILURE;
   }
 
-  nsRefPtr<DOMFile> file = DOMFile::CreateFromFile(aFile);
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+  NS_ENSURE_STATE(window);
+
+  nsPIDOMWindow* innerWindow = window->GetCurrentInnerWindow();
+  if (!innerWindow) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<DOMFile> file = DOMFile::CreateFromFile(innerWindow, aFile);
   file.forget(aDOMFile);
   return NS_OK;
 }
 
 #ifdef DEBUG
 static bool
 CheckLeafLayers(Layer* aLayer, const nsIntPoint& aOffset, nsIntRegion* aCoveredRegion)
 {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7873,28 +7873,42 @@ struct StructuredCloneInfo {
 
 static JSObject*
 PostMessageReadStructuredClone(JSContext* cx,
                                JSStructuredCloneReader* reader,
                                uint32_t tag,
                                uint32_t data,
                                void* closure)
 {
+  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
+  NS_ASSERTION(scInfo, "Must have scInfo!");
+
   if (tag == SCTAG_DOM_BLOB) {
     NS_ASSERTION(!data, "Data should be empty");
 
     // What we get back from the reader is a DOMFileImpl.
     // From that we create a new DOMFile.
-    nsISupports* supports;
-    if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
-      nsCOMPtr<nsIDOMBlob> file = new DOMFile(static_cast<DOMFileImpl*>(supports));
+    DOMFileImpl* blobImpl;
+    if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) {
+      MOZ_ASSERT(blobImpl);
+
+      // nsRefPtr<DOMFile> needs to go out of scope before toObjectOrNull() is
+      // called because the static analysis thinks dereferencing XPCOM objects
+      // can GC (because in some cases it can!), and a return statement with a
+      // JSObject* type means that JSObject* is on the stack as a raw pointer
+      // while destructors are running.
       JS::Rooted<JS::Value> val(cx);
-      if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, file, &val))) {
-        return val.toObjectOrNull();
-      }
+      {
+        nsRefPtr<DOMFile> blob = new DOMFile(scInfo->window, blobImpl);
+        if (!WrapNewBindingObject(cx, blob, &val)) {
+          return nullptr;
+        }
+      }
+
+      return &val.toObject();
     }
   }
 
   if (tag == SCTAG_DOM_FILELIST) {
     NS_ASSERTION(!data, "Data should be empty");
 
     nsISupports* supports;
     if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
@@ -7919,30 +7933,36 @@ static bool
 PostMessageWriteStructuredClone(JSContext* cx,
                                 JSStructuredCloneWriter* writer,
                                 JS::Handle<JSObject*> obj,
                                 void *closure)
 {
   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
   NS_ASSERTION(scInfo, "Must have scInfo!");
 
+  // See if this is a File/Blob object.
+  {
+    DOMFile* blob = nullptr;
+    if (scInfo->subsumes && NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
+      DOMFileImpl* blobImpl = blob->Impl();
+      if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
+          JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
+        scInfo->event->StoreISupports(blobImpl);
+        return true;
+      }
+    }
+  }
+
   nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
   nsContentUtils::XPConnect()->
     GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
   if (wrappedNative) {
     uint32_t scTag = 0;
     nsISupports* supports = wrappedNative->Native();
 
-    nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
-    if (blob && scInfo->subsumes) {
-      scTag = SCTAG_DOM_BLOB;
-      DOMFile* file = static_cast<DOMFile*>(blob.get());
-      supports = file->Impl();
-    }
-
     nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
     if (list && scInfo->subsumes)
       scTag = SCTAG_DOM_FILELIST;
 
     if (scTag)
       return JS_WriteUint32Pair(writer, scTag, 0) &&
              JS_WriteBytes(writer, &supports, sizeof(supports)) &&
              scInfo->event->StoreISupports(supports);
--- a/dom/base/test/file_url.jsm
+++ b/dom/base/test/file_url.jsm
@@ -1,12 +1,12 @@
 this.EXPORTED_SYMBOLS = ['checkFromJSM'];
 
 this.checkFromJSM = function checkFromJSM(ok, is) {
-  Components.utils.importGlobalProperties(['URL']);
+  Components.utils.importGlobalProperties(['URL', 'Blob']);
 
   var url = new URL('http://www.example.com');
   is(url.href, "http://www.example.com/", "JSM should have URL");
 
   var url2 = new URL('/foobar', url);
   is(url2.href, "http://www.example.com/foobar", "JSM should have URL - based on another URL");
 
   var blob = new Blob(['a']);
--- a/dom/base/test/test_messageChannel_post.html
+++ b/dom/base/test/test_messageChannel_post.html
@@ -45,17 +45,21 @@ https://bugzilla.mozilla.org/show_bug.cg
                   null,
                   undefined,
                   "hello world",
                   new Blob([]),
                   true ];
 
     a.port1.onmessage = function(evt) {
       ok(tests.length, "We are waiting for a message");
-      is(tests[0], evt.data, "Value ok: " + tests[0]);
+      if (typeof(tests[0]) == 'object') {
+        is(typeof(tests[0]), typeof(evt.data), "Value ok: " + tests[0]);
+      } else {
+        is(tests[0], evt.data, "Value ok: " + tests[0]);
+      }
       tests.shift();
       runTest();
     }
 
     function runTest() {
       if (!tests.length) {
         SimpleTest.finish();
         return;
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -131,23 +131,20 @@ DOMInterfaces = {
         'channelInterpretation': 'channelInterpretationValue',
     },
 },
 
 'BarProp': {
     'headerFile': 'mozilla/dom/BarProps.h',
 },
 
-'Blob': [
-{
-    'headerFile': 'nsIDOMFile.h',
+'Blob': {
+    'nativeType': 'mozilla::dom::DOMFile',
+    'headerFile': 'nsDOMFile.h',
 },
-{
-    'workers': True,
-}],
 
 'BatteryManager': {
     'nativeType': 'mozilla::dom::battery::BatteryManager',
     'headerFile': 'BatteryManager.h'
 },
 
 'BluetoothAdapter': {
     'nativeType': 'mozilla::dom::bluetooth::BluetoothAdapter',
@@ -398,18 +395,23 @@ DOMInterfaces = {
 
 'Exception': {
     'headerFile': 'mozilla/dom/DOMException.h',
     'binaryNames': {
         'message': 'messageMoz',
     },
 },
 
+'File': {
+    'nativeType': 'mozilla::dom::DOMFile',
+    'headerFile': 'nsDOMFile.h',
+},
+
 'FileList': {
-    'nativeType': 'nsDOMFileList',
+    'nativeType': 'mozilla::dom::nsDOMFileList',
     'headerFile': 'nsDOMFile.h',
 },
 
 'FileReader': {
     'nativeType': 'nsDOMFileReader',
     'implicitJSContext': [ 'readAsArrayBuffer' ],
 },
 
@@ -1793,17 +1795,16 @@ def addExternalIface(iface, nativeType=N
         domInterface['headerFile'] = headerFile
     domInterface['notflattened'] = notflattened
     DOMInterfaces[iface] = domInterface
 
 addExternalIface('ApplicationCache', nativeType='nsIDOMOfflineResourceList')
 addExternalIface('Counter')
 addExternalIface('CSSRule')
 addExternalIface('RTCDataChannel', nativeType='nsIDOMDataChannel')
-addExternalIface('File')
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
 addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
 addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
 addExternalIface('MozControllers', nativeType='nsIControllers')
 addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
 addExternalIface('MozFrameRequestCallback', nativeType='nsIFrameRequestCallback',
@@ -1822,16 +1823,17 @@ addExternalIface('MozWakeLockListener', 
 addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
 addExternalIface('nsIBrowserDOMWindow', nativeType='nsIBrowserDOMWindow',
                  notflattened=True)
 addExternalIface('nsIControllers', nativeType='nsIControllers')
 addExternalIface('nsIDOMCrypto', nativeType='nsIDOMCrypto',
                  headerFile='Crypto.h')
 addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback',
                  headerFile='nsIAsyncInputStream.h')
+addExternalIface('nsIFile', nativeType='nsIFile', notflattened=True)
 addExternalIface('nsIMessageBroadcaster', nativeType='nsIMessageBroadcaster',
                  headerFile='nsIMessageManager.h', notflattened=True)
 addExternalIface('nsISelectionListener', nativeType='nsISelectionListener')
 addExternalIface('nsIStreamListener', nativeType='nsIStreamListener', notflattened=True)
 addExternalIface('nsISupports', nativeType='nsISupports')
 addExternalIface('nsIDocShell', nativeType='nsIDocShell', notflattened=True)
 addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
 addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "nsDOMClassInfo.h"
 #include "nsTArrayHelpers.h"
 #include "DOMRequest.h"
+#include "nsDOMFile.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/BluetoothAdapterBinding.h"
 #include "mozilla/dom/BluetoothDeviceEvent.h"
 #include "mozilla/dom/BluetoothDiscoveryStateChangedEvent.h"
 #include "mozilla/dom/BluetoothStatusChangedEvent.h"
 #include "mozilla/dom/ContentChild.h"
@@ -765,17 +766,17 @@ BluetoothAdapter::IsConnected(const uint
   }
   bs->IsConnected(aServiceUuid, results);
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
-                           nsIDOMBlob* aBlob, ErrorResult& aRv)
+                           DOMFile& aBlob, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
@@ -785,25 +786,25 @@ BluetoothAdapter::SendFile(const nsAStri
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     // In-process transfer
-    bs->SendFile(aDeviceAddress, aBlob, results);
+    bs->SendFile(aDeviceAddress, &aBlob, results);
   } else {
     ContentChild *cc = ContentChild::GetSingleton();
     if (!cc) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
-    BlobChild* actor = cc->GetOrCreateActorForBlob(aBlob);
+    BlobChild* actor = cc->GetOrCreateActorForBlob(&aBlob);
     if (!actor) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
     bs->SendFile(aDeviceAddress, nullptr, actor, results);
   }
 
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -10,16 +10,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "BluetoothCommon.h"
 #include "BluetoothPropertyContainer.h"
 #include "nsCOMPtr.h"
 
 namespace mozilla {
 namespace dom {
+class DOMFile;
 class DOMRequest;
 struct MediaMetaData;
 struct MediaPlayStatus;
 }
 }
 
 BEGIN_BLUETOOTH_NAMESPACE
 
@@ -128,17 +129,17 @@ public:
   already_AddRefed<DOMRequest>
     IsConnected(const uint16_t aServiceUuid,
                 ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
     GetConnectedDevices(uint16_t aServiceUuid, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
-    SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob,
+    SendFile(const nsAString& aDeviceAddress, DOMFile& aBlob,
              ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     StopSendingFile(const nsAString& aDeviceAddress, ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     ConfirmReceivingFile(const nsAString& aDeviceAddress, bool aConfirmation,
                          ErrorResult& aRv);
 
   already_AddRefed<DOMRequest> ConnectSco(ErrorResult& aRv);
--- a/dom/bluetooth/bluedroid/BluetoothOppManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothOppManager.cpp
@@ -15,31 +15,32 @@
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsAutoPtr.h"
 #include "nsCExternalHandlerService.h"
+#include "nsDOMFile.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "nsIDOMFile.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsIMIMEService.h"
 #include "nsIOutputStream.h"
 #include "nsIVolumeService.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 
 #define TARGET_SUBDIR "Download/Bluetooth/"
 
 USING_BLUETOOTH_NAMESPACE
 using namespace mozilla;
+using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
 namespace {
 // Sending system message "bluetooth-opp-update-progress" every 50kb
 static const uint32_t kUpdateProgressBase = 50 * 1024;
 
 /*
  * The format of the header of an PUT request is
@@ -344,17 +345,18 @@ BluetoothOppManager::StartSendingNextFil
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               BlobParent* aActor)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsCOMPtr<nsIDOMBlob> blob = aActor->GetBlob();
+  nsRefPtr<DOMFileImpl> impl = aActor->GetBlobImpl();
+  nsCOMPtr<nsIDOMBlob> blob = new DOMFile(nullptr, impl);
 
   return SendFile(aDeviceAddress, blob.get());
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               nsIDOMBlob* aBlob)
 {
--- a/dom/bluetooth/bluez/BluetoothOppManager.cpp
+++ b/dom/bluetooth/bluez/BluetoothOppManager.cpp
@@ -15,31 +15,32 @@
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsAutoPtr.h"
 #include "nsCExternalHandlerService.h"
+#include "nsDOMFile.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "nsIDOMFile.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsIMIMEService.h"
 #include "nsIOutputStream.h"
 #include "nsIVolumeService.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 
 #define TARGET_SUBDIR "Download/Bluetooth/"
 
 USING_BLUETOOTH_NAMESPACE
 using namespace mozilla;
+using namespace mozilla::dom;
 using namespace mozilla::ipc;
 using mozilla::TimeDuration;
 using mozilla::TimeStamp;
 
 namespace {
 // Sending system message "bluetooth-opp-update-progress" every 50kb
 static const uint32_t kUpdateProgressBase = 50 * 1024;
 
@@ -366,17 +367,18 @@ BluetoothOppManager::StartSendingNextFil
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               BlobParent* aActor)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsCOMPtr<nsIDOMBlob> blob = aActor->GetBlob();
+  nsRefPtr<DOMFileImpl> impl = aActor->GetBlobImpl();
+  nsCOMPtr<nsIDOMBlob> blob = new DOMFile(nullptr, impl);
 
   return SendFile(aDeviceAddress, blob.get());
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               nsIDOMBlob* aBlob)
 {
--- a/dom/browser-element/BrowserElementParent.jsm
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -575,17 +575,18 @@ BrowserElementParent.prototype = {
 
     if ('successRv' in data.json) {
       debug("Successful gotDOMRequestResult.");
       let clientObj = Cu.cloneInto(data.json.successRv, this._window);
       Services.DOMRequest.fireSuccess(req, clientObj);
     }
     else {
       debug("Got error in gotDOMRequestResult.");
-      Services.DOMRequest.fireErrorAsync(req, data.json.errorMsg);
+      Services.DOMRequest.fireErrorAsync(req,
+        Cu.cloneInto(data.json.errorMsg, this._window));
     }
   },
 
   _setVisible: function(visible) {
     this._sendAsyncMsg('set-visible', {visible: visible});
     this._frameLoader.visible = visible;
   },
 
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -1432,33 +1432,35 @@ nsDOMCameraControl::OnFacesDetected(cons
 
   DispatchTrustedEvent(event);
 }
 
 void
 nsDOMCameraControl::OnTakePictureComplete(nsIDOMBlob* aPicture)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aPicture != nullptr);
+  MOZ_ASSERT(aPicture);
 
   nsRefPtr<Promise> promise = mTakePicturePromise.forget();
   if (promise) {
     nsCOMPtr<nsIDOMBlob> picture = aPicture;
     promise->MaybeResolve(picture);
   }
 
+  nsRefPtr<DOMFile> blob = static_cast<DOMFile*>(aPicture);
+
   nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb.forget();
   mTakePictureOnErrorCb = nullptr;
   if (cb) {
     ErrorResult ignored;
-    cb->Call(aPicture, ignored);
+    cb->Call(*blob, ignored);
   }
 
   BlobEventInit eventInit;
-  eventInit.mData = aPicture;
+  eventInit.mData = blob;
 
   nsRefPtr<BlobEvent> event = BlobEvent::Constructor(this,
                                                      NS_LITERAL_STRING("picture"),
                                                      eventInit);
 
   DispatchTrustedEvent(event);
 }
 
--- a/dom/camera/DOMCameraControlListener.cpp
+++ b/dom/camera/DOMCameraControlListener.cpp
@@ -343,17 +343,18 @@ DOMCameraControlListener::OnTakePictureC
       , mLength(aLength)
       , mMimeType(aMimeType)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
       nsCOMPtr<nsIDOMBlob> picture =
-        DOMFile::CreateMemoryFile(static_cast<void*>(mData),
+        DOMFile::CreateMemoryFile(mDOMCameraControl,
+                                  static_cast<void*>(mData),
                                   static_cast<uint64_t>(mLength),
                                   mMimeType);
       aDOMCameraControl->OnTakePictureComplete(picture);
     }
 
   protected:
     uint8_t* mData;
     uint32_t mLength;
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -85,18 +85,19 @@ ContactManager.prototype = {
     this.__DOM_IMPL__.setEventHandler("oncontactchange", aHandler);
   },
 
   get oncontactchange() {
     return this.__DOM_IMPL__.getEventHandler("oncontactchange");
   },
 
   _convertContact: function(aContact) {
-    let newContact = new this._window.mozContact(aContact.properties);
-    newContact.setMetadata(aContact.id, aContact.published, aContact.updated);
+    let contact = Cu.cloneInto(aContact, this._window);
+    let newContact = new this._window.mozContact(contact.properties);
+    newContact.setMetadata(contact.id, contact.published, contact.updated);
     return newContact;
   },
 
   _convertContacts: function(aContacts) {
     let contacts = new this._window.Array();
     for (let i in aContacts) {
       contacts.push(this._convertContact(aContacts[i]));
     }
--- a/dom/contacts/tests/test_contacts_blobs.html
+++ b/dom/contacts/tests/test_contacts_blobs.html
@@ -83,24 +83,24 @@ var properties2 = {
 };
 
 var sample_id1;
 var createResult1;
 var findResult1;
 
 function verifyBlob(blob1, blob2, isLast)
 {
-  is(blob1 instanceof SpecialPowers.Ci.nsIDOMBlob, true,
-     "blob1 is an instance of nsIDOMBlob");
-  is(blob2 instanceof SpecialPowers.Ci.nsIDOMBlob, true,
-     "blob2 is an instance of nsIDOMBlob");
-  isnot(blob1 instanceof SpecialPowers.Ci.nsIDOMFile, true,
-     "blob1 is an instance of nsIDOMFile");
-  isnot(blob2 instanceof SpecialPowers.Ci.nsIDOMFile, true,
-     "blob2 is an instance of nsIDOMFile");
+  is(blob1 instanceof Blob, true,
+     "blob1 is an instance of DOMBlob");
+  is(blob2 instanceof Blob, true,
+     "blob2 is an instance of DOMBlob");
+  isnot(blob1 instanceof File, true,
+     "blob1 is an instance of DOMFile");
+  isnot(blob2 instanceof File, true,
+     "blob2 is an instance of DOMFile");
   ise(blob1.size, blob2.size, "Same size");
   ise(blob1.type, blob2.type, "Same type");
 
   var buffer1;
   var buffer2;
 
   var reader1 = new FileReader();
   reader1.readAsArrayBuffer(blob2);
--- a/dom/devicestorage/DeviceStorageRequestChild.cpp
+++ b/dom/devicestorage/DeviceStorageRequestChild.cpp
@@ -98,22 +98,25 @@ DeviceStorageRequestChild::
       mRequest->FireSuccess(result);
       break;
     }
 
     case DeviceStorageResponseValue::TBlobResponse:
     {
       BlobResponse r = aValue;
       BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
-      nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
+      nsRefPtr<DOMFileImpl> bloblImpl = actor->GetBlobImpl();
+      nsRefPtr<DOMFile> blob = new DOMFile(mRequest->GetParentObject(), bloblImpl);
+
+      AutoJSContext cx;
 
-      nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob);
-      AutoJSContext cx;
-      JS::Rooted<JS::Value> result(cx,
-        InterfaceToJsval(window, file, &NS_GET_IID(nsIDOMFile)));
+      JS::Rooted<JSObject*> obj(cx, blob->WrapObject(cx));
+      MOZ_ASSERT(obj);
+
+      JS::Rooted<JS::Value> result(cx, JS::ObjectValue(*obj));
       mRequest->FireSuccess(result);
       break;
     }
 
     case DeviceStorageResponseValue::TFreeSpaceStorageResponse:
     {
       FreeSpaceStorageResponse r = aValue;
       AutoJSContext cx;
--- a/dom/devicestorage/DeviceStorageRequestParent.cpp
+++ b/dom/devicestorage/DeviceStorageRequestParent.cpp
@@ -39,20 +39,20 @@ DeviceStorageRequestParent::Dispatch()
     case DeviceStorageParams::TDeviceStorageAddParams:
     {
       DeviceStorageAddParams p = mParams;
 
       nsRefPtr<DeviceStorageFile> dsf =
         new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
 
       BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
-      nsCOMPtr<nsIDOMBlob> blob = bp->GetBlob();
+      nsRefPtr<DOMFileImpl> blobImpl = bp->GetBlobImpl();
 
       nsCOMPtr<nsIInputStream> stream;
-      blob->GetInternalStream(getter_AddRefs(stream));
+      blobImpl->GetInternalStream(getter_AddRefs(stream));
 
       nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream,
                                                           DEVICE_STORAGE_REQUEST_CREATE);
 
       nsCOMPtr<nsIEventTarget> target
         = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       MOZ_ASSERT(target);
       target->Dispatch(r, NS_DISPATCH_NORMAL);
@@ -62,20 +62,20 @@ DeviceStorageRequestParent::Dispatch()
     case DeviceStorageParams::TDeviceStorageAppendParams:
     {
       DeviceStorageAppendParams p = mParams;
 
       nsRefPtr<DeviceStorageFile> dsf =
         new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
 
       BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
-      nsCOMPtr<nsIDOMBlob> blob = bp->GetBlob();
+      nsRefPtr<DOMFileImpl> blobImpl = bp->GetBlobImpl();
 
       nsCOMPtr<nsIInputStream> stream;
-      blob->GetInternalStream(getter_AddRefs(stream));
+      blobImpl->GetInternalStream(getter_AddRefs(stream));
 
       nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream,
                                                           DEVICE_STORAGE_REQUEST_APPEND);
 
       nsCOMPtr<nsIEventTarget> target
         = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       MOZ_ASSERT(target);
       target->Dispatch(r, NS_DISPATCH_NORMAL);
@@ -517,17 +517,17 @@ nsresult
 DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsString mime;
   CopyASCIItoUTF16(mMimeType, mime);
 
   nsString fullPath;
   mFile->GetFullPath(fullPath);
-  nsCOMPtr<nsIDOMBlob> blob = new DOMFile(
+  nsRefPtr<DOMFile> blob = new DOMFile(nullptr,
     new DOMFileImplFile(fullPath, mime, mLength, mFile->mFile,
                         mLastModificationDate));
 
   ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
   BlobParent* actor = cp->GetOrCreateActorForBlob(blob);
   if (!actor) {
     ErrorResponse response(NS_LITERAL_STRING(POST_ERROR_EVENT_UNKNOWN));
     unused << mParent->Send__delete__(mParent, response);
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -1800,17 +1800,17 @@ nsIFileToJsval(nsPIDOMWindow* aWindow, D
   aFile->GetFullPath(fullPath);
 
   // This check is useful to know if somewhere the DeviceStorageFile
   // has not been properly set. Mimetype is not checked because it can be
   // empty.
   MOZ_ASSERT(aFile->mLength != UINT64_MAX);
   MOZ_ASSERT(aFile->mLastModifiedDate != UINT64_MAX);
 
-  nsCOMPtr<nsIDOMBlob> blob = new DOMFile(
+  nsCOMPtr<nsIDOMBlob> blob = new DOMFile(aWindow,
     new DOMFileImplFile(fullPath, aFile->mMimeType,
                         aFile->mLength, aFile->mFile,
                         aFile->mLastModifiedDate));
   return InterfaceToJsval(aWindow, blob, &NS_GET_IID(nsIDOMBlob));
 }
 
 bool
 StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString,
@@ -2909,17 +2909,18 @@ public:
             !typeChecker->Check(mFile->mStorageType, mBlob)) {
           r = new PostErrorEvent(mRequest.forget(),
                                  POST_ERROR_EVENT_ILLEGAL_TYPE);
           return NS_DispatchToCurrentThread(r);
         }
 
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
           BlobChild* actor
-            = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob);
+            = ContentChild::GetSingleton()->GetOrCreateActorForBlob(
+              static_cast<DOMFile*>(mBlob.get()));
           if (!actor) {
             return NS_ERROR_FAILURE;
           }
 
           DeviceStorageAddParams params;
           params.blobChild() = actor;
           params.type() = mFile->mStorageType;
           params.storageName() = mFile->mStorageName;
@@ -2954,17 +2955,18 @@ public:
             !typeChecker->Check(mFile->mStorageType, mBlob)) {
           r = new PostErrorEvent(mRequest.forget(),
                                  POST_ERROR_EVENT_ILLEGAL_TYPE);
           return NS_DispatchToCurrentThread(r);
         }
 
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
           BlobChild* actor
-            = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob);
+            = ContentChild::GetSingleton()->GetOrCreateActorForBlob(
+              static_cast<DOMFile*>(mBlob.get()));
           if (!actor) {
             return NS_ERROR_FAILURE;
           }
 
           DeviceStorageAppendParams params;
           params.blobChild() = actor;
           params.type() = mFile->mStorageType;
           params.storageName() = mFile->mStorageName;
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -298,17 +298,18 @@ DataTransfer::GetFiles(ErrorResult& aRv)
       if (NS_FAILED(rv))
         continue;
 
       nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
 
       if (!file)
         continue;
 
-      nsRefPtr<DOMFile> domFile = DOMFile::CreateFromFile(file);
+      nsRefPtr<DOMFile> domFile =
+        DOMFile::CreateFromFile(GetParentObject(), file);
 
       if (!mFiles->Append(domFile)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return nullptr;
       }
     }
   }
 
--- a/dom/events/test/test_eventctors.html
+++ b/dom/events/test/test_eventctors.html
@@ -198,17 +198,17 @@ ok(ex, "Shouldn't be able to re-define t
 ex = false;
 ok(!e.isTrusted, "BlobEvent shouldn't be trusted!");
 
 ok(!e.bubbles, "Event shouldn't bubble!");
 ok(!e.cancelable, "Event shouldn't be cancelable!");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
 
-var blob = Blob();
+var blob = new Blob();
 e = new BlobEvent("hello", { bubbles: true, cancelable: true, data: blob });
 is(e.type, "hello", "Wrong event type!");
 ok(!e.isTrusted, "Event shouldn't be trusted!");
 ok(e.bubbles, "Event should bubble!");
 ok(e.cancelable, "Event should be cancelable!");
 is(e.data, blob , "Wrong event.data!");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
--- a/dom/filehandle/FileHandle.cpp
+++ b/dom/filehandle/FileHandle.cpp
@@ -12,17 +12,17 @@
 #include "FileService.h"
 #include "FileStreamWrappers.h"
 #include "MemoryStreams.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "MutableFile.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsError.h"
-#include "nsIDOMFile.h"
+#include "nsDOMFile.h"
 #include "nsIEventTarget.h"
 #include "nsISeekableStream.h"
 #include "nsNetUtil.h"
 #include "nsString.h"
 #include "nsStringStream.h"
 #include "nsThreadUtils.h"
 #include "xpcpublic.h"
 
@@ -617,27 +617,27 @@ FileHandleBase::GetInputStream(const Arr
   }
 
   *aInputLength = length;
   return stream.forget();
 }
 
 // static
 already_AddRefed<nsIInputStream>
-FileHandleBase::GetInputStream(nsIDOMBlob* aValue, uint64_t* aInputLength,
+FileHandleBase::GetInputStream(const DOMFile& aValue, uint64_t* aInputLength,
                                ErrorResult& aRv)
 {
-  uint64_t length;
-  aRv = aValue->GetSize(&length);
+  DOMFile& file = const_cast<DOMFile&>(aValue);
+  uint64_t length = file.GetSize(aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   nsCOMPtr<nsIInputStream> stream;
-  aRv = aValue->GetInternalStream(getter_AddRefs(stream));
+  aRv = file.GetInternalStream(getter_AddRefs(stream));
   if (aRv.Failed()) {
     return nullptr;
   }
 
   *aInputLength = length;
   return stream.forget();
 }
 
--- a/dom/filehandle/FileHandle.h
+++ b/dom/filehandle/FileHandle.h
@@ -16,21 +16,21 @@
 #include "mozilla/ErrorResult.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIInputStream.h"
 #include "nsIRunnable.h"
 #include "nsTArray.h"
 
 class nsAString;
-class nsIDOMBlob;
 
 namespace mozilla {
 namespace dom {
 
+class DOMFile;
 class FileHelper;
 class FileRequestBase;
 class FileService;
 class FinishHelper;
 class MetadataHelper;
 class MutableFileBase;
 
 /**
@@ -235,17 +235,18 @@ protected:
   nsresult
   Finish();
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(const ArrayBuffer& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 
   static already_AddRefed<nsIInputStream>
-  GetInputStream(nsIDOMBlob* aValue, uint64_t* aInputLength, ErrorResult& aRv);
+  GetInputStream(const DOMFile& aValue, uint64_t* aInputLength,
+                 ErrorResult& aRv);
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(const nsAString& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 };
 
 class FinishHelper MOZ_FINAL : public nsIRunnable
 {
--- a/dom/filesystem/CreateFileTask.cpp
+++ b/dom/filesystem/CreateFileTask.cpp
@@ -22,17 +22,17 @@
 
 namespace mozilla {
 namespace dom {
 
 uint32_t CreateFileTask::sOutputBufferSize = 0;
 
 CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
                                const nsAString& aPath,
-                               nsIDOMBlob* aBlobData,
+                               DOMFile* aBlobData,
                                InfallibleTArray<uint8_t>& aArrayData,
                                bool replace,
                                ErrorResult& aRv)
   : FileSystemTaskBase(aFileSystem)
   , mTargetRealPath(aPath)
   , mReplace(replace)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
@@ -74,19 +74,20 @@ CreateFileTask::CreateFileTask(FileSyste
   auto& data = aParam.data();
 
   if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
     mArrayData = data;
     return;
   }
 
   BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
-  nsCOMPtr<nsIDOMBlob> blobData = bp->GetBlob();
-  MOZ_ASSERT(blobData, "blobData should not be null.");
-  nsresult rv = blobData->GetInternalStream(getter_AddRefs(mBlobStream));
+  nsRefPtr<DOMFileImpl> blobImpl = bp->GetBlobImpl();
+  MOZ_ASSERT(blobImpl, "blobData should not be null.");
+
+  nsresult rv = blobImpl->GetInternalStream(getter_AddRefs(mBlobStream));
   NS_WARN_IF(NS_FAILED(rv));
 }
 
 CreateFileTask::~CreateFileTask()
 {
   MOZ_ASSERT((!mPromise && !mBlobData) || NS_IsMainThread(),
              "mPromise and mBlobData should be released on main thread!");
 
@@ -121,34 +122,34 @@ CreateFileTask::GetRequestParams(const n
   }
   return param;
 }
 
 FileSystemResponseValue
 CreateFileTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
-  nsRefPtr<DOMFile> file = new DOMFile(mTargetFileImpl);
+  nsRefPtr<DOMFile> file = new DOMFile(mFileSystem->GetWindow(),
+                                       mTargetFileImpl);
   BlobParent* actor = GetBlobParent(file);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
 
 void
 CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   FileSystemFileResponse r = aValue;
   BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
-  nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
-  mTargetFileImpl = static_cast<DOMFile*>(blob.get())->Impl();
+  mTargetFileImpl = actor->GetBlobImpl();
 }
 
 nsresult
 CreateFileTask::Work()
 {
   class AutoClose
   {
   public:
@@ -297,17 +298,18 @@ CreateFileTask::HandlerCallback()
     nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
       mErrorValue);
     mPromise->MaybeRejectBrokenly(domError);
     mPromise = nullptr;
     mBlobData = nullptr;
     return;
   }
 
-  nsCOMPtr<nsIDOMFile> file = new DOMFile(mTargetFileImpl);
+  nsCOMPtr<nsIDOMFile> file = new DOMFile(mFileSystem->GetWindow(),
+                                          mTargetFileImpl);
   mPromise->MaybeResolve(file);
   mPromise = nullptr;
   mBlobData = nullptr;
 }
 
 void
 CreateFileTask::GetPermissionAccessType(nsCString& aAccess) const
 {
--- a/dom/filesystem/CreateFileTask.h
+++ b/dom/filesystem/CreateFileTask.h
@@ -6,32 +6,32 @@
 
 #ifndef mozilla_dom_CreateFileTask_h
 #define mozilla_dom_CreateFileTask_h
 
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "nsAutoPtr.h"
 #include "mozilla/ErrorResult.h"
 
-class nsIDOMBlob;
 class nsIInputStream;
 
 namespace mozilla {
 namespace dom {
 
+class DOMFile;
 class DOMFileImpl;
 class Promise;
 
 class CreateFileTask MOZ_FINAL
   : public FileSystemTaskBase
 {
 public:
   CreateFileTask(FileSystemBase* aFileSystem,
                  const nsAString& aPath,
-                 nsIDOMBlob* aBlobData,
+                 DOMFile* aBlobData,
                  InfallibleTArray<uint8_t>& aArrayData,
                  bool replace,
                  ErrorResult& aRv);
   CreateFileTask(FileSystemBase* aFileSystem,
                  const FileSystemCreateFileParams& aParam,
                  FileSystemRequestParent* aParent);
 
   virtual
@@ -63,17 +63,17 @@ private:
   void
   GetOutputBufferSize() const;
 
   static uint32_t sOutputBufferSize;
   nsRefPtr<Promise> mPromise;
   nsString mTargetRealPath;
 
   // Not thread-safe and should be released on main thread.
-  nsCOMPtr<nsIDOMBlob> mBlobData;
+  nsRefPtr<DOMFile> mBlobData;
 
   nsCOMPtr<nsIInputStream> mBlobStream;
   InfallibleTArray<uint8_t> mArrayData;
   bool mReplace;
 
   // This cannot be a DOMFile because this object is created on a different
   // thread and DOMFile is not thread-safe. Let's use the DOMFileImpl instead.
   nsRefPtr<DOMFileImpl> mTargetFileImpl;
--- a/dom/filesystem/DeviceStorageFileSystem.cpp
+++ b/dom/filesystem/DeviceStorageFileSystem.cpp
@@ -118,17 +118,19 @@ DeviceStorageFileSystem::GetRealPath(DOM
 {
   MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
              "Should be on parent process!");
   MOZ_ASSERT(aFile, "aFile Should not be null.");
 
   aRealPath.Truncate();
 
   nsAutoString filePath;
-  if (NS_FAILED(aFile->GetMozFullPathInternal(filePath))) {
+  ErrorResult rv;
+  aFile->GetMozFullPathInternal(filePath, rv);
+  if (NS_WARN_IF(rv.Failed())) {
     return false;
   }
 
   return LocalPathToRealPath(filePath, aRealPath);
 }
 
 const nsAString&
 DeviceStorageFileSystem::GetRootName() const
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -96,17 +96,17 @@ Directory::GetName(nsString& aRetval) co
 }
 
 already_AddRefed<Promise>
 Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
                       ErrorResult& aRv)
 {
   nsresult error = NS_OK;
   nsString realPath;
-  nsRefPtr<nsIDOMBlob> blobData;
+  nsRefPtr<DOMFile> blobData;
   InfallibleTArray<uint8_t> arrayData;
   bool replace = (aOptions.mIfExists == CreateIfExistsMode::Replace);
 
   // Get the file content.
   if (aOptions.mData.WasPassed()) {
     auto& data = aOptions.mData.Value();
     if (data.IsString()) {
       NS_ConvertUTF16toUTF8 str(data.GetAsString());
@@ -124,18 +124,18 @@ Directory::CreateFile(const nsAString& a
       blobData = data.GetAsBlob();
     }
   }
 
   if (!DOMPathToRealPath(aPath, realPath)) {
     error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
   }
 
-  nsRefPtr<CreateFileTask> task = new CreateFileTask(mFileSystem, realPath,
-    blobData, arrayData, replace, aRv);
+  nsRefPtr<CreateFileTask> task =
+    new CreateFileTask(mFileSystem, realPath, blobData, arrayData, replace, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
   task->SetError(error);
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
 
@@ -193,17 +193,17 @@ Directory::RemoveInternal(const StringOr
 {
   nsresult error = NS_OK;
   nsString realPath;
   nsRefPtr<DOMFileImpl> file;
 
   // Check and get the target path.
 
   if (aPath.IsFile()) {
-    file = static_cast<DOMFile*>(aPath.GetAsFile())->Impl();
+    file = aPath.GetAsFile().Impl();
     goto parameters_check_done;
   }
 
   if (aPath.IsString()) {
     if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) {
       error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
     }
     goto parameters_check_done;
--- a/dom/filesystem/FileSystemTaskBase.cpp
+++ b/dom/filesystem/FileSystemTaskBase.cpp
@@ -165,17 +165,17 @@ FileSystemTaskBase::GetBlobParent(nsIDOM
   nsString mimeType;
   aFile->GetType(mimeType);
   uint64_t fileSize;
   aFile->GetSize(&fileSize);
   uint64_t lastModifiedDate;
   aFile->GetMozLastModifiedDate(&lastModifiedDate);
 
   ContentParent* cp = static_cast<ContentParent*>(mRequestParent->Manager());
-  return cp->GetOrCreateActorForBlob(aFile);
+  return cp->GetOrCreateActorForBlob(static_cast<DOMFile*>(aFile));
 }
 
 void
 FileSystemTaskBase::SetError(const nsresult& aErrorValue)
 {
   uint16_t module = NS_ERROR_GET_MODULE(aErrorValue);
   if (module == NS_ERROR_MODULE_DOM_FILESYSTEM ||
       module == NS_ERROR_MODULE_DOM_FILE ||
--- a/dom/filesystem/GetFileOrDirectoryTask.cpp
+++ b/dom/filesystem/GetFileOrDirectoryTask.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GetFileOrDirectoryTask.h"
 
 #include "js/Value.h"
 #include "mozilla/dom/Directory.h"
+#include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "nsDOMFile.h"
 #include "nsIFile.h"
 #include "nsStringGlue.h"
@@ -76,17 +77,18 @@ GetFileOrDirectoryTask::GetRequestParams
 FileSystemResponseValue
 GetFileOrDirectoryTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mIsDirectory) {
     return FileSystemDirectoryResponse(mTargetRealPath);
   }
 
-  nsRefPtr<DOMFile> file = new DOMFile(mTargetFileImpl);
+  nsRefPtr<DOMFile> file = new DOMFile(mFileSystem->GetWindow(),
+                                       mTargetFileImpl);
   BlobParent* actor = GetBlobParent(file);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
@@ -94,18 +96,17 @@ GetFileOrDirectoryTask::GetSuccessReques
 void
 GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   switch (aValue.type()) {
     case FileSystemResponseValue::TFileSystemFileResponse: {
       FileSystemFileResponse r = aValue;
       BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
-      nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
-      mTargetFileImpl = static_cast<DOMFile*>(blob.get())->Impl();
+      mTargetFileImpl = actor->GetBlobImpl();
       mIsDirectory = false;
       break;
     }
     case FileSystemResponseValue::TFileSystemDirectoryResponse: {
       FileSystemDirectoryResponse r = aValue;
       mTargetRealPath = r.realPath();
       mIsDirectory = true;
       break;
@@ -209,17 +210,18 @@ GetFileOrDirectoryTask::HandlerCallback(
 
   if (mIsDirectory) {
     nsRefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
     mPromise->MaybeResolve(dir);
     mPromise = nullptr;
     return;
   }
 
-  nsCOMPtr<nsIDOMFile> file = new DOMFile(mTargetFileImpl);
+  nsCOMPtr<nsIDOMFile> file = new DOMFile(mFileSystem->GetWindow(),
+                                          mTargetFileImpl);
   mPromise->MaybeResolve(file);
   mPromise = nullptr;
 }
 
 void
 GetFileOrDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
 {
   aAccess.AssignLiteral("read");
--- a/dom/filesystem/RemoveTask.cpp
+++ b/dom/filesystem/RemoveTask.cpp
@@ -61,19 +61,18 @@ RemoveTask::RemoveTask(FileSystemBase* a
   const FileSystemPathOrFileValue& target = aParam.target();
 
   if (target.type() == FileSystemPathOrFileValue::TnsString) {
     mTargetRealPath = target;
     return;
   }
 
   BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(target));
-  nsCOMPtr<nsIDOMBlob> blob = bp->GetBlob();
-  MOZ_ASSERT(blob);
-  mTargetFileImpl = static_cast<DOMFile*>(blob.get())->Impl();
+  mTargetFileImpl = bp->GetBlobImpl();
+  MOZ_ASSERT(mTargetFileImpl);
 }
 
 RemoveTask::~RemoveTask()
 {
   MOZ_ASSERT(!mPromise || NS_IsMainThread(),
              "mPromise should be released on main thread!");
 }
 
@@ -88,17 +87,18 @@ FileSystemParams
 RemoveTask::GetRequestParams(const nsString& aFileSystem) const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   FileSystemRemoveParams param;
   param.filesystem() = aFileSystem;
   param.directory() = mDirRealPath;
   param.recursive() = mRecursive;
   if (mTargetFileImpl) {
-    nsRefPtr<DOMFile> file = new DOMFile(mTargetFileImpl);
+    nsRefPtr<DOMFile> file = new DOMFile(mFileSystem->GetWindow(),
+                                         mTargetFileImpl);
     BlobChild* actor
       = ContentChild::GetSingleton()->GetOrCreateActorForBlob(file);
     if (actor) {
       param.target() = actor;
     }
   } else {
     param.target() = mTargetRealPath;
   }
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -519,18 +519,20 @@ ConvertActorsToBlobs(IDBDatabase* aDatab
 
   if (!blobs.IsEmpty()) {
     const uint32_t count = blobs.Length();
     aFiles.SetCapacity(count);
 
     for (uint32_t index = 0; index < count; index++) {
       BlobChild* actor = static_cast<BlobChild*>(blobs[index]);
 
-      nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
-      MOZ_ASSERT(blob);
+      nsRefPtr<DOMFileImpl> blobImpl = actor->GetBlobImpl();
+      MOZ_ASSERT(blobImpl);
+
+      nsRefPtr<DOMFile> blob = new DOMFile(aDatabase->GetOwner(), blobImpl);
 
       nsRefPtr<FileInfo> fileInfo;
       if (!fileInfos.IsEmpty()) {
         fileInfo = dont_AddRef(reinterpret_cast<FileInfo*>(fileInfos[index]));
 
         MOZ_ASSERT(fileInfo);
         MOZ_ASSERT(fileInfo->Id() > 0);
 
--- a/dom/indexedDB/FileSnapshot.cpp
+++ b/dom/indexedDB/FileSnapshot.cpp
@@ -126,33 +126,35 @@ FileImplSnapshot::GetInternalStream(nsII
   }
 
   return NS_OK;
 }
 
 already_AddRefed<DOMFileImpl>
 FileImplSnapshot::CreateSlice(uint64_t aStart,
                               uint64_t aLength,
-                              const nsAString& aContentType)
+                              const nsAString& aContentType,
+                              ErrorResult& aRv)
 {
   AssertSanity();
 
   nsRefPtr<DOMFileImpl> impl =
     new FileImplSnapshot(this, aStart, aLength, aContentType);
 
   return impl.forget();
 }
 
-nsresult
-FileImplSnapshot::GetMozFullPathInternal(nsAString& aFilename)
+void
+FileImplSnapshot::GetMozFullPathInternal(nsAString& aFilename,
+                                         ErrorResult& aRv)
 {
   AssertSanity();
   MOZ_ASSERT(mIsFile);
 
-  return mFile->GetPath(aFilename);
+  aRv = mFile->GetPath(aFilename);
 }
 
 bool
 FileImplSnapshot::IsStoredFile() const
 {
   AssertSanity();
 
   return true;
--- a/dom/indexedDB/FileSnapshot.h
+++ b/dom/indexedDB/FileSnapshot.h
@@ -54,35 +54,36 @@ private:
   static void
   AssertSanity()
 #ifdef DEBUG
   ;
 #else
   { }
 #endif
 
-  virtual nsresult
-  GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
+  virtual void
+  GetMozFullPathInternal(nsAString& aFullPath, ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual nsresult
   GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
   virtual void
   Unlink() MOZ_OVERRIDE;
 
   virtual void
   Traverse(nsCycleCollectionTraversalCallback &aCb) MOZ_OVERRIDE;
 
   virtual bool
   IsCCed() const MOZ_OVERRIDE;
 
   virtual already_AddRefed<DOMFileImpl>
   CreateSlice(uint64_t aStart,
               uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType,
+              ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual bool
   IsStoredFile() const MOZ_OVERRIDE;
 
   virtual bool
   IsWholeFile() const MOZ_OVERRIDE;
 
   virtual bool
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -798,33 +798,34 @@ IDBDatabase::AbortTransactions()
       return PL_DHASH_NEXT;
     }
   };
 
   Helper::AbortTransactions(mTransactions);
 }
 
 PBackgroundIDBDatabaseFileChild*
-IDBDatabase::GetOrCreateFileActorForBlob(nsIDOMBlob* aBlob)
+IDBDatabase::GetOrCreateFileActorForBlob(DOMFile* aBlob)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aBlob);
   MOZ_ASSERT(mBackgroundActor);
 
   // We use the DOMFile's nsIWeakReference as the key to the table because
   // a) it is unique per blob, b) it is reference-counted so that we can
   // guarantee that it stays alive, and c) it doesn't hold the actual DOMFile
   // alive.
-  nsCOMPtr<nsIWeakReference> weakRef = do_GetWeakReference(aBlob);
+  nsCOMPtr<nsIDOMBlob> blob = aBlob;
+  nsCOMPtr<nsIWeakReference> weakRef = do_GetWeakReference(blob);
   MOZ_ASSERT(weakRef);
 
   PBackgroundIDBDatabaseFileChild* actor = nullptr;
 
   if (!mFileActors.Get(weakRef, &actor)) {
-    DOMFileImpl* blobImpl = static_cast<DOMFile*>(aBlob)->Impl();
+    DOMFileImpl* blobImpl = aBlob->Impl();
     MOZ_ASSERT(blobImpl);
 
     if (mReceivedBlobs.GetEntry(weakRef)) {
       // This blob was previously retrieved from the database.
       nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(blobImpl);
       MOZ_ASSERT(remoteBlob);
 
       BlobChild* blobChild = remoteBlob->GetBlobChild();
@@ -906,25 +907,25 @@ IDBDatabase::NoteFinishedFileActor(PBack
       return PL_DHASH_NEXT;
     }
   };
 
   mFileActors.Enumerate(&Helper::Remove, aFileActor);
 }
 
 void
-IDBDatabase::NoteReceivedBlob(nsIDOMBlob* aBlob)
+IDBDatabase::NoteReceivedBlob(DOMFile* aBlob)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aBlob);
   MOZ_ASSERT(mBackgroundActor);
 
 #ifdef DEBUG
   {
-    nsRefPtr<DOMFileImpl> blobImpl = static_cast<DOMFile*>(aBlob)->Impl();
+    nsRefPtr<DOMFileImpl> blobImpl = aBlob->Impl();
     MOZ_ASSERT(blobImpl);
 
     nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(blobImpl);
     MOZ_ASSERT(remoteBlob);
 
     BlobChild* blobChild = remoteBlob->GetBlobChild();
     MOZ_ASSERT(blobChild);
 
@@ -933,17 +934,18 @@ IDBDatabase::NoteReceivedBlob(nsIDOMBlob
 
     PBackgroundChild* thisManager = mBackgroundActor->Manager()->Manager();
     MOZ_ASSERT(thisManager);
 
     MOZ_ASSERT(thisManager == backgroundManager);
   }
 #endif
 
-  nsCOMPtr<nsIWeakReference> weakRef = do_GetWeakReference(aBlob);
+  nsCOMPtr<nsIDOMBlob> blob = aBlob;
+  nsCOMPtr<nsIWeakReference> weakRef = do_GetWeakReference(blob);
   MOZ_ASSERT(weakRef);
 
   // It's ok if this entry already exists in the table.
   mReceivedBlobs.PutEntry(weakRef);
 }
 
 void
 IDBDatabase::DelayedMaybeExpireFileActors()
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -14,27 +14,27 @@
 #include "mozilla/dom/quota/PersistenceType.h"
 #include "nsAutoPtr.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsString.h"
 #include "nsTHashtable.h"
 
 class nsIDocument;
-class nsIDOMBlob;
 class nsIWeakReference;
 class nsPIDOMWindow;
 
 namespace mozilla {
 
 class ErrorResult;
 class EventChainPostVisitor;
 
 namespace dom {
 
+class DOMFile;
 class DOMStringList;
 struct IDBObjectStoreParameters;
 template <typename> class Sequence;
 
 namespace indexedDB {
 
 class BackgroundDatabaseChild;
 class DatabaseSpec;
@@ -169,23 +169,23 @@ public:
 
   void
   UnregisterTransaction(IDBTransaction* aTransaction);
 
   void
   AbortTransactions();
 
   PBackgroundIDBDatabaseFileChild*
-  GetOrCreateFileActorForBlob(nsIDOMBlob* aBlob);
+  GetOrCreateFileActorForBlob(DOMFile* aBlob);
 
   void
   NoteFinishedFileActor(PBackgroundIDBDatabaseFileChild* aFileActor);
 
   void
-  NoteReceivedBlob(nsIDOMBlob* aBlob);
+  NoteReceivedBlob(DOMFile* aBlob);
 
   void
   DelayedMaybeExpireFileActors();
 
   // XXX This doesn't really belong here... It's only needed for IDBMutableFile
   //     serialization and should be removed someday.
   nsresult
   GetQuotaInfo(nsACString& aOrigin, PersistenceType* aPersistenceType);
--- a/dom/indexedDB/IDBMutableFile.cpp
+++ b/dom/indexedDB/IDBMutableFile.cpp
@@ -346,17 +346,17 @@ IDBMutableFile::CreateFileObject(IDBFile
   nsRefPtr<DOMFileImpl> impl =
     new FileImplSnapshot(mName,
                          mType,
                          aMetadataParams,
                          mFile,
                          aFileHandle,
                          mFileInfo);
 
-  nsCOMPtr<nsIDOMFile> fileSnapshot = new DOMFile(impl);
+  nsCOMPtr<nsIDOMFile> fileSnapshot = new DOMFile(GetOwner(), impl);
   return fileSnapshot.forget();
 }
 
 already_AddRefed<DOMRequest>
 IDBMutableFile::GetFile(ErrorResult& aError)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -25,16 +25,17 @@
 #include "mozilla/Endian.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Move.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/dom/IDBMutableFileBinding.h"
+#include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/IDBObjectStoreBinding.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/ipc/nsIRemoteBlob.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
@@ -53,17 +54,17 @@ namespace indexedDB {
 
 using namespace mozilla::dom::quota;
 using namespace mozilla::ipc;
 
 struct IDBObjectStore::StructuredCloneWriteInfo
 {
   struct BlobOrFileInfo
   {
-    nsCOMPtr<nsIDOMBlob> mBlob;
+    nsRefPtr<DOMFile> mBlob;
     nsRefPtr<FileInfo> mFileInfo;
 
     bool
     operator==(const BlobOrFileInfo& aOther) const
     {
       return this->mBlob == aOther.mBlob && this->mFileInfo == aOther.mFileInfo;
     }
   };
@@ -292,82 +293,74 @@ StructuredCloneWriteCallback(JSContext* 
         cloneWriteInfo->mBlobOrFileInfos.AppendElement();
     newBlobOrFileInfo->mFileInfo.swap(fileInfo);
 
     return true;
   }
 
   MOZ_ASSERT(NS_IsMainThread(), "This can't work off the main thread!");
 
-  nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
-  nsContentUtils::XPConnect()->
-    GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative));
-
-  if (wrappedNative) {
-    nsISupports* supports = wrappedNative->Native();
-
-    nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
-    if (blob) {
+  {
+    DOMFile* blob = nullptr;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
       uint64_t size;
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetSize(&size)));
 
       size = NativeEndian::swapToLittleEndian(size);
 
       nsString type;
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetType(type)));
 
       NS_ConvertUTF16toUTF8 convType(type);
       uint32_t convTypeLength =
         NativeEndian::swapToLittleEndian(convType.Length());
 
-      nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob);
-
       if (cloneWriteInfo->mBlobOrFileInfos.Length() > size_t(UINT32_MAX)) {
         MOZ_ASSERT(false,
                    "Fix the structured clone data to use a bigger type!");
         return false;
       }
 
       const uint32_t index =
         uint32_t(cloneWriteInfo->mBlobOrFileInfos.Length());
 
       if (!JS_WriteUint32Pair(aWriter,
-                              file ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
+                              blob->IsFile() ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
                               index) ||
           !JS_WriteBytes(aWriter, &size, sizeof(size)) ||
           !JS_WriteBytes(aWriter, &convTypeLength, sizeof(convTypeLength)) ||
           !JS_WriteBytes(aWriter, convType.get(), convType.Length())) {
         return false;
       }
 
-      if (file) {
+      if (blob->IsFile()) {
         uint64_t lastModifiedDate;
         MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
-          file->GetMozLastModifiedDate(&lastModifiedDate)));
+          blob->GetMozLastModifiedDate(&lastModifiedDate)));
 
         lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate);
 
         nsString name;
-        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(file->GetName(name)));
+        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetName(name)));
 
         NS_ConvertUTF16toUTF8 convName(name);
         uint32_t convNameLength =
           NativeEndian::swapToLittleEndian(convName.Length());
 
         if (!JS_WriteBytes(aWriter, &lastModifiedDate, sizeof(lastModifiedDate)) || 
             !JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
             !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
           return false;
         }
       }
 
       IDBObjectStore::StructuredCloneWriteInfo::BlobOrFileInfo*
         newBlobOrFileInfo =
           cloneWriteInfo->mBlobOrFileInfos.AppendElement();
-      newBlobOrFileInfo->mBlob.swap(blob);
+      newBlobOrFileInfo->mBlob = blob;
 
       return true;
     }
   }
 
   // Try using the runtime callbacks
   const JSStructuredCloneCallbacks* runtimeCallbacks =
     js::GetContextStructuredCloneCallbacks(aCx);
@@ -403,22 +396,21 @@ GetAddInfoCallback(JSContext* aCx, void*
                                                 &data->mCloneWriteInfo)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   return NS_OK;
 }
 
 BlobChild*
-ActorFromRemoteBlob(nsIDOMBlob* aBlob)
+ActorFromRemoteBlob(DOMFile* aBlob)
 {
   MOZ_ASSERT(aBlob);
 
-  nsRefPtr<DOMFile> blob = static_cast<DOMFile*>(aBlob);
-  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(blob->Impl());
+  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob->Impl());
   if (remoteBlob) {
     BlobChild* actor = remoteBlob->GetBlobChild();
     MOZ_ASSERT(actor);
 
     if (actor->GetContentManager()) {
       return nullptr;
     }
 
@@ -430,32 +422,32 @@ ActorFromRemoteBlob(nsIDOMBlob* aBlob)
 
     return actor;
   }
 
   return nullptr;
 }
 
 bool
-ResolveMysteryFile(nsIDOMBlob* aBlob,
+ResolveMysteryFile(DOMFile* aBlob,
                    const nsString& aName,
                    const nsString& aContentType,
                    uint64_t aSize,
                    uint64_t aLastModifiedDate)
 {
   BlobChild* actor = ActorFromRemoteBlob(aBlob);
   if (actor) {
     return actor->SetMysteryBlobInfo(aName, aContentType,
                                      aSize, aLastModifiedDate);
   }
   return true;
 }
 
 bool
-ResolveMysteryBlob(nsIDOMBlob* aBlob,
+ResolveMysteryBlob(DOMFile* aBlob,
                    const nsString& aContentType,
                    uint64_t aSize)
 {
   BlobChild* actor = ActorFromRemoteBlob(aBlob);
   if (actor) {
     return actor->SetMysteryBlobInfo(aContentType, aSize);
   }
   return true;
@@ -599,67 +591,69 @@ public:
     }
 
     aResult.set(result);
     return true;
   }
 
   static bool
   CreateAndWrapBlobOrFile(JSContext* aCx,
+                          IDBDatabase* aDatabase,
                           StructuredCloneFile& aFile,
                           const BlobOrFileData& aData,
                           JS::MutableHandle<JSObject*> aResult)
   {
     MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
                aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
                aData.tag == SCTAG_DOM_BLOB);
     MOZ_ASSERT(aFile.mFile);
 
     MOZ_ASSERT(NS_IsMainThread(),
                "This wrapping currently only works on the main thread!");
 
+    // It can happen that this IDB is chrome code, so there is no parent, but
+    // still we want to set a correct parent for the new DOMFile object.
+    nsCOMPtr<nsISupports> parent;
+    if (aDatabase && aDatabase->GetParentObject()) {
+      parent = aDatabase->GetParentObject();
+    } else {
+      parent  = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
+    }
+
+    MOZ_ASSERT(parent);
+    nsRefPtr<DOMFile> file = new DOMFile(parent, aFile.mFile->Impl());
+
     if (aData.tag == SCTAG_DOM_BLOB) {
       if (NS_WARN_IF(!ResolveMysteryBlob(aFile.mFile,
                                          aData.type,
                                          aData.size))) {
         return false;
       }
 
       JS::Rooted<JS::Value> wrappedBlob(aCx);
-      nsresult rv =
-        nsContentUtils::WrapNative(aCx,
-                                   aFile.mFile,
-                                   &NS_GET_IID(nsIDOMBlob),
-                                   &wrappedBlob);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
+      if (!WrapNewBindingObject(aCx, aFile.mFile, &wrappedBlob)) {
         return false;
       }
 
       aResult.set(&wrappedBlob.toObject());
       return true;
     }
 
-    nsCOMPtr<nsIDOMFile> domFile = do_QueryInterface(aFile.mFile);
-    MOZ_ASSERT(domFile);
+    MOZ_ASSERT(aFile.mFile->IsFile());
 
-    if (NS_WARN_IF(!ResolveMysteryFile(domFile,
+    if (NS_WARN_IF(!ResolveMysteryFile(aFile.mFile,
                                        aData.name,
                                        aData.type,
                                        aData.size,
                                        aData.lastModifiedDate))) {
       return false;
     }
 
     JS::Rooted<JS::Value> wrappedFile(aCx);
-    nsresult rv =
-      nsContentUtils::WrapNative(aCx,
-                                 aFile.mFile,
-                                 &NS_GET_IID(nsIDOMFile),
-                                 &wrappedFile);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
+    if (!WrapNewBindingObject(aCx, aFile.mFile, &wrappedFile)) {
       return false;
     }
 
     aResult.set(&wrappedFile.toObject());
     return true;
   }
 };
 
@@ -684,16 +678,17 @@ public:
     }
 
     aResult.set(obj);
     return true;
   }
 
   static bool
   CreateAndWrapBlobOrFile(JSContext* aCx,
+                          IDBDatabase* aDatabase,
                           StructuredCloneFile& aFile,
                           const BlobOrFileData& aData,
                           JS::MutableHandle<JSObject*> aResult)
   {
     MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
                aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
                aData.tag == SCTAG_DOM_BLOB);
 
@@ -810,16 +805,17 @@ CommonStructuredCloneReadCallback(JSCont
     }
 
     BlobOrFileData data;
     if (NS_WARN_IF(!ReadBlobOrFile(aReader, aTag, &data))) {
       return nullptr;
     }
 
     if (NS_WARN_IF(!Traits::CreateAndWrapBlobOrFile(aCx,
+                                                    cloneReadInfo->mDatabase,
                                                     file,
                                                     data,
                                                     &result))) {
       return nullptr;
     }
 
     return result;
   }
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -12,16 +12,17 @@
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IDBIndex.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/EventDispatcher.h"
+#include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsIScriptContext.h"
 #include "nsJSUtils.h"
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -11,17 +11,16 @@
 #include "mozilla/dom/IDBTransactionBinding.h"
 #include "mozilla/dom/indexedDB/IDBWrapperCache.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIRunnable.h"
 #include "nsString.h"
 #include "nsTArray.h"
 
-class nsIDOMBlob;
 class nsPIDOMWindow;
 
 namespace mozilla {
 
 class ErrorResult;
 class EventChainPreVisitor;
 
 namespace dom {
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -9,32 +9,34 @@
 
 #include "nsIProgrammingLanguage.h"
 
 #include "js/StructuredClone.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 
-class nsIDOMBlob;
 class nsIInputStream;
 
 namespace mozilla {
 namespace dom {
+
+class DOMFile;
+
 namespace indexedDB {
 
 class FileInfo;
 class IDBDatabase;
 class IDBTransaction;
 class SerializedStructuredCloneReadInfo;
 class SerializedStructuredCloneWriteInfo;
 
 struct StructuredCloneFile
 {
-  nsCOMPtr<nsIDOMBlob> mFile;
+  nsRefPtr<DOMFile> mFile;
   nsRefPtr<FileInfo> mFileInfo;
 
   // In IndexedDatabaseInlines.h
   inline
   StructuredCloneFile();
 
   // In IndexedDatabaseInlines.h
   inline
--- a/dom/indexedDB/IndexedDatabaseInlines.h
+++ b/dom/indexedDB/IndexedDatabaseInlines.h
@@ -8,17 +8,17 @@
 #define IndexedDatabaseInlines_h
 
 #ifndef mozilla_dom_indexeddb_indexeddatabase_h__
 #error Must include IndexedDatabase.h first
 #endif
 
 #include "FileInfo.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
-#include "nsIDOMFile.h"
+#include "nsDOMFile.h"
 #include "nsIInputStream.h"
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 inline
 StructuredCloneFile::StructuredCloneFile()
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -12,16 +12,17 @@
 #include "nsIObserverService.h"
 #include "nsIScriptError.h"
 
 #include "jsapi.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/PBlobChild.h"
 #include "mozilla/dom/quota/OriginOrPatternString.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/quota/Utilities.h"
 #include "mozilla/dom/TabContext.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/ipc/BackgroundChild.h"
--- a/dom/indexedDB/test/unit/test_temporary_storage.js
+++ b/dom/indexedDB/test/unit/test_temporary_storage.js
@@ -1,13 +1,15 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+Components.utils.importGlobalProperties(['Blob']);
+
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
 
   const urls = [
     { url: "http://www.alpha.com",        flags: [true, true, true, true] },
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -1042,33 +1042,30 @@ public:
     MOZ_ASSERT(mActor);
     mActor->AssertIsOnOwningThread();
 
     mActor = nullptr;
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
-  virtual nsresult
-  GetMozFullPathInternal(nsAString &aFilePath) MOZ_OVERRIDE;
+  virtual void
+  GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual already_AddRefed<DOMFileImpl>
-  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
-              MOZ_OVERRIDE;
+  CreateSlice(uint64_t aStart, uint64_t aLength,
+              const nsAString& aContentType, ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual nsresult
   GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
   virtual int64_t
   GetFileId() MOZ_OVERRIDE;
 
-  virtual nsresult
-  GetLastModifiedDate(JSContext* cx,
-                      JS::MutableHandle<JS::Value> aLastModifiedDate)
-                      MOZ_OVERRIDE;
+  virtual int64_t GetLastModified(ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual BlobChild*
   GetBlobChild() MOZ_OVERRIDE;
 
   virtual BlobParent*
   GetBlobParent() MOZ_OVERRIDE;
 
 private:
@@ -1356,47 +1353,50 @@ private:
  ******************************************************************************/
 
 NS_IMPL_ADDREF(BlobChild::RemoteBlobImpl)
 NS_IMPL_RELEASE_WITH_DESTROY(BlobChild::RemoteBlobImpl, Destroy())
 NS_IMPL_QUERY_INTERFACE_INHERITED(BlobChild::RemoteBlobImpl,
                                   DOMFileImpl,
                                   nsIRemoteBlob)
 
-nsresult
+void
 BlobChild::
-RemoteBlobImpl::GetMozFullPathInternal(nsAString &aFilePath)
+RemoteBlobImpl::GetMozFullPathInternal(nsAString& aFilePath,
+                                       ErrorResult& aRv)
 {
   if (!mActor) {
-    return NS_ERROR_UNEXPECTED;
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
   }
 
   nsString filePath;
   if (!mActor->SendGetFilePath(&filePath)) {
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
   }
 
   aFilePath = filePath;
-  return NS_OK;
 }
 
 already_AddRefed<DOMFileImpl>
 BlobChild::
-RemoteBlobImpl::CreateSlice(uint64_t aStart,
-                            uint64_t aLength,
-                            const nsAString& aContentType)
+RemoteBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
+                            const nsAString& aContentType, ErrorResult& aRv)
 {
   if (!mActor) {
+    aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
 
   nsRefPtr<DOMFileImpl> impl = helper->GetSlice(aStart, aLength, aContentType);
   if (NS_WARN_IF(!impl)) {
+    aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return impl.forget();
 }
 
 nsresult
 BlobChild::
@@ -1417,32 +1417,25 @@ RemoteBlobImpl::GetFileId()
   int64_t fileId;
   if (mActor && mActor->SendGetFileId(&fileId)) {
     return fileId;
   }
 
   return -1;
 }
 
-nsresult
+int64_t
 BlobChild::
-RemoteBlobImpl::GetLastModifiedDate(
-                                 JSContext* cx,
-                                 JS::MutableHandle<JS::Value> aLastModifiedDate)
+RemoteBlobImpl::GetLastModified(ErrorResult& aRv)
 {
   if (IsDateUnknown()) {
-    aLastModifiedDate.setNull();
-  } else {
-    JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate);
-    if (!date) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    aLastModifiedDate.setObject(*date);
+    return 0;
   }
-  return NS_OK;
+
+  return mLastModificationDate;
 }
 
 BlobChild*
 BlobChild::
 RemoteBlobImpl::GetBlobChild()
 {
   return mActor;
 }
@@ -1568,28 +1561,29 @@ BlobChild::CommonInit(BlobChild* aOther)
   MOZ_ASSERT_IF(mBackgroundManager, aOther->GetContentManager());
 
   MOZ_COUNT_CTOR(BlobChild);
 
   nsRefPtr<DOMFileImpl> otherImpl = aOther->GetBlobImpl();
   MOZ_ASSERT(otherImpl);
 
   nsString contentType;
-  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(otherImpl->GetType(contentType)));
-
-  uint64_t length;
-  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(otherImpl->GetSize(&length)));
+  otherImpl->GetType(contentType);
+
+  ErrorResult rv;
+  uint64_t length = otherImpl->GetSize(rv);
+  MOZ_ASSERT(!rv.Failed());
 
   nsRefPtr<RemoteBlobImpl> remoteBlob;
   if (otherImpl->IsFile()) {
     nsString name;
-    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(otherImpl->GetName(name)));
-
-    uint64_t modDate;
-    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(otherImpl->GetMozLastModifiedDate(&modDate)));
+    otherImpl->GetName(name);
+
+    uint64_t modDate = otherImpl->GetLastModified(rv);
+    MOZ_ASSERT(!rv.Failed());
 
     remoteBlob = new RemoteBlobImpl(this, name, contentType, length, modDate);
   } else {
     remoteBlob = new RemoteBlobImpl(this, contentType, length);
   }
 
   MOZ_ASSERT(remoteBlob);
 
@@ -1750,31 +1744,32 @@ BlobChild::GetOrCreateFromImpl(ChildMana
   }
 
   MOZ_ASSERT(!aBlobImpl->IsSizeUnknown());
   MOZ_ASSERT(!aBlobImpl->IsDateUnknown());
 
   AnyBlobConstructorParams blobParams;
 
   nsString contentType;
-  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aBlobImpl->GetType(contentType)));
-
-  uint64_t length;
-  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aBlobImpl->GetSize(&length)));
+  aBlobImpl->GetType(contentType);
+
+  ErrorResult rv;
+  uint64_t length = aBlobImpl->GetSize(rv);
+  MOZ_ASSERT(!rv.Failed());
 
   nsCOMPtr<nsIInputStream> stream;
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
     aBlobImpl->GetInternalStream(getter_AddRefs(stream))));
 
   if (aBlobImpl->IsFile()) {
     nsString name;
-    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aBlobImpl->GetName(name)));
-
-    uint64_t modDate;
-    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aBlobImpl->GetMozLastModifiedDate(&modDate)));
+    aBlobImpl->GetName(name);
+
+    uint64_t modDate = aBlobImpl->GetLastModified(rv);
+    MOZ_ASSERT(!rv.Failed());
 
     blobParams = FileBlobConstructorParams(name, contentType, length, modDate);
   } else {
     blobParams = NormalBlobConstructorParams(contentType, length);
   }
 
   InputStreamParams inputStreamParams;
 
@@ -1822,22 +1817,26 @@ BlobChild::CreateFromParams(ChildManager
       auto* actor =
         const_cast<BlobChild*>(
           static_cast<const BlobChild*>(params.sourceChild()));
       MOZ_ASSERT(actor);
 
       nsRefPtr<DOMFileImpl> source = actor->GetBlobImpl();
       MOZ_ASSERT(source);
 
-      nsRefPtr<DOMFileImpl> slice;
-      if (NS_WARN_IF(NS_FAILED(source->Slice(params.begin(),
-                                             params.end(),
-                                             params.contentType(),
-                                             3,
-                                             getter_AddRefs(slice))))) {
+      Optional<int64_t> start;
+      start.Construct(params.begin());
+
+      Optional<int64_t> end;
+      start.Construct(params.end());
+
+      ErrorResult rv;
+      nsRefPtr<DOMFileImpl> slice =
+        source->Slice(start, end, params.contentType(), rv);
+      if (NS_WARN_IF(rv.Failed())) {
         return nullptr;
       }
 
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(slice->SetMutable(false)));
 
       actor = new BlobChild(aManager, slice);
 
       actor->mParentID = aParams.id();
@@ -1968,28 +1967,16 @@ BlobChild::GetBlobImpl()
     blobImpl = mBlobImpl;
   }
 
   MOZ_ASSERT(blobImpl);
 
   return blobImpl.forget();
 }
 
-already_AddRefed<nsIDOMBlob>
-BlobChild::GetBlob()
-{
-  AssertIsOnOwningThread();
-
-  nsRefPtr<DOMFileImpl> blobImpl = GetBlobImpl();
-  MOZ_ASSERT(blobImpl);
-
-  nsCOMPtr<nsIDOMBlob> blob = new DOMFile(blobImpl);
-  return blob.forget();
-}
-
 bool
 BlobChild::SetMysteryBlobInfo(const nsString& aName,
                               const nsString& aContentType,
                               uint64_t aLength,
                               uint64_t aLastModifiedDate)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mBlobImpl);
@@ -2175,26 +2162,24 @@ class BlobParent::RemoteBlobImpl MOZ_FIN
   class SliceHelper;
 
   InputStreamParams mInputStreamParams;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual already_AddRefed<DOMFileImpl>
-  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
-              MOZ_OVERRIDE;
+  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
+              ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual nsresult
   GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
-  virtual nsresult
-  GetLastModifiedDate(JSContext* cx,
-                      JS::MutableHandle<JS::Value> aLastModifiedDate)
-                      MOZ_OVERRIDE;
+  virtual int64_t
+  GetLastModified(ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual BlobChild*
   GetBlobChild() MOZ_OVERRIDE;
 
   virtual BlobParent*
   GetBlobParent() MOZ_OVERRIDE;
 
 private:
@@ -2380,71 +2365,65 @@ class BlobParent::ForwardingRemoteBlobIm
   typedef mozilla::dom::indexedDB::FileManager FileManager;
 
   nsRefPtr<DOMFileImpl> mBlobImpl;
   nsCOMPtr<nsIRemoteBlob> mRemoteBlob;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
-  virtual nsresult
+  virtual void
   GetName(nsAString& aName) MOZ_OVERRIDE
   {
-    return mBlobImpl->GetName(aName);
+    mBlobImpl->GetName(aName);
   }
 
   virtual nsresult
   GetPath(nsAString& aPath) MOZ_OVERRIDE
   {
     return mBlobImpl->GetPath(aPath);
   }
 
-  virtual nsresult
-  GetLastModifiedDate(JSContext* aCx,
-                      JS::MutableHandle<JS::Value> aDate) MOZ_OVERRIDE
+  virtual int64_t
+  GetLastModified(ErrorResult& aRv) MOZ_OVERRIDE
   {
-    return mBlobImpl->GetLastModifiedDate(aCx, aDate);
+    return mBlobImpl->GetLastModified(aRv);
   }
 
-  virtual nsresult
-  GetMozFullPath(nsAString& aName) MOZ_OVERRIDE
+  virtual void
+  GetMozFullPath(nsAString& aName, ErrorResult& aRv) MOZ_OVERRIDE
   {
-    return mBlobImpl->GetMozFullPath(aName);
+    mBlobImpl->GetMozFullPath(aName, aRv);
   }
 
-  virtual nsresult
-  GetMozFullPathInternal(nsAString& aFileName) MOZ_OVERRIDE
+  virtual void
+  GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) MOZ_OVERRIDE
   {
-    return mBlobImpl->GetMozFullPathInternal(aFileName);
+    mBlobImpl->GetMozFullPathInternal(aFileName, aRv);
   }
 
-  virtual nsresult
-  GetSize(uint64_t* aSize) MOZ_OVERRIDE
+  virtual uint64_t
+  GetSize(ErrorResult& aRv) MOZ_OVERRIDE
   {
-    return mBlobImpl->GetSize(aSize);
+    return mBlobImpl->GetSize(aRv);
   }
 
-  virtual nsresult
+  virtual void
   GetType(nsAString& aType) MOZ_OVERRIDE
   {
-    return mBlobImpl->GetType(aType);
-  }
-
-  virtual nsresult
-  GetMozLastModifiedDate(uint64_t* aDate) MOZ_OVERRIDE
-  {
-    return mBlobImpl->GetMozLastModifiedDate(aDate);
+    mBlobImpl->GetType(aType);
   }
 
   virtual already_AddRefed<DOMFileImpl>
   CreateSlice(uint64_t aStart,
               uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE
+              const nsAString& aContentType,
+              ErrorResult& aRv) MOZ_OVERRIDE
   {
-    return mBlobImpl->CreateSlice(aStart, aLength, aContentType);
+    return mBlobImpl->CreateSlice(aStart, aLength, aContentType, aRv);
   }
 
   virtual const nsTArray<nsRefPtr<DOMFileImpl>>*
   GetSubBlobImpls() const MOZ_OVERRIDE
   {
     return mBlobImpl->GetSubBlobImpls();
   }
 
@@ -2524,25 +2503,16 @@ public:
   }
 
   virtual bool
   IsFile() const MOZ_OVERRIDE
   {
     return mBlobImpl->IsFile();
   }
 
-  virtual nsresult
-  Initialize(nsISupports* aOwner,
-             JSContext* aCx,
-             JSObject* aObj,
-             const JS::CallArgs& aArgs) MOZ_OVERRIDE
-  {
-    MOZ_CRASH("This should never be called!");
-  }
-
   virtual void
   Unlink() MOZ_OVERRIDE
   {
     return mBlobImpl->Unlink();
   }
 
   virtual void
   Traverse(nsCycleCollectionTraversalCallback& aCallback) MOZ_OVERRIDE
@@ -2593,26 +2563,29 @@ NS_IMPL_RELEASE_WITH_DESTROY(BlobParent:
 NS_IMPL_QUERY_INTERFACE_INHERITED(BlobParent::RemoteBlobImpl,
                                   DOMFileImplBase,
                                   nsIRemoteBlob)
 
 already_AddRefed<DOMFileImpl>
 BlobParent::
 RemoteBlobImpl::CreateSlice(uint64_t aStart,
                             uint64_t aLength,
-                            const nsAString& aContentType)
+                            const nsAString& aContentType,
+                            ErrorResult& aRv)
 {
   if (!mActor) {
+    aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
 
   nsRefPtr<DOMFileImpl> impl = helper->GetSlice(aStart, aLength, aContentType);
   if (NS_WARN_IF(!impl)) {
+    aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return impl.forget();
 }
 
 nsresult
 BlobParent::
@@ -2629,32 +2602,25 @@ RemoteBlobImpl::GetInternalStream(nsIInp
   }
 
   nsCOMPtr<nsIInputStream> stream =
     new BlobInputStreamTether(realStream, this);
   stream.forget(aStream);
   return NS_OK;
 }
 
-nsresult
+int64_t
 BlobParent::
-RemoteBlobImpl::GetLastModifiedDate(
-                                 JSContext* cx,
-                                 JS::MutableHandle<JS::Value> aLastModifiedDate)
+RemoteBlobImpl::GetLastModified(ErrorResult& aRv)
 {
   if (IsDateUnknown()) {
-    aLastModifiedDate.setNull();
-  } else {
-    JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate);
-    if (!date) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    aLastModifiedDate.setObject(*date);
+    return 0;
   }
-  return NS_OK;
+
+  return mLastModificationDate;
 }
 
 BlobChild*
 BlobParent::
 RemoteBlobImpl::GetBlobChild()
 {
   return nullptr;
 }
@@ -2945,28 +2911,28 @@ BlobParent::GetOrCreateFromImpl(ParentMa
 
   if (aBlobImpl->IsSizeUnknown() || aBlobImpl->IsDateUnknown()) {
     // We don't want to call GetSize or GetLastModifiedDate yet since that may
     // stat a file on the this thread. Instead we'll learn the size lazily from
     // the other side.
     blobParams = MysteryBlobConstructorParams();
   } else {
     nsString contentType;
-    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aBlobImpl->GetType(contentType)));
-
-    uint64_t length;
-    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aBlobImpl->GetSize(&length)));
+    aBlobImpl->GetType(contentType);
+
+    ErrorResult rv;
+    uint64_t length = aBlobImpl->GetSize(rv);
+    MOZ_ASSERT(!rv.Failed());
 
     if (aBlobImpl->IsFile()) {
       nsString name;
-      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aBlobImpl->GetName(name)));
-
-      uint64_t modDate;
-      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
-        aBlobImpl->GetMozLastModifiedDate(&modDate)));
+      aBlobImpl->GetName(name);
+
+      uint64_t modDate = aBlobImpl->GetLastModified(rv);
+      MOZ_ASSERT(!rv.Failed());
 
       blobParams =
         FileBlobConstructorParams(name, contentType, length, modDate);
     } else {
       blobParams = NormalBlobConstructorParams(contentType, length);
     }
   }
 
@@ -3033,22 +2999,26 @@ BlobParent::CreateFromParams(ParentManag
       auto* actor =
         const_cast<BlobParent*>(
           static_cast<const BlobParent*>(params.sourceParent()));
       MOZ_ASSERT(actor);
 
       nsRefPtr<DOMFileImpl> source = actor->GetBlobImpl();
       MOZ_ASSERT(source);
 
-      nsRefPtr<DOMFileImpl> slice;
-      if (NS_WARN_IF(NS_FAILED(source->Slice(params.begin(),
-                                             params.end(),
-                                             params.contentType(),
-                                             3,
-                                             getter_AddRefs(slice))))) {
+      Optional<int64_t> start;
+      start.Construct(params.begin());
+
+      Optional<int64_t> end;
+      end.Construct(params.end());
+
+      ErrorResult rv;
+      nsRefPtr<DOMFileImpl> slice =
+        source->Slice(start, end, params.contentType(), rv);
+      if (NS_WARN_IF(rv.Failed())) {
         return nullptr;
       }
 
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(slice->SetMutable(false)));
 
       nsRefPtr<IDTableEntry> idTableEntry =
         IDTableEntry::Create(params.optionalID(),
                              ActorManagerProcessID(aManager),
@@ -3162,30 +3132,16 @@ BlobParent::GetBlobImpl()
     blobImpl = mBlobImpl;
   }
 
   MOZ_ASSERT(blobImpl);
 
   return blobImpl.forget();
 }
 
-already_AddRefed<nsIDOMBlob>
-BlobParent::GetBlob()
-{
-  MOZ_ASSERT(!mBackgroundManager,
-             "Don't call this method on a non-DOM thread! Use GetBlobImpl()!");
-  AssertIsOnOwningThread();
-
-  nsRefPtr<DOMFileImpl> blobImpl = GetBlobImpl();
-  MOZ_ASSERT(blobImpl);
-
-  nsCOMPtr<nsIDOMBlob> blob = new DOMFile(blobImpl);
-  return blob.forget();
-}
-
 void
 BlobParent::NoteDyingRemoteBlobImpl()
 {
   MOZ_ASSERT(mRemoteBlobImpl);
   MOZ_ASSERT(!mOwnsBlobImpl);
 
   // This may be called on any thread due to the fact that RemoteBlobImpl is
   // designed to be passed between threads. We must start the shutdown process
@@ -3473,18 +3429,19 @@ BlobParent::RecvGetFilePath(nsString* aF
 #ifdef MOZ_CHILD_PERMISSIONS
   if (NS_WARN_IF(!IndexedDatabaseManager::InTestingMode())) {
     ASSERT_UNLESS_FUZZING();
     return false;
   }
 #endif
 
   nsString filePath;
-  nsresult rv = mBlobImpl->GetMozFullPathInternal(filePath);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
+  ErrorResult rv;
+  mBlobImpl->GetMozFullPathInternal(filePath, rv);
+  if (NS_WARN_IF(rv.Failed())) {
     return false;
   }
 
   *aFilePath = filePath;
   return true;
 }
 
 bool
--- a/dom/ipc/BlobChild.h
+++ b/dom/ipc/BlobChild.h
@@ -100,20 +100,16 @@ public:
 
   // Get the DOMFileImpl associated with this actor. This may always be called
   // on the sending side. It may also be called on the receiving side unless
   // this is a "mystery" blob that has not yet received a SetMysteryBlobInfo()
   // call.
   already_AddRefed<DOMFileImpl>
   GetBlobImpl();
 
-  // XXX This method will be removed soon.
-  already_AddRefed<nsIDOMBlob>
-  GetBlob();
-
   // Use this for files.
   bool
   SetMysteryBlobInfo(const nsString& aName,
                      const nsString& aContentType,
                      uint64_t aLength,
                      uint64_t aLastModifiedDate);
 
   // Use this for non-file blobs.
--- a/dom/ipc/BlobParent.h
+++ b/dom/ipc/BlobParent.h
@@ -124,21 +124,16 @@ public:
   {
     return mContentManager;
   }
 
   // Get the DOMFileImpl associated with this actor.
   already_AddRefed<DOMFileImpl>
   GetBlobImpl();
 
-  // XXX This method will be removed soon. It may never be called on a non-DOM
-  //     thread.
-  already_AddRefed<nsIDOMBlob>
-  GetBlob();
-
   void
   AssertIsOnOwningThread() const
 #ifdef DEBUG
   ;
 #else
   { }
 #endif
 
--- a/dom/ipc/FilePickerParent.cpp
+++ b/dom/ipc/FilePickerParent.cpp
@@ -112,17 +112,18 @@ FilePickerParent::FileSizeAndDateRunnabl
 
 void
 FilePickerParent::SendFiles(const nsCOMArray<nsIDOMFile>& aDomfiles)
 {
   nsIContentParent* parent = static_cast<TabParent*>(Manager())->Manager();
   InfallibleTArray<PBlobParent*> files;
 
   for (unsigned i = 0; i < aDomfiles.Length(); i++) {
-    BlobParent* blob = parent->GetOrCreateActorForBlob(aDomfiles[i]);
+    BlobParent* blob = parent->GetOrCreateActorForBlob(
+      static_cast<DOMFile*>(aDomfiles[i]));
     if (blob) {
       files.AppendElement(blob);
     }
   }
 
   InputFiles infiles;
   infiles.filesParent().SwapElements(files);
   unused << Send__delete__(this, infiles, mResult);
@@ -144,25 +145,30 @@ FilePickerParent::Done(int16_t aResult)
     NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
 
     nsCOMPtr<nsISupports> supports;
     bool loop = true;
     while (NS_SUCCEEDED(iter->HasMoreElements(&loop)) && loop) {
       iter->GetNext(getter_AddRefs(supports));
       if (supports) {
         nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
-        nsCOMPtr<nsIDOMFile> domfile = DOMFile::CreateFromFile(file);
+
+        // A null parent is fine because DOMFile are not used in this process
+        // but only in the child.
+        nsCOMPtr<nsIDOMFile> domfile = DOMFile::CreateFromFile(nullptr, file);
         domfiles.AppendElement(domfile);
       }
     }
   } else {
     nsCOMPtr<nsIFile> file;
     mFilePicker->GetFile(getter_AddRefs(file));
     if (file) {
-      nsCOMPtr<nsIDOMFile> domfile = DOMFile::CreateFromFile(file);
+      // A null parent is fine because DOMFile are not used in this process
+      // but only in the child.
+      nsCOMPtr<nsIDOMFile> domfile = DOMFile::CreateFromFile(nullptr, file);
       domfiles.AppendElement(domfile);
     }
   }
 
   MOZ_ASSERT(!mRunnable);
   mRunnable = new FileSizeAndDateRunnable(this, domfiles);
   if (!mRunnable->Dispatch()) {
     unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
--- a/dom/ipc/StructuredCloneUtils.cpp
+++ b/dom/ipc/StructuredCloneUtils.cpp
@@ -1,21 +1,22 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set sw=4 ts=8 et 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 "StructuredCloneUtils.h"
 
-#include "nsIDOMFile.h"
 #include "nsIDOMDOMException.h"
 #include "nsIMutable.h"
 #include "nsIXPConnect.h"
 
+#include "mozilla/dom/BlobBinding.h"
+#include "nsDOMFile.h"
 #include "nsContentUtils.h"
 #include "nsJSEnvironment.h"
 #include "MainThreadUtils.h"
 #include "StructuredCloneTags.h"
 #include "jsapi.h"
 
 using namespace mozilla::dom;
 
@@ -33,117 +34,71 @@ Read(JSContext* aCx, JSStructuredCloneRe
      uint32_t aData, void* aClosure)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aClosure);
 
   StructuredCloneClosure* closure =
     static_cast<StructuredCloneClosure*>(aClosure);
 
-  if (aTag == SCTAG_DOM_FILE) {
-    MOZ_ASSERT(aData < closure->mBlobs.Length());
-
-    nsCOMPtr<nsIDOMFile> file = do_QueryInterface(closure->mBlobs[aData]);
-    MOZ_ASSERT(file);
+  if (aTag == SCTAG_DOM_BLOB) {
+    // nsRefPtr<DOMFile> needs to go out of scope before toObjectOrNull() is
+    // called because the static analysis thinks dereferencing XPCOM objects
+    // can GC (because in some cases it can!), and a return statement with a
+    // JSObject* type means that JSObject* is on the stack as a raw pointer
+    // while destructors are running.
+    JS::Rooted<JS::Value> val(aCx);
+    {
+      MOZ_ASSERT(aData < closure->mBlobs.Length());
+      nsRefPtr<DOMFile> blob = closure->mBlobs[aData];
 
 #ifdef DEBUG
-    {
-      // File should not be mutable.
-      nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file);
-      bool isMutable;
-      MOZ_ASSERT(NS_SUCCEEDED(mutableFile->GetMutable(&isMutable)));
-      MOZ_ASSERT(!isMutable);
-    }
+      {
+        // File should not be mutable.
+        bool isMutable;
+        MOZ_ASSERT(NS_SUCCEEDED(blob->GetMutable(&isMutable)));
+        MOZ_ASSERT(!isMutable);
+      }
 #endif
 
-    JS::Rooted<JS::Value> wrappedFile(aCx);
-    nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile),
-                                             &wrappedFile);
-    if (NS_FAILED(rv)) {
-      Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR);
-      return nullptr;
+      // Let's create a new blob with the correct parent.
+      nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
+      MOZ_ASSERT(global);
+
+      nsRefPtr<DOMFile> newBlob = new DOMFile(global, blob->Impl());
+      if (!WrapNewBindingObject(aCx, newBlob, &val)) {
+        return nullptr;
+      }
     }
 
-    return &wrappedFile.toObject();
-  }
-
-  if (aTag == SCTAG_DOM_BLOB) {
-    MOZ_ASSERT(aData < closure->mBlobs.Length());
-
-    nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(closure->mBlobs[aData]);
-    MOZ_ASSERT(blob);
-
-#ifdef DEBUG
-    {
-      // Blob should not be mutable.
-      nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
-      bool isMutable;
-      MOZ_ASSERT(NS_SUCCEEDED(mutableBlob->GetMutable(&isMutable)));
-      MOZ_ASSERT(!isMutable);
-    }
-#endif
-
-    JS::Rooted<JS::Value> wrappedBlob(aCx);
-    nsresult rv = nsContentUtils::WrapNative(aCx, blob, &NS_GET_IID(nsIDOMBlob),
-                                             &wrappedBlob);
-    if (NS_FAILED(rv)) {
-      Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR);
-      return nullptr;
-    }
-
-    return &wrappedBlob.toObject();
+    return &val.toObject();
   }
 
   return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr);
 }
 
 bool
 Write(JSContext* aCx, JSStructuredCloneWriter* aWriter,
       JS::Handle<JSObject*> aObj, void* aClosure)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aClosure);
 
   StructuredCloneClosure* closure =
     static_cast<StructuredCloneClosure*>(aClosure);
 
-  // See if this is a wrapped native.
-  nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
-  nsContentUtils::XPConnect()->
-    GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative));
-
-  if (wrappedNative) {
-    // Get the raw nsISupports out of it.
-    nsISupports* wrappedObject = wrappedNative->Native();
-    MOZ_ASSERT(wrappedObject);
-
-    // See if the wrapped native is a nsIDOMFile.
-    nsCOMPtr<nsIDOMFile> file = do_QueryInterface(wrappedObject);
-    if (file) {
-      nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file);
-      if (mutableFile &&
-          NS_SUCCEEDED(mutableFile->SetMutable(false)) &&
-          JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILE,
-                             closure->mBlobs.Length())) {
-        closure->mBlobs.AppendElement(file);
-        return true;
-      }
-    }
-
-    // See if the wrapped native is a nsIDOMBlob.
-    nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(wrappedObject);
-    if (blob) {
-      nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
-      if (mutableBlob &&
-          NS_SUCCEEDED(mutableBlob->SetMutable(false)) &&
-          JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
-                             closure->mBlobs.Length())) {
-        closure->mBlobs.AppendElement(blob);
-        return true;
-      }
+  // See if the wrapped native is a DOMFile/Blob.
+  {
+    DOMFile* blob = nullptr;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
+        NS_SUCCEEDED(blob->SetMutable(false)) &&
+        JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
+                           closure->mBlobs.Length())) {
+      closure->mBlobs.AppendElement(blob);
+      return true;
     }
   }
 
   return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr);
 }
 
 JSStructuredCloneCallbacks gCallbacks = {
   Read,
--- a/dom/ipc/StructuredCloneUtils.h
+++ b/dom/ipc/StructuredCloneUtils.h
@@ -4,30 +4,30 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_StructuredCloneUtils_h
 #define mozilla_dom_StructuredCloneUtils_h
 
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
-#include "nsIDOMFile.h"
+#include "nsDOMFile.h"
 
 #include "js/StructuredClone.h"
 
 namespace mozilla {
 
 struct SerializedStructuredCloneBuffer;
 
 namespace dom {
 
 struct
 StructuredCloneClosure
 {
-  nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
+  nsTArray<nsRefPtr<DOMFile>> mBlobs;
 };
 
 struct
 StructuredCloneData
 {
   StructuredCloneData() : mData(nullptr), mDataLength(0) {}
   uint64_t* mData;
   size_t mDataLength;
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -92,22 +92,22 @@ nsIContentChild::AllocPBlobChild(const B
 bool
 nsIContentChild::DeallocPBlobChild(PBlobChild* aActor)
 {
   BlobChild::Destroy(aActor);
   return true;
 }
 
 BlobChild*
-nsIContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
+nsIContentChild::GetOrCreateActorForBlob(DOMFile* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
 
-  nsRefPtr<DOMFileImpl> blobImpl = static_cast<DOMFile*>(aBlob)->Impl();
+  nsRefPtr<DOMFileImpl> blobImpl = aBlob->Impl();
   MOZ_ASSERT(blobImpl);
 
   BlobChild* actor = BlobChild::GetOrCreate(this, blobImpl);
   NS_ENSURE_TRUE(actor, nullptr);
 
   return actor;
 }
 
--- a/dom/ipc/nsIContentChild.h
+++ b/dom/ipc/nsIContentChild.h
@@ -10,17 +10,16 @@
 #include "nsISupports.h"
 #include "nsTArrayForwardDeclare.h"
 #include "mozilla/dom/CPOWManagerGetter.h"
 
 #define NS_ICONTENTCHILD_IID                                    \
   { 0x4eed2e73, 0x94ba, 0x48a8,                                 \
     { 0xa2, 0xd1, 0xa5, 0xed, 0x86, 0xd7, 0xbb, 0xe4 } }
 
-class nsIDOMBlob;
 class nsString;
 
 namespace IPC {
 class Principal;
 } // IPC
 
 namespace mozilla {
 
@@ -29,27 +28,28 @@ class PJavaScriptChild;
 class CpowEntry;
 } // jsipc
 
 namespace dom {
 
 class BlobChild;
 class BlobConstructorParams;
 class ClonedMessageData;
+class DOMFile;
 class IPCTabContext;
 class PBlobChild;
 class PBrowserChild;
 
 class nsIContentChild : public nsISupports
                       , public CPOWManagerGetter
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTCHILD_IID)
 
-  BlobChild* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
+  BlobChild* GetOrCreateActorForBlob(DOMFile* aBlob);
 
   virtual PBlobChild* SendPBlobConstructor(
     PBlobChild* aActor,
     const BlobConstructorParams& aParams) = 0;
 
   virtual bool
   SendPBrowserConstructor(PBrowserChild* aActor,
                           const IPCTabContext& aContext,
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -146,22 +146,22 @@ nsIContentParent::AllocPBlobParent(const
 bool
 nsIContentParent::DeallocPBlobParent(PBlobParent* aActor)
 {
   BlobParent::Destroy(aActor);
   return true;
 }
 
 BlobParent*
-nsIContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
+nsIContentParent::GetOrCreateActorForBlob(DOMFile* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
 
-  nsRefPtr<DOMFileImpl> blobImpl = static_cast<DOMFile*>(aBlob)->Impl();
+  nsRefPtr<DOMFileImpl> blobImpl = aBlob->Impl();
   MOZ_ASSERT(blobImpl);
 
   BlobParent* actor = BlobParent::GetOrCreate(this, blobImpl);
   NS_ENSURE_TRUE(actor, nullptr);
 
   return actor;
 }
 
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -11,17 +11,16 @@
 #include "nsISupports.h"
 #include "mozilla/dom/CPOWManagerGetter.h"
 
 #define NS_ICONTENTPARENT_IID                                   \
   { 0xeeec9ebf, 0x8ecf, 0x4e38,                                 \
     { 0x81, 0xda, 0xb7, 0x34, 0x13, 0x7e, 0xac, 0xf3 } }
 
 class nsFrameMessageManager;
-class nsIDOMBlob;
 
 namespace IPC {
 class Principal;
 } // namespace IPC
 
 namespace mozilla {
 
 namespace jsipc {
@@ -29,30 +28,31 @@ class PJavaScriptParent;
 class CpowEntry;
 } // namespace jsipc
 
 namespace dom {
 
 class BlobConstructorParams;
 class BlobParent;
 class ContentParent;
+class DOMFile;
 class IPCTabContext;
 class PBlobParent;
 class PBrowserParent;
 
 class nsIContentParent : public nsISupports
                        , public mozilla::dom::ipc::MessageManagerCallback
                        , public CPOWManagerGetter
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTPARENT_IID)
 
   nsIContentParent();
 
-  BlobParent* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
+  BlobParent* GetOrCreateActorForBlob(DOMFile* aBlob);
 
   virtual uint64_t ChildID() = 0;
   virtual bool IsForApp() = 0;
   virtual bool IsForBrowser() = 0;
 
   virtual PBlobParent* SendPBlobConstructor(
     PBlobParent* aActor,
     const BlobConstructorParams& aParams) NS_WARN_UNUSED_RESULT = 0;
--- a/dom/mobilemessage/MmsMessage.cpp
+++ b/dom/mobilemessage/MmsMessage.cpp
@@ -86,20 +86,25 @@ MmsMessage::MmsMessage(const mobilemessa
 {
   uint32_t len = aData.attachments().Length();
   mAttachments.SetCapacity(len);
   for (uint32_t i = 0; i < len; i++) {
     MmsAttachment att;
     const MmsAttachmentData &element = aData.attachments()[i];
     att.mId = element.id();
     att.mLocation = element.location();
+
+    // mContent is not going to be exposed to JS directly so we can use
+    // nullptr as parent.
     if (element.contentParent()) {
-      att.mContent = static_cast<BlobParent*>(element.contentParent())->GetBlob();
+      nsRefPtr<DOMFileImpl> impl = static_cast<BlobParent*>(element.contentParent())->GetBlobImpl();
+      att.mContent = new DOMFile(nullptr, impl);
     } else if (element.contentChild()) {
-      att.mContent = static_cast<BlobChild*>(element.contentChild())->GetBlob();
+      nsRefPtr<DOMFileImpl> impl = static_cast<BlobChild*>(element.contentChild())->GetBlobImpl();
+      att.mContent = new DOMFile(nullptr, impl);
     } else {
       NS_WARNING("MmsMessage: Unable to get attachment content.");
     }
     mAttachments.AppendElement(att);
   }
 
   len = aData.deliveryInfo().Length();
   mDeliveryInfo.SetCapacity(len);
@@ -382,20 +387,19 @@ MmsMessage::GetData(ContentParent* aPare
     const Attachment &element = mAttachments[i];
     mma.id().Assign(element.id);
     mma.location().Assign(element.location);
 
     // This is a workaround. Sometimes the blob we get from the database
     // doesn't have a valid last modified date, making the ContentParent
     // send a "Mystery Blob" to the ContentChild. Attempting to get the
     // last modified date of blob can force that value to be initialized.
-    DOMFile* file = static_cast<DOMFile*>(element.content.get());
-    if (file->IsDateUnknown()) {
+    if (element.content->IsDateUnknown()) {
       uint64_t date;
-      if (NS_FAILED(file->GetMozLastModifiedDate(&date))) {
+      if (NS_FAILED(element.content->GetMozLastModifiedDate(&date))) {
         NS_WARNING("Failed to get last modified date!");
       }
     }
 
     mma.contentParent() = aParent->GetOrCreateActorForBlob(element.content);
     if (!mma.contentParent()) {
       return false;
     }
@@ -567,24 +571,28 @@ MmsMessage::GetAttachments(JSContext* aC
                                    attachment.location.Length());
     NS_ENSURE_TRUE(tmpJsStr, NS_ERROR_OUT_OF_MEMORY);
 
     if (!JS_DefineProperty(aCx, attachmentObj, "location", tmpJsStr, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
     // Get |attachment.mContent|.
-    JS::Rooted<JS::Value> tmpJsVal(aCx);
-    nsresult rv = nsContentUtils::WrapNative(aCx,
-                                             attachment.content,
-                                             &NS_GET_IID(nsIDOMBlob),
-                                             &tmpJsVal);
-    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Duplicating the DOMFile with the correct parent object.
+    nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
+    MOZ_ASSERT(global);
+    nsRefPtr<DOMFile> newBlob = new DOMFile(global, attachment.content->Impl());
 
-    if (!JS_DefineProperty(aCx, attachmentObj, "content", tmpJsVal, JSPROP_ENUMERATE)) {
+    JS::Rooted<JS::Value> val(aCx);
+    if (!WrapNewBindingObject(aCx, newBlob, &val)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    if (!JS_DefineProperty(aCx, attachmentObj, "content", val, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
     if (!JS_SetElement(aCx, attachments, i, attachmentObj)) {
       return NS_ERROR_FAILURE;
     }
   }
 
--- a/dom/mobilemessage/MmsMessage.h
+++ b/dom/mobilemessage/MmsMessage.h
@@ -11,32 +11,34 @@
 #include "mozilla/dom/mobilemessage/Types.h"
 #include "mozilla/dom/MozMmsMessageBinding.h"
 #include "mozilla/dom/MozMobileMessageManagerBinding.h"
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
 namespace dom {
 
+class DOMFile;
+
 namespace mobilemessage {
 class MmsMessageData;
 } // namespace mobilemessage
 
 class ContentParent;
 
 class MmsMessage MOZ_FINAL : public nsIDOMMozMmsMessage
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMOZMMSMESSAGE
 
   // If this is changed, change the WebIDL dictionary as well.
   struct Attachment MOZ_FINAL
   {
-    nsCOMPtr<nsIDOMBlob> content;
+    nsRefPtr<DOMFile> content;
     nsString id;
     nsString location;
 
     explicit Attachment(const MmsAttachment& aAttachment) :
       content(aAttachment.mContent),
       id(aAttachment.mId),
       location(aAttachment.mLocation)
     {}
--- a/dom/mobilemessage/gonk/WspPduHelper.jsm
+++ b/dom/mobilemessage/gonk/WspPduHelper.jsm
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
+Cu.importGlobalProperties(['Blob']);
 Cu.import("resource://gre/modules/wap_consts.js", this);
 
 let DEBUG; // set to true to see debug messages
 
 // Special ASCII characters
 const NUL = 0;
 const CR = 13;
 const LF = 10;
--- a/dom/mobilemessage/ipc/SmsParent.cpp
+++ b/dom/mobilemessage/ipc/SmsParent.cpp
@@ -48,23 +48,34 @@ MmsAttachmentDataToJSObject(JSContext* a
   JS::Rooted<JSString*> locStr(aContext, JS_NewUCStringCopyN(aContext,
                                                              aAttachment.location().get(),
                                                              aAttachment.location().Length()));
   NS_ENSURE_TRUE(locStr, nullptr);
   if (!JS_DefineProperty(aContext, obj, "location", locStr, 0)) {
     return nullptr;
   }
 
-  nsCOMPtr<nsIDOMBlob> blob = static_cast<BlobParent*>(aAttachment.contentParent())->GetBlob();
+  nsRefPtr<DOMFileImpl> blobImpl = static_cast<BlobParent*>(aAttachment.contentParent())->GetBlobImpl();
+
+  // nsRefPtr<DOMFile> needs to go out of scope before toObjectOrNull() is
+  // called because the static analysis thinks dereferencing XPCOM objects
+  // can GC (because in some cases it can!), and a return statement with a
+  // JSObject* type means that JSObject* is on the stack as a raw pointer
+  // while destructors are running.
   JS::Rooted<JS::Value> content(aContext);
-  nsresult rv = nsContentUtils::WrapNative(aContext,
-                                           blob,
-                                           &NS_GET_IID(nsIDOMBlob),
-                                           &content);
-  NS_ENSURE_SUCCESS(rv, nullptr);
+  {
+    nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aContext));
+    MOZ_ASSERT(global);
+
+    nsRefPtr<DOMFile> blob = new DOMFile(global, blobImpl);
+    if (!WrapNewBindingObject(aContext, blob, &content)) {
+      return nullptr;
+    }
+  }
+
   if (!JS_DefineProperty(aContext, obj, "content", content, 0)) {
     return nullptr;
   }
 
   return obj;
 }
 
 static bool
--- a/dom/network/UDPSocket.cpp
+++ b/dom/network/UDPSocket.cpp
@@ -8,17 +8,17 @@
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/UDPMessageEvent.h"
 #include "mozilla/dom/UDPSocketBinding.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "mozilla/net/DNS.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
-#include "nsIDOMFile.h"
+#include "nsDOMFile.h"
 #include "nsINetAddr.h"
 #include "nsStringStream.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(UDPSocket)
 
@@ -323,19 +323,19 @@ UDPSocket::Send(const StringOrBlobOrArra
     remotePort = mRemotePort.Value();
   } else {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return false;
   }
 
   nsCOMPtr<nsIInputStream> stream;
   if (aData.IsBlob()) {
-    nsCOMPtr<nsIDOMBlob> blob = aData.GetAsBlob();
+    DOMFile& blob = aData.GetAsBlob();
 
-    aRv = blob->GetInternalStream(getter_AddRefs(stream));
+    aRv = blob.GetInternalStream(getter_AddRefs(stream));
     if (NS_WARN_IF(aRv.Failed())) {
       return false;
     }
   } else {
     nsresult rv;
     nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       aRv.Throw(rv);
--- a/dom/settings/SettingsDB.jsm
+++ b/dom/settings/SettingsDB.jsm
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cu = Components.utils;
 
+Cu.importGlobalProperties(['Blob']);
 Cu.import("resource://gre/modules/Services.jsm");
 
 this.EXPORTED_SYMBOLS = ["SettingsDB", "SETTINGSDB_NAME", "SETTINGSSTORE_NAME"];
 
 const DEBUG = false;
 function debug(s) {
   if (DEBUG) dump("-*- SettingsDB: " + s + "\n");
 }
--- a/dom/webidl/Blob.webidl
+++ b/dom/webidl/Blob.webidl
@@ -5,32 +5,37 @@
  *
  * The origin of this IDL file is
  * http://dev.w3.org/2006/webapi/FileAPI/#blob
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-/*
-[Constructor, Constructor((ArrayBuffer or ArrayBufferView or Blob or DOMString)[] blobParts, optional BlobPropertyBag options)] 
+[Constructor,
+ Constructor(sequence<(ArrayBuffer or ArrayBufferView or Blob or DOMString)> blobParts, optional BlobPropertyBag options),
+ Exposed=(Window,Worker)]
 interface Blob {
 
+  [GetterThrows]
   readonly attribute unsigned long long size;
+
   readonly attribute DOMString type;
 
+  // readonly attribute boolean isClosed; TODO bug 1048321
+
   //slice Blob into byte-ranged chunks
 
-  Blob slice(optional long long start,
-             optional long long end,
-             optional DOMString contentType);
-  void close(); 
+  [Throws]
+  Blob slice([Clamp] optional long long start,
+             [Clamp] optional long long end,
+             optional DOMString contentType = "");
 
+  // void close(); TODO bug 1048325
 };
-*/
 
 enum EndingTypes{"transparent", "native"};
 
 dictionary BlobPropertyBag {
 
   DOMString type = "";
   EndingTypes endings = "transparent";
 
--- a/dom/webidl/BlobEvent.webidl
+++ b/dom/webidl/BlobEvent.webidl
@@ -1,14 +1,13 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
-interface Blob;
 
 [Constructor(DOMString type, optional BlobEventInit eventInitDict)]
 interface BlobEvent : Event
 {
   readonly attribute Blob? data;
 };
 
 dictionary BlobEventInit : EventInit
--- a/dom/webidl/Directory.webidl
+++ b/dom/webidl/Directory.webidl
@@ -1,16 +1,14 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-interface File;
-
 /*
  * All functions on Directory that accept DOMString arguments for file or
  * directory names only allow relative path to current directory itself. The
  * path should be a descendent path like "path/to/file.txt" and not contain a
  * segment of ".." or ".". So the paths aren't allowed to walk up the directory
  * tree. For example, paths like "../foo", "..", "/foo/bar" or "foo/../bar" are
  * not allowed.
  */
--- a/dom/webidl/File.webidl
+++ b/dom/webidl/File.webidl
@@ -1,9 +1,45 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-dictionary FilePropertyBag : BlobPropertyBag {
-  DOMString name = "";
+interface nsIFile;
+
+[Constructor(sequence<(ArrayBuffer or ArrayBufferView or Blob or DOMString)> fileBits,
+             ScalarValueString fileName, optional FilePropertyBag options),
+
+ // These constructors are just for chrome callers:
+ Constructor(Blob fileBits, optional FilePropertyBag options),
+ Constructor(nsIFile fileBits, optional FilePropertyBag options),
+ Constructor(ScalarValueString fileBits, optional FilePropertyBag options),
+
+ Exposed=(Window,Worker)]
+interface File : Blob {
+
+  readonly attribute DOMString name;
+
+  [GetterThrows]
+  readonly attribute long long lastModified;
+
 };
+
+
+dictionary FilePropertyBag {
+
+      DOMString type = "";
+      DOMString name = ""; // TODO: to remove!
+      long long lastModified;
+
+};
+
+// Mozilla extensions
+partial interface File {
+
+  [GetterThrows]
+  readonly attribute Date lastModifiedDate;
+
+  [GetterThrows]
+  readonly attribute DOMString mozFullPath;
+
+};
--- a/dom/webidl/FileList.webidl
+++ b/dom/webidl/FileList.webidl
@@ -5,14 +5,12 @@
  *
  * The origin of this IDL file is
  * http://dev.w3.org/2006/webapi/FileAPI/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-interface File;
-
 interface FileList {
   getter File? item(unsigned long index);
   readonly attribute unsigned long length;
 };
--- a/dom/webidl/FileReaderSync.webidl
+++ b/dom/webidl/FileReaderSync.webidl
@@ -5,18 +5,16 @@
  *
  * The origin of this IDL file is
  * http://dev.w3.org/2006/webapi/FileAPI/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-interface Blob;
-
 [Constructor,
  Exposed=Worker]
 interface FileReaderSync {
 
   // Synchronously return strings
 
   [Throws]
   ArrayBuffer readAsArrayBuffer(Blob blob);
--- a/dom/webidl/HTMLCanvasElement.webidl
+++ b/dom/webidl/HTMLCanvasElement.webidl
@@ -5,17 +5,16 @@
  *
  * The origin of this IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/#the-canvas-element
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
-interface Blob;
 interface nsIInputStreamCallback;
 interface nsISupports;
 interface Variant;
 
 interface HTMLCanvasElement : HTMLElement {
   [Pure, SetterThrows]
            attribute unsigned long width;
   [Pure, SetterThrows]
--- a/dom/webidl/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -5,17 +5,16 @@
  *
  * The origin of this IDL file is
  * www.w3.org/TR/2012/WD-XMLHttpRequest-20120117/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-interface Blob;
 interface InputStream;
 interface MozChannel;
 interface IID;
 
 enum XMLHttpRequestResponseType {
   "",
   "arraybuffer",
   "blob",
deleted file mode 100644
--- a/dom/workers/File.cpp
+++ /dev/null
@@ -1,503 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* 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 "File.h"
-
-#include "nsDOMFile.h"
-#include "nsDOMBlobBuilder.h"
-#include "nsError.h"
-
-#include "jsapi.h"
-#include "jsfriendapi.h"
-#include "nsCOMPtr.h"
-#include "nsJSUtils.h"
-#include "nsString.h"
-
-#include "mozilla/dom/Exceptions.h"
-#include "WorkerInlines.h"
-#include "WorkerPrivate.h"
-
-USING_WORKERS_NAMESPACE
-using mozilla::dom::Throw;
-
-namespace {
-
-class Blob
-{
-  // Blob should never be instantiated.
-  Blob();
-  ~Blob();
-
-  static const JSClass sClass;
-  static const JSPropertySpec sProperties[];
-  static const JSFunctionSpec sFunctions[];
-
-public:
-  static JSObject*
-  InitClass(JSContext* aCx, JS::Handle<JSObject*> aObj)
-  {
-    return JS_InitClass(aCx, aObj, JS::NullPtr(), &sClass, Construct, 0,
-                        sProperties, sFunctions, nullptr, nullptr);
-  }
-
-  static JSObject*
-  Create(JSContext* aCx, nsIDOMBlob* aBlob)
-  {
-    MOZ_ASSERT(SameCOMIdentity(static_cast<nsISupports*>(aBlob), aBlob));
-
-    JSObject* obj = JS_NewObject(aCx, &sClass, JS::NullPtr(), JS::NullPtr());
-    if (obj) {
-      JS_SetPrivate(obj, aBlob);
-      NS_ADDREF(aBlob);
-    }
-    return obj;
-  }
-
-  static nsIDOMBlob*
-  GetPrivate(JSObject* aObj);
-
-private:
-  static nsIDOMBlob*
-  GetInstancePrivate(JSContext* aCx, JS::Handle<JSObject*> aObj, const char* aFunctionName)
-  {
-    nsIDOMBlob* blob = GetPrivate(aObj);
-    if (blob) {
-      return blob;
-    }
-
-    JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
-                         JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
-                         JS_GetClass(aObj)->name);
-    return nullptr;
-  }
-
-  static nsIDOMBlob*
-  Unwrap(JSContext* aCx, JSObject* aObj)
-  {
-    return GetPrivate(aObj);
-  }
-
-  static bool
-  Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
-  {
-    JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
-
-    nsRefPtr<DOMMultipartFileImpl> fileImpl = new DOMMultipartFileImpl();
-    nsRefPtr<mozilla::dom::DOMFile> file = new mozilla::dom::DOMFile(fileImpl);
-
-    nsresult rv = fileImpl->InitBlob(aCx, args.length(), args.array(), Unwrap);
-    if (NS_FAILED(rv)) {
-      return Throw(aCx, rv);
-    }
-
-    JSObject* obj = file::CreateBlob(aCx, file);
-    if (!obj) {
-      return false;
-    }
-
-    args.rval().setObject(*obj);
-    return true;
-  }
-
-  static void
-  Finalize(JSFreeOp* aFop, JSObject* aObj)
-  {
-    MOZ_ASSERT(JS_GetClass(aObj) == &sClass);
-
-    nsIDOMBlob* blob = GetPrivate(aObj);
-    NS_IF_RELEASE(blob);
-  }
-
-  static bool
-  IsBlob(JS::Handle<JS::Value> v)
-  {
-    return v.isObject() && GetPrivate(&v.toObject()) != nullptr;
-  }
-
-  static bool
-  GetSizeImpl(JSContext* aCx, JS::CallArgs aArgs)
-  {
-    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
-    nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "size");
-    MOZ_ASSERT(blob);
-
-    uint64_t size;
-    if (NS_FAILED(blob->GetSize(&size))) {
-      return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
-    }
-
-    aArgs.rval().setNumber(double(size));
-    return true;
-  }
-
-  static bool
-  GetSize(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-  {
-    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
-    return JS::CallNonGenericMethod<IsBlob, GetSizeImpl>(aCx, args);
-  }
-
-  static bool
-  GetTypeImpl(JSContext* aCx, JS::CallArgs aArgs)
-  {
-    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
-    nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "type");
-    MOZ_ASSERT(blob);
-
-    nsString type;
-    if (NS_FAILED(blob->GetType(type))) {
-      return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
-    }
-
-    JSString* jsType = JS_NewUCStringCopyN(aCx, type.get(), type.Length());
-    if (!jsType) {
-      return false;
-    }
-
-    aArgs.rval().setString(jsType);
-    return true;
-  }
-
-  static bool
-  GetType(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-  {
-    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
-    return JS::CallNonGenericMethod<IsBlob, GetTypeImpl>(aCx, args);
-  }
-
-  static bool
-  Slice(JSContext* aCx, unsigned aArgc, jsval* aVp)
-  {
-    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
-
-    JS::Rooted<JSObject*> obj(aCx, args.thisv().toObjectOrNull());
-    if (!obj) {
-      return false;
-    }
-
-    nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "slice");
-    if (!blob) {
-      return false;
-    }
-
-    double start = 0, end = 0;
-    JS::Rooted<JSString*> jsContentType(aCx, JS_GetEmptyString(JS_GetRuntime(aCx)));
-    if (!JS_ConvertArguments(aCx, args, "/IIS", &start,
-                             &end, jsContentType.address())) {
-      return false;
-    }
-
-    nsAutoJSString contentType;
-    if (!contentType.init(aCx, jsContentType)) {
-      return false;
-    }
-
-    uint8_t optionalArgc = aArgc;
-    nsCOMPtr<nsIDOMBlob> rtnBlob;
-    if (NS_FAILED(blob->Slice(static_cast<uint64_t>(start),
-                              static_cast<uint64_t>(end),
-                              contentType, optionalArgc,
-                              getter_AddRefs(rtnBlob)))) {
-      return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
-    }
-
-    JSObject* rtnObj = file::CreateBlob(aCx, rtnBlob);
-    if (!rtnObj) {
-      return false;
-    }
-
-    args.rval().setObject(*rtnObj);
-    return true;
-  }
-};
-
-const JSClass Blob::sClass = {
-  "Blob",
-  JSCLASS_HAS_PRIVATE,
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize
-};
-
-const JSPropertySpec Blob::sProperties[] = {
-  JS_PSGS("size", GetSize, GetterOnlyJSNative, JSPROP_ENUMERATE),
-  JS_PSGS("type", GetType, GetterOnlyJSNative, JSPROP_ENUMERATE),
-  JS_PS_END
-};
-
-const JSFunctionSpec Blob::sFunctions[] = {
-  JS_FN("slice", Slice, 1, JSPROP_ENUMERATE),
-  JS_FS_END
-};
-
-class File : public Blob
-{
-  // File should never be instantiated.
-  File();
-  ~File();
-
-  static const JSClass sClass;
-  static const JSPropertySpec sProperties[];
-
-public:
-  static JSObject*
-  InitClass(JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<JSObject*> aParentProto)
-  {
-    return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
-                        sProperties, nullptr, nullptr, nullptr);
-  }
-
-  static JSObject*
-  Create(JSContext* aCx, nsIDOMFile* aFile)
-  {
-    MOZ_ASSERT(SameCOMIdentity(static_cast<nsISupports*>(aFile), aFile));
-
-    JSObject* obj = JS_NewObject(aCx, &sClass, JS::NullPtr(), JS::NullPtr());
-    if (obj) {
-      JS_SetPrivate(obj, aFile);
-      NS_ADDREF(aFile);
-    }
-    return obj;
-  }
-
-  static nsIDOMFile*
-  GetPrivate(JSObject* aObj)
-  {
-    if (aObj) {
-      const JSClass* classPtr = JS_GetClass(aObj);
-      if (classPtr == &sClass) {
-        nsISupports* priv = static_cast<nsISupports*>(JS_GetPrivate(aObj));
-        nsCOMPtr<nsIDOMFile> file = do_QueryInterface(priv);
-        MOZ_ASSERT_IF(priv, file);
-        return file;
-      }
-    }
-    return nullptr;
-  }
-
-  static const JSClass*
-  Class()
-  {
-    return &sClass;
-  }
-
-private:
-  static nsIDOMFile*
-  GetInstancePrivate(JSContext* aCx, JS::Handle<JSObject*> aObj, const char* aFunctionName)
-  {
-    nsIDOMFile* file = GetPrivate(aObj);
-    if (file) {
-      return file;
-    }
-
-    JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
-                         JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
-                         JS_GetClass(aObj)->name);
-    return nullptr;
-  }
-
-  static bool
-  Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
-  {
-    JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
-                         JSMSG_WRONG_CONSTRUCTOR,
-                         sClass.name);
-    return false;
-  }
-
-  static void
-  Finalize(JSFreeOp* aFop, JSObject* aObj)
-  {
-    MOZ_ASSERT(JS_GetClass(aObj) == &sClass);
-
-    nsIDOMFile* file = GetPrivate(aObj);
-    NS_IF_RELEASE(file);
-  }
-
-  static bool
-  IsFile(JS::Handle<JS::Value> v)
-  {
-    return v.isObject() && GetPrivate(&v.toObject()) != nullptr;
-  }
-
-  static bool
-  GetMozFullPathImpl(JSContext* aCx, JS::CallArgs aArgs)
-  {
-    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
-    nsIDOMFile* file = GetInstancePrivate(aCx, obj, "mozFullPath");
-    MOZ_ASSERT(file);
-
-    nsString fullPath;
-
-    if (GetWorkerPrivateFromContext(aCx)->UsesSystemPrincipal() &&
-        NS_FAILED(file->GetMozFullPathInternal(fullPath))) {
-      return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
-    }
-
-    JSString* jsFullPath = JS_NewUCStringCopyN(aCx, fullPath.get(),
-                                               fullPath.Length());
-    if (!jsFullPath) {
-      return false;
-    }
-
-    aArgs.rval().setString(jsFullPath);
-    return true;
-  }
-
-  static bool
-  GetMozFullPath(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-  {
-    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
-    return JS::CallNonGenericMethod<IsFile, GetMozFullPathImpl>(aCx, args);
-  }
-
-  static bool
-  GetNameImpl(JSContext* aCx, JS::CallArgs aArgs)
-  {
-    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
-    nsIDOMFile* file = GetInstancePrivate(aCx, obj, "name");
-    MOZ_ASSERT(file);
-
-    nsString name;
-    if (NS_FAILED(file->GetName(name))) {
-      name.Truncate();
-    }
-
-    JSString* jsName = JS_NewUCStringCopyN(aCx, name.get(), name.Length());
-    if (!jsName) {
-      return false;
-    }
-
-    aArgs.rval().setString(jsName);
-    return true;
-  }
-
-  static bool
-  GetName(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-  {
-    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
-    return JS::CallNonGenericMethod<IsFile, GetNameImpl>(aCx, args);
-  }
-
-  static bool
-  GetPathImpl(JSContext* aCx, JS::CallArgs aArgs)
-  {
-    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
-    nsIDOMFile* file = GetInstancePrivate(aCx, obj, "path");
-    MOZ_ASSERT(file);
-
-    nsString path;
-    if (NS_FAILED(file->GetPath(path))) {
-      path.Truncate();
-    }
-
-    JSString* jsPath = JS_NewUCStringCopyN(aCx, path.get(), path.Length());
-    if (!jsPath) {
-      return false;
-    }
-
-    aArgs.rval().setString(jsPath);
-    return true;
-  }
-
-  static bool
-  GetPath(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-  {
-    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
-    return JS::CallNonGenericMethod<IsFile, GetPathImpl>(aCx, args);
-  }
-
-  static bool
-  GetLastModifiedDateImpl(JSContext* aCx, JS::CallArgs aArgs)
-  {
-    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
-    nsIDOMFile* file = GetInstancePrivate(aCx, obj, "lastModifiedDate");
-    MOZ_ASSERT(file);
-
-    if (NS_FAILED(file->GetLastModifiedDate(aCx, aArgs.rval()))) {
-      return false;
-    }
-    return true;
-  }
-
-  static bool
-  GetLastModifiedDate(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-  {
-    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
-    return JS::CallNonGenericMethod<IsFile, GetLastModifiedDateImpl>(aCx, args);
-  }
-};
-
-const JSClass File::sClass = {
-  "File",
-  JSCLASS_HAS_PRIVATE,
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize
-};
-
-const JSPropertySpec File::sProperties[] = {
-  JS_PSGS("name", GetName, GetterOnlyJSNative, JSPROP_ENUMERATE),
-  JS_PSGS("path", GetPath, GetterOnlyJSNative, JSPROP_ENUMERATE),
-  JS_PSGS("lastModifiedDate", GetLastModifiedDate, GetterOnlyJSNative,
-          JSPROP_ENUMERATE),
-  JS_PSGS("mozFullPath", GetMozFullPath, GetterOnlyJSNative, JSPROP_ENUMERATE),
-  JS_PS_END
-};
-
-nsIDOMBlob*
-Blob::GetPrivate(JSObject* aObj)
-{
-  if (aObj) {
-    const JSClass* classPtr = JS_GetClass(aObj);
-    if (classPtr == &sClass || classPtr == File::Class()) {
-      nsISupports* priv = static_cast<nsISupports*>(JS_GetPrivate(aObj));
-      nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(priv);
-      MOZ_ASSERT_IF(priv, blob);
-      return blob;
-    }
-  }
-  return nullptr;
-}
-
-} // anonymous namespace
-
-BEGIN_WORKERS_NAMESPACE
-
-namespace file {
-
-JSObject*
-CreateBlob(JSContext* aCx, nsIDOMBlob* aBlob)
-{
-  return Blob::Create(aCx, aBlob);
-}
-
-bool
-InitClasses(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
-{
-  JS::Rooted<JSObject*> blobProto(aCx, Blob::InitClass(aCx, aGlobal));
-  return blobProto && File::InitClass(aCx, aGlobal, blobProto);
-}
-
-nsIDOMBlob*
-GetDOMBlobFromJSObject(JSObject* aObj)
-{
-  return Blob::GetPrivate(aObj);
-}
-
-JSObject*
-CreateFile(JSContext* aCx, nsIDOMFile* aFile)
-{
-  return File::Create(aCx, aFile);
-}
-
-nsIDOMFile*
-GetDOMFileFromJSObject(JSObject* aObj)
-{
-  return File::GetPrivate(aObj);
-}
-
-} // namespace file
-
-END_WORKERS_NAMESPACE
deleted file mode 100644
--- a/dom/workers/File.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* 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/. */
-
-#ifndef mozilla_dom_workers_file_h__
-#define mozilla_dom_workers_file_h__
-
-#include "Workers.h"
-
-class nsIDOMFile;
-class nsIDOMBlob;
-
-BEGIN_WORKERS_NAMESPACE
-
-namespace file {
-
-bool
-InitClasses(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
-
-JSObject*
-CreateBlob(JSContext* aCx, nsIDOMBlob* aBlob);
-
-nsIDOMBlob*
-GetDOMBlobFromJSObject(JSObject* aObj);
-
-JSObject*
-CreateFile(JSContext* aCx, nsIDOMFile* aFile);
-
-nsIDOMFile*
-GetDOMFileFromJSObject(JSObject* aObj);
-
-} // namespace file
-
-END_WORKERS_NAMESPACE
-
-#endif /* mozilla_dom_workers_file_h__ */
--- a/dom/workers/FileReaderSync.cpp
+++ b/dom/workers/FileReaderSync.cpp
@@ -10,30 +10,30 @@
 #include "mozilla/Base64.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/FileReaderSyncBinding.h"
 #include "nsCExternalHandlerService.h"
 #include "nsComponentManagerUtils.h"
 #include "nsCOMPtr.h"
 #include "nsDOMClassInfoID.h"
+#include "nsDOMFile.h"
 #include "nsError.h"
-#include "nsIDOMFile.h"
 #include "nsIConverterInputStream.h"
 #include "nsIInputStream.h"
 #include "nsISeekableStream.h"
 #include "nsISupportsImpl.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 
-#include "File.h"
 #include "RuntimeService.h"
 
 USING_WORKERS_NAMESPACE
 using namespace mozilla;
+using namespace mozilla::dom;
 using mozilla::dom::Optional;
 using mozilla::dom::GlobalObject;
 
 // static
 already_AddRefed<FileReaderSync>
 FileReaderSync::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
 {
   nsRefPtr<FileReaderSync> frs = new FileReaderSync();
@@ -45,28 +45,22 @@ JSObject*
 FileReaderSync::WrapObject(JSContext* aCx)
 {
   return FileReaderSyncBinding_workers::Wrap(aCx, this);
 }
 
 void
 FileReaderSync::ReadAsArrayBuffer(JSContext* aCx,
                                   JS::Handle<JSObject*> aScopeObj,
-                                  JS::Handle<JSObject*> aBlob,
+                                  DOMFile& aBlob,
                                   JS::MutableHandle<JSObject*> aRetval,
                                   ErrorResult& aRv)
 {
-  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
-  if (!blob) {
-    aRv.Throw(NS_ERROR_INVALID_ARG);
-    return;
-  }
-
   uint64_t blobSize;
-  nsresult rv = blob->GetSize(&blobSize);
+  nsresult rv = aBlob.GetSize(&blobSize);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   JS::Rooted<JSObject*> jsArrayBuffer(aCx, JS_NewArrayBuffer(aCx, blobSize));
   if (!jsArrayBuffer) {
     // XXXkhuey we need a way to indicate to the bindings that the call failed
@@ -78,17 +72,17 @@ FileReaderSync::ReadAsArrayBuffer(JSCont
   uint32_t bufferLength = JS_GetArrayBufferByteLength(jsArrayBuffer);
   uint8_t* arrayBuffer = JS_GetStableArrayBufferData(aCx, jsArrayBuffer);
   if (!arrayBuffer) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   nsCOMPtr<nsIInputStream> stream;
-  rv = blob->GetInternalStream(getter_AddRefs(stream));
+  rv = aBlob.GetInternalStream(getter_AddRefs(stream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   uint32_t numRead;
   rv = stream->Read((char*)arrayBuffer, bufferLength, &numRead);
   if (NS_FAILED(rv)) {
@@ -96,28 +90,22 @@ FileReaderSync::ReadAsArrayBuffer(JSCont
     return;
   }
   NS_ASSERTION(numRead == bufferLength, "failed to read data");
 
   aRetval.set(jsArrayBuffer);
 }
 
 void
-FileReaderSync::ReadAsBinaryString(JS::Handle<JSObject*> aBlob,
+FileReaderSync::ReadAsBinaryString(DOMFile& aBlob,
                                    nsAString& aResult,
                                    ErrorResult& aRv)
 {
-  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
-  if (!blob) {
-    aRv.Throw(NS_ERROR_INVALID_ARG);
-    return;
-  }
-
   nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = blob->GetInternalStream(getter_AddRefs(stream));
+  nsresult rv = aBlob.GetInternalStream(getter_AddRefs(stream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   uint32_t numRead;
   do {
     char readBuf[4096];
@@ -132,29 +120,23 @@ FileReaderSync::ReadAsBinaryString(JS::H
     if (aResult.Length() - oldLength != numRead) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return;
     }
   } while (numRead > 0);
 }
 
 void
-FileReaderSync::ReadAsText(JS::Handle<JSObject*> aBlob,
+FileReaderSync::ReadAsText(DOMFile& aBlob,
                            const Optional<nsAString>& aEncoding,
                            nsAString& aResult,
                            ErrorResult& aRv)
 {
-  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
-  if (!blob) {
-    aRv.Throw(NS_ERROR_INVALID_ARG);
-    return;
-  }
-
   nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = blob->GetInternalStream(getter_AddRefs(stream));
+  nsresult rv = aBlob.GetInternalStream(getter_AddRefs(stream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   nsAutoCString encoding;
   unsigned char sniffBuf[3] = { 0, 0, 0 };
   uint32_t numRead;
@@ -169,17 +151,17 @@ FileReaderSync::ReadAsText(JS::Handle<JS
   // Standard, which the File API references.
   if (!nsContentUtils::CheckForBOM(sniffBuf, numRead, encoding)) {
     // BOM sniffing failed. Try the API argument.
     if (!aEncoding.WasPassed() ||
         !EncodingUtils::FindEncodingForLabel(aEncoding.Value(),
                                              encoding)) {
       // API argument failed. Try the type property of the blob.
       nsAutoString type16;
-      blob->GetType(type16);
+      aBlob.GetType(type16);
       NS_ConvertUTF16toUTF8 type(type16);
       nsAutoCString specifiedCharset;
       bool haveCharset;
       int32_t charsetStart, charsetEnd;
       NS_ExtractCharsetFromContentType(type,
                                        specifiedCharset,
                                        &haveCharset,
                                        &charsetStart,
@@ -208,47 +190,41 @@ FileReaderSync::ReadAsText(JS::Handle<JS
   rv = ConvertStream(stream, encoding.get(), aResult);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 }
 
 void
-FileReaderSync::ReadAsDataURL(JS::Handle<JSObject*> aBlob, nsAString& aResult,
+FileReaderSync::ReadAsDataURL(DOMFile& aBlob, nsAString& aResult,
                               ErrorResult& aRv)
 {
-  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
-  if (!blob) {
-    aRv.Throw(NS_ERROR_INVALID_ARG);
-    return;
-  }
-
   nsAutoString scratchResult;
   scratchResult.AssignLiteral("data:");
 
   nsString contentType;
-  blob->GetType(contentType);
+  aBlob.GetType(contentType);
 
   if (contentType.IsEmpty()) {
     scratchResult.AppendLiteral("application/octet-stream");
   } else {
     scratchResult.Append(contentType);
   }
   scratchResult.AppendLiteral(";base64,");
 
   nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = blob->GetInternalStream(getter_AddRefs(stream));
+  nsresult rv = aBlob.GetInternalStream(getter_AddRefs(stream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   uint64_t size;
-  rv = blob->GetSize(&size);
+  rv = aBlob.GetSize(&size);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   nsCOMPtr<nsIInputStream> bufferedStream;
   rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), stream, size);
   if (NS_FAILED(rv)) {
--- a/dom/workers/FileReaderSync.h
+++ b/dom/workers/FileReaderSync.h
@@ -11,16 +11,17 @@
 
 class nsIInputStream;
 class nsIDOMBlob;
 
 namespace mozilla {
 class ErrorResult;
 
 namespace dom {
+class DOMFile;
 class GlobalObject;
 template<typename> class Optional;
 }
 }
 
 BEGIN_WORKERS_NAMESPACE
 
 class FileReaderSync MOZ_FINAL
@@ -38,23 +39,19 @@ private:
 
 public:
   static already_AddRefed<FileReaderSync>
   Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
 
   JSObject* WrapObject(JSContext* aCx);
 
   void ReadAsArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aScopeObj,
-                         JS::Handle<JSObject*> aBlob,
-                         JS::MutableHandle<JSObject*> aRetval,
+                         DOMFile& aBlob, JS::MutableHandle<JSObject*> aRetval,
                          ErrorResult& aRv);
-  void ReadAsBinaryString(JS::Handle<JSObject*> aBlob, nsAString& aResult,
-                          ErrorResult& aRv);
-  void ReadAsText(JS::Handle<JSObject*> aBlob,
-                  const Optional<nsAString>& aEncoding,
+  void ReadAsBinaryString(DOMFile& aBlob, nsAString& aResult, ErrorResult& aRv);
+  void ReadAsText(DOMFile& aBlob, const Optional<nsAString>& aEncoding,
                   nsAString& aResult, ErrorResult& aRv);
-  void ReadAsDataURL(JS::Handle<JSObject*> aBlob, nsAString& aResult,
-                     ErrorResult& aRv);
+  void ReadAsDataURL(DOMFile& aBlob, nsAString& aResult, ErrorResult& aRv);
 };
 
 END_WORKERS_NAMESPACE
 
 #endif // mozilla_dom_workers_filereadersync_h__
--- a/dom/workers/RegisterBindings.cpp
+++ b/dom/workers/RegisterBindings.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WorkerPrivate.h"
 #include "ChromeWorkerScope.h"
-#include "File.h"
 #include "RuntimeService.h"
 
 #include "jsapi.h"
 #include "js/OldDebugAPI.h"
 #include "mozilla/dom/RegisterWorkerBindings.h"
 #include "mozilla/OSFileConstants.h"
 
 USING_WORKERS_NAMESPACE
@@ -26,19 +25,14 @@ WorkerPrivate::RegisterBindings(JSContex
 
   if (IsChromeWorker()) {
     if (!DefineChromeWorkerFunctions(aCx, aGlobal) ||
         !DefineOSFileConstants(aCx, aGlobal)) {
       return false;
     }
   }
 
-  // Init other classes we care about.
-  if (!file::InitClasses(aCx, aGlobal)) {
-    return false;
-  }
-
   if (!JS_DefineProfilingFunctions(aCx, aGlobal)) {
     return false;
   }
 
   return true;
 }
--- a/dom/workers/URL.cpp
+++ b/dom/workers/URL.cpp
@@ -14,17 +14,16 @@
 #include "mozilla/dom/URLBinding.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "nsGlobalWindow.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsNetCID.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 
-#include "File.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 
 BEGIN_WORKERS_NAMESPACE
 using mozilla::dom::GlobalObject;
 
 class URLProxy MOZ_FINAL
 {
@@ -843,50 +842,42 @@ URL::SetHash(const nsAString& aHash, Err
 }
 
 // static
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal, JSObject* aBlob,
                      const mozilla::dom::objectURLOptions& aOptions,
                      nsString& aResult, mozilla::ErrorResult& aRv)
 {
+  SetDOMStringToNull(aResult);
+
+  NS_NAMED_LITERAL_STRING(argStr, "Argument 1 of URL.createObjectURL");
+  NS_NAMED_LITERAL_STRING(blobStr, "MediaStream");
+  aRv.ThrowTypeError(MSG_DOES_NOT_IMPLEMENT_INTERFACE, &argStr, &blobStr);
+}
+
+// static
+void
+URL::CreateObjectURL(const GlobalObject& aGlobal, DOMFile& aBlob,
+                     const mozilla::dom::objectURLOptions& aOptions,
+                     nsString& aResult, mozilla::ErrorResult& aRv)
+{
   JSContext* cx = aGlobal.Context();
   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
 
-  nsCOMPtr<nsIDOMBlob> blob = file::GetDOMBlobFromJSObject(aBlob);
-  if (!blob) {
-    SetDOMStringToNull(aResult);
-
-    NS_NAMED_LITERAL_STRING(argStr, "Argument 1 of URL.createObjectURL");
-    NS_NAMED_LITERAL_STRING(blobStr, "Blob");
-    aRv.ThrowTypeError(MSG_DOES_NOT_IMPLEMENT_INTERFACE, &argStr, &blobStr);
-    return;
-  }
-
-  DOMFile* domBlob = static_cast<DOMFile*>(blob.get());
-
   nsRefPtr<CreateURLRunnable> runnable =
-    new CreateURLRunnable(workerPrivate, domBlob->Impl(), aOptions, aResult);
+    new CreateURLRunnable(workerPrivate, aBlob.Impl(), aOptions, aResult);
 
   if (!runnable->Dispatch(cx)) {
     JS_ReportPendingException(cx);
   }
 }
 
 // static
 void
-URL::CreateObjectURL(const GlobalObject& aGlobal, JSObject& aBlob,
-                     const mozilla::dom::objectURLOptions& aOptions,
-                     nsString& aResult, mozilla::ErrorResult& aRv)
-{
-  return CreateObjectURL(aGlobal, &aBlob, aOptions, aResult, aRv);
-}
-
-// static
-void
 URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl)
 {
   JSContext* cx = aGlobal.Context();
   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
 
   nsRefPtr<RevokeURLRunnable> runnable =
     new RevokeURLRunnable(workerPrivate, aUrl);
 
--- a/dom/workers/URL.h
+++ b/dom/workers/URL.h
@@ -12,16 +12,17 @@
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/URLSearchParams.h"
 
 class nsIPrincipal;
 
 namespace mozilla {
 namespace dom {
+class DOMFile;
 struct objectURLOptions;
 }
 }
 
 BEGIN_WORKERS_NAMESPACE
 
 class URLProxy;
 
@@ -58,17 +59,17 @@ public:
 
   static void
   CreateObjectURL(const GlobalObject& aGlobal,
                   JSObject* aArg, const objectURLOptions& aOptions,
                   nsString& aResult, ErrorResult& aRv);
 
   static void
   CreateObjectURL(const GlobalObject& aGlobal,
-                  JSObject& aArg, const objectURLOptions& aOptions,
+                  DOMFile& aArg, const objectURLOptions& aOptions,
                   nsString& aResult, ErrorResult& aRv);
 
   static void
   RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl);
 
   void GetHref(nsString& aHref, ErrorResult& aRv) const;
 
   void SetHref(const nsAString& aHref, ErrorResult& aRv);
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -35,16 +35,17 @@
 #include "js/OldDebugAPI.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Likely.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ImageDataBinding.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
@@ -69,17 +70,16 @@
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
 #ifdef DEBUG
 #include "nsThreadManager.h"
 #endif
 
-#include "File.h"
 #include "MessagePort.h"
 #include "Navigator.h"
 #include "Principal.h"
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "ServiceWorkerManager.h"
 #include "SharedWorker.h"
 #include "WorkerFeature.h"
@@ -294,44 +294,18 @@ LogErrorToConsole(const nsAString& aMess
 struct WorkerStructuredCloneCallbacks
 {
   static JSObject*
   Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
        uint32_t aData, void* aClosure)
   {
     JS::Rooted<JSObject*> result(aCx);
 
-    // See if object is a nsIDOMFile pointer.
-    if (aTag == DOMWORKER_SCTAG_FILE) {
-      MOZ_ASSERT(!aData);
-
-      DOMFileImpl* fileImpl;
-      if (JS_ReadBytes(aReader, &fileImpl, sizeof(fileImpl))) {
-        MOZ_ASSERT(fileImpl);
-
-#ifdef DEBUG
-        {
-          // File should not be mutable.
-          bool isMutable;
-          NS_ASSERTION(NS_SUCCEEDED(fileImpl->GetMutable(&isMutable)) &&
-                       !isMutable,
-                       "Only immutable file should be passed to worker");
-        }
-#endif
-
-        {
-          // New scope to protect |result| from a moving GC during ~nsRefPtr.
-          nsRefPtr<DOMFile> file = new DOMFile(fileImpl);
-          result = file::CreateFile(aCx, file);
-        }
-        return result;
-      }
-    }
     // See if object is a nsIDOMBlob pointer.
-    else if (aTag == DOMWORKER_SCTAG_BLOB) {
+    if (aTag == DOMWORKER_SCTAG_BLOB) {
       MOZ_ASSERT(!aData);
 
       DOMFileImpl* blobImpl;
       if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) {
         MOZ_ASSERT(blobImpl);
 
 #ifdef DEBUG
         {
@@ -340,19 +314,23 @@ struct WorkerStructuredCloneCallbacks
           NS_ASSERTION(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)) &&
                        !isMutable,
                        "Only immutable blob should be passed to worker");
         }
 #endif
 
         {
           // New scope to protect |result| from a moving GC during ~nsRefPtr.
-          nsRefPtr<DOMFile> blob = new DOMFile(blobImpl);
-          result = file::CreateBlob(aCx, blob);
+          nsRefPtr<DOMFile> blob = new DOMFile(nullptr, blobImpl);
+          JS::Rooted<JS::Value> val(aCx);
+          if (WrapNewBindingObject(aCx, blob, &val)) {
+            result = val.toObjectOrNull();
+          }
         }
+
         return result;
       }
     }
     // See if the object is an ImageData.
     else if (aTag == SCTAG_DOM_IMAGEDATA) {
       MOZ_ASSERT(!aData);
       return ReadStructuredCloneImageData(aCx, aReader);
     }
@@ -366,34 +344,21 @@ struct WorkerStructuredCloneCallbacks
         JS::Handle<JSObject*> aObj, void* aClosure)
   {
     NS_ASSERTION(aClosure, "Null pointer!");
 
     // We'll stash any nsISupports pointers that need to be AddRef'd here.
     nsTArray<nsCOMPtr<nsISupports> >* clonedObjects =
       static_cast<nsTArray<nsCOMPtr<nsISupports> >*>(aClosure);
 
-    // See if this is a File object.
+    // See if this is a Blob/File object.
     {
-      nsIDOMFile* file = file::GetDOMFileFromJSObject(aObj);
-      if (file) {
-        DOMFileImpl* fileImpl = static_cast<DOMFile*>(file)->Impl();
-        if (JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_FILE, 0) &&
-            JS_WriteBytes(aWriter, &fileImpl, sizeof(fileImpl))) {
-          clonedObjects->AppendElement(fileImpl);
-          return true;
-        }
-      }
-    }
-
-    // See if this is a Blob object.
-    {
-      nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aObj);
-      if (blob) {
-        DOMFileImpl* blobImpl = static_cast<DOMFile*>(blob)->Impl();
+      DOMFile* blob = nullptr;
+      if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
+        DOMFileImpl* blobImpl = blob->Impl();
         if (blobImpl && NS_SUCCEEDED(blobImpl->SetMutable(false)) &&
             JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0) &&
             JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl))) {
           clonedObjects->AppendElement(blobImpl);
           return true;
         }
       }
     }
@@ -429,82 +394,48 @@ JSStructuredCloneCallbacks gWorkerStruct
 struct MainThreadWorkerStructuredCloneCallbacks
 {
   static JSObject*
   Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
        uint32_t aData, void* aClosure)
   {
     AssertIsOnMainThread();
 
-    // See if object is a nsIDOMFile pointer.
-    if (aTag == DOMWORKER_SCTAG_FILE) {
-      MOZ_ASSERT(!aData);
-
-      DOMFileImpl* fileImpl;
-      if (JS_ReadBytes(aReader, &fileImpl, sizeof(fileImpl))) {
-        MOZ_ASSERT(fileImpl);
-
-#ifdef DEBUG
-        {
-          // File should not be mutable.
-          bool isMutable;
-          NS_ASSERTION(NS_SUCCEEDED(fileImpl->GetMutable(&isMutable)) &&
-                       !isMutable,
-                       "Only immutable file should be passed to worker");
-        }
-#endif
-
-        nsCOMPtr<nsIDOMFile> file = new DOMFile(fileImpl);
-
-        // nsIDOMFiles should be threadsafe, thus we will use the same instance
-        // on the main thread.
-        JS::Rooted<JS::Value> wrappedFile(aCx);
-        nsresult rv = nsContentUtils::WrapNative(aCx, file,
-                                                 &NS_GET_IID(nsIDOMFile),