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 233721 6238ff5d3ed0cdc42ec39ec772a1ffd705ed7846
parent 233720 c28b84a34465f2b870f4bef8dae364e6ae7efc01
child 233722 e087289ccfbb9db1a0b471b6baa665810d95edaf
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, bkelly, bholley
bugs1047483
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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,