Bug 1159401 - patch 1 - Split Blob and File in 2 classes, r=bz
☠☠ backed out by 49678aa590e2 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 11 May 2015 15:20:06 +0100
changeset 274142 96a3ebfe09d801bbc47206d31e10b8e470faa333
parent 274141 68d13dd7ae733389a41d0276a3c0c8f87b0ebb5b
child 274143 4287533203fb5c458e8b6281013a97dd1d421295
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1159401
milestone40.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 1159401 - patch 1 - Split Blob and File in 2 classes, r=bz
dom/archivereader/ArchiveEvent.cpp
dom/archivereader/ArchiveEvent.h
dom/archivereader/ArchiveReader.cpp
dom/archivereader/ArchiveReader.h
dom/archivereader/ArchiveRequest.cpp
dom/archivereader/ArchiveRequest.h
dom/archivereader/ArchiveZipEvent.cpp
dom/archivereader/ArchiveZipEvent.h
dom/base/BlobSet.h
dom/base/Console.cpp
dom/base/File.cpp
dom/base/File.h
dom/base/ImageEncoder.cpp
dom/base/ImageEncoder.h
dom/base/MessagePort.cpp
dom/base/MultipartFileImpl.cpp
dom/base/MultipartFileImpl.h
dom/base/Navigator.cpp
dom/base/URL.cpp
dom/base/URL.h
dom/base/WebSocket.cpp
dom/base/WebSocket.h
dom/base/nsContentUtils.cpp
dom/base/nsDOMDataChannel.cpp
dom/base/nsDOMDataChannel.h
dom/base/nsDOMFileReader.cpp
dom/base/nsDOMFileReader.h
dom/base/nsFormData.cpp
dom/base/nsFormData.h
dom/base/nsFrameMessageManager.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsXMLHttpRequest.cpp
dom/base/nsXMLHttpRequest.h
dom/bindings/Bindings.conf
dom/broadcastchannel/BroadcastChannel.cpp
dom/broadcastchannel/BroadcastChannelChild.cpp
dom/camera/DOMCameraControl.cpp
dom/camera/DOMCameraControlListener.cpp
dom/devicestorage/DeviceStorage.h
dom/devicestorage/DeviceStorageRequestChild.cpp
dom/devicestorage/DeviceStorageRequestParent.cpp
dom/devicestorage/nsDeviceStorage.cpp
dom/devicestorage/nsDeviceStorage.h
dom/events/DataTransfer.cpp
dom/fetch/Fetch.cpp
dom/filehandle/FileHandle.cpp
dom/filehandle/FileHandle.h
dom/filesystem/CreateFileTask.cpp
dom/filesystem/CreateFileTask.h
dom/filesystem/Directory.cpp
dom/filesystem/FileSystemTaskBase.cpp
dom/filesystem/FileSystemTaskBase.h
dom/filesystem/GetFileOrDirectoryTask.cpp
dom/filesystem/RemoveTask.cpp
dom/html/HTMLCanvasElement.cpp
dom/html/HTMLInputElement.cpp
dom/html/nsFormSubmission.cpp
dom/html/nsFormSubmission.h
dom/indexedDB/ActorsChild.cpp
dom/indexedDB/ActorsParent.cpp
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBDatabase.h
dom/indexedDB/IDBMutableFile.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IndexedDatabase.h
dom/indexedDB/IndexedDatabaseInlines.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/media/EncodedBufferCache.cpp
dom/media/EncodedBufferCache.h
dom/media/MediaRecorder.cpp
dom/media/imagecapture/CaptureTask.cpp
dom/media/imagecapture/CaptureTask.h
dom/media/imagecapture/ImageCapture.cpp
dom/media/imagecapture/ImageCapture.h
dom/mobilemessage/MmsMessage.cpp
dom/mobilemessage/MmsMessage.h
dom/mobilemessage/ipc/SmsParent.cpp
dom/network/UDPSocket.cpp
dom/workers/FileReaderSync.cpp
dom/workers/FileReaderSync.h
dom/workers/ServiceWorkerEvents.cpp
dom/workers/ServiceWorkerEvents.h
dom/workers/URL.cpp
dom/workers/URL.h
dom/workers/WorkerPrivate.cpp
dom/workers/XMLHttpRequest.cpp
dom/workers/XMLHttpRequest.h
ipc/glue/BackgroundImpl.cpp
js/xpconnect/src/ExportHelpers.cpp
widget/nsFilePickerProxy.cpp
--- a/dom/archivereader/ArchiveEvent.cpp
+++ b/dom/archivereader/ArchiveEvent.cpp
@@ -100,17 +100,17 @@ ArchiveReaderEvent::RunShare(nsresult aS
   NS_DispatchToMainThread(event);
 
   return NS_OK;
 }
 
 void
 ArchiveReaderEvent::ShareMainThread()
 {
-  nsTArray<nsCOMPtr<nsIDOMFile> > fileList;
+  nsTArray<nsRefPtr<File>> fileList;
 
   if (!NS_FAILED(mStatus)) {
     // This extra step must run in the main thread:
     for (uint32_t index = 0; index < mFileList.Length(); ++index) {
       nsRefPtr<ArchiveItem> item = mFileList[index];
 
       nsString tmp;
       nsresult rv = item->GetFilename(tmp);
@@ -126,17 +126,17 @@ ArchiveReaderEvent::ShareMainThread()
         // Just to be sure, if something goes wrong, the mimetype is an empty string:
         nsCString type;
         if (NS_SUCCEEDED(GetType(filename, type))) {
           item->SetType(type);
         }
       }
 
       // This is a File:
-      nsRefPtr<nsIDOMFile> file = item->File(mArchiveReader);
+      nsRefPtr<File> file = item->GetFile(mArchiveReader);
       if (file) {
         fileList.AppendElement(file);
       }
     }
   }
 
   mArchiveReader->Ready(fileList, mStatus);
 }
--- a/dom/archivereader/ArchiveEvent.h
+++ b/dom/archivereader/ArchiveEvent.h
@@ -31,17 +31,17 @@ public:
   // Getter/Setter for the type
   nsCString GetType();
   void SetType(const nsCString& aType);
 
   // Getter for the filename
   virtual nsresult GetFilename(nsString& aFilename) = 0;
 
   // Generate a File
-  virtual nsIDOMFile* File(ArchiveReader* aArchiveReader) = 0;
+  virtual already_AddRefed<File> GetFile(ArchiveReader* aArchiveReader) = 0;
 
 protected:
   virtual ~ArchiveItem();
 
   nsCString mType;
 };
 
 /**
--- a/dom/archivereader/ArchiveReader.cpp
+++ b/dom/archivereader/ArchiveReader.cpp
@@ -19,17 +19,17 @@
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 USING_ARCHIVEREADER_NAMESPACE
 
 /* static */ already_AddRefed<ArchiveReader>
 ArchiveReader::Constructor(const GlobalObject& aGlobal,
-                           File& aBlob,
+                           Blob& aBlob,
                            const ArchiveReaderOptions& aOptions,
                            ErrorResult& aError)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aError.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
@@ -41,17 +41,17 @@ ArchiveReader::Constructor(const GlobalO
     return nullptr;
   }
 
   nsRefPtr<ArchiveReader> reader =
     new ArchiveReader(aBlob, window, encoding);
   return reader.forget();
 }
 
-ArchiveReader::ArchiveReader(File& aBlob, nsPIDOMWindow* aWindow,
+ArchiveReader::ArchiveReader(Blob& aBlob, nsPIDOMWindow* aWindow,
                              const nsACString& aEncoding)
   : mFileImpl(aBlob.Impl())
   , mWindow(aWindow)
   , mStatus(NOT_STARTED)
   , mEncoding(aEncoding)
 {
   MOZ_ASSERT(aWindow);
 }
@@ -131,17 +131,17 @@ ArchiveReader::OpenArchive()
   // we increase the refcount here:
   AddRef();
 
   return NS_OK;
 }
 
 // Data received from the dispatched event:
 void
-ArchiveReader::Ready(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
+ArchiveReader::Ready(nsTArray<nsRefPtr<File>>& aFileList,
                      nsresult aStatus)
 {
   mStatus = READY;
  
   // Let's store the values:
   mData.fileList = aFileList;
   mData.status = aStatus;
 
--- a/dom/archivereader/ArchiveReader.h
+++ b/dom/archivereader/ArchiveReader.h
@@ -8,22 +8,22 @@
 #define mozilla_dom_archivereader_domarchivereader_h__
 
 #include "nsWrapperCache.h"
 
 #include "ArchiveReaderCommon.h"
 
 #include "nsCOMArray.h"
 #include "nsIChannel.h"
-#include "nsIDOMFile.h"
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
 namespace dom {
 struct ArchiveReaderOptions;
+class Blob;
 class File;
 class FileImpl;
 class GlobalObject;
 } // namespace dom
 } // namespace mozilla
 
 BEGIN_ARCHIVEREADER_NAMESPACE
 
@@ -35,20 +35,20 @@ class ArchiveRequest;
 class ArchiveReader 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, File& aBlob,
+  Constructor(const GlobalObject& aGlobal, Blob& aBlob,
               const ArchiveReaderOptions& aOptions, ErrorResult& aError);
 
-  ArchiveReader(File& aBlob, nsPIDOMWindow* aWindow,
+  ArchiveReader(Blob& aBlob, nsPIDOMWindow* aWindow,
                 const nsACString& aEncoding);
 
   nsIDOMWindow* GetParentObject() const
   {
     return mWindow;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -64,18 +64,17 @@ public: // for the ArchiveRequest:
   nsresult RegisterRequest(ArchiveRequest* aRequest);
 
 public: // For events:
   FileImpl* GetFileImpl() const
   {
     return mFileImpl;
   }
 
-  void Ready(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
-             nsresult aStatus);
+  void Ready(nsTArray<nsRefPtr<File>>& aFileList, nsresult aStatus);
 
 private:
   ~ArchiveReader();
 
   already_AddRefed<ArchiveRequest> GenerateArchiveRequest();
 
   nsresult OpenArchive();
 
@@ -103,17 +102,17 @@ protected:
     Search  // ... if the data length is unknown (== 0) we wait until we read a new header 
   } mReadStatus;
 
   // List of requests to be processed
   nsTArray<nsRefPtr<ArchiveRequest> > mRequests;
 
   // Everything related to the blobs and the status:
   struct {
-    nsTArray<nsCOMPtr<nsIDOMFile> > fileList;
+    nsTArray<nsRefPtr<File>> fileList;
     nsresult status;
   } mData;
 
   nsCString mEncoding;
 };
 
 END_ARCHIVEREADER_NAMESPACE
 
--- a/dom/archivereader/ArchiveRequest.cpp
+++ b/dom/archivereader/ArchiveRequest.cpp
@@ -117,17 +117,17 @@ ArchiveRequest::OpGetFile(const nsAStrin
 
 void
 ArchiveRequest::OpGetFiles()
 {
   mOperation = GetFiles;
 }
 
 nsresult
-ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
+ArchiveRequest::ReaderReady(nsTArray<nsRefPtr<File>>& aFileList,
                             nsresult aStatus)
 {
   if (NS_FAILED(aStatus)) {
     FireError(aStatus);
     return NS_OK;
   }
 
   nsresult rv;
@@ -169,28 +169,28 @@ ArchiveRequest::ReaderReady(nsTArray<nsC
   }
 
   return NS_OK;
 }
 
 nsresult
 ArchiveRequest::GetFilenamesResult(JSContext* aCx,
                                    JS::Value* aValue,
-                                   nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
+                                   nsTArray<nsRefPtr<File>>& aFileList)
 {
   JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aFileList.Length()));
   nsresult rv;
 
   if (!array) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   JS::Rooted<JSString*> str(aCx);
   for (uint32_t i = 0; i < aFileList.Length(); ++i) {
-    nsCOMPtr<nsIDOMFile> file = aFileList[i];
+    nsRefPtr<File> file = aFileList[i];
 
     nsString filename;
     rv = file->GetName(filename);
     NS_ENSURE_SUCCESS(rv, rv);
 
     str = JS_NewUCStringCopyZ(aCx, filename.get());
     NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
 
@@ -206,52 +206,56 @@ ArchiveRequest::GetFilenamesResult(JSCon
 
   *aValue = OBJECT_TO_JSVAL(array);
   return NS_OK;
 }
 
 nsresult
 ArchiveRequest::GetFileResult(JSContext* aCx,
                               JS::MutableHandle<JS::Value> aValue,
-                              nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
+                              nsTArray<nsRefPtr<File>>& aFileList)
 {
   for (uint32_t i = 0; i < aFileList.Length(); ++i) {
-    nsCOMPtr<nsIDOMFile> file = aFileList[i];
+    nsRefPtr<File> file = aFileList[i];
 
     nsString filename;
     nsresult rv = file->GetName(filename);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (filename == mFilename) {
-      return nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile),
-                                        aValue);
+      if (!ToJSValue(aCx, file, aValue)) {
+        return NS_ERROR_FAILURE;
+      }
+
+      return NS_OK;
     }
   }
 
   return NS_ERROR_FAILURE;
 }
 
 nsresult
 ArchiveRequest::GetFilesResult(JSContext* aCx,
                                JS::MutableHandle<JS::Value> aValue,
-                               nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
+                               nsTArray<nsRefPtr<File>>& aFileList)
 {
   JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aFileList.Length()));
   if (!array) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   for (uint32_t i = 0; i < aFileList.Length(); ++i) {
-    nsCOMPtr<nsIDOMFile> file = aFileList[i];
+    nsRefPtr<File> file = aFileList[i];
 
     JS::Rooted<JS::Value> value(aCx);
-    nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile),
-                                             &value);
-    if (NS_FAILED(rv) ||
-        !JS_DefineElement(aCx, array, i, value, JSPROP_ENUMERATE)) {
+    if (!ToJSValue(aCx, file, &value)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    if (!JS_DefineElement(aCx, array, i, value, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   aValue.setObject(*array);
   return NS_OK;
 }
 
--- a/dom/archivereader/ArchiveRequest.h
+++ b/dom/archivereader/ArchiveRequest.h
@@ -44,35 +44,34 @@ public:
   // This is called by the DOMArchiveRequestEvent
   void Run();
 
   // Set the types for this request
   void OpGetFilenames();
   void OpGetFile(const nsAString& aFilename);
   void OpGetFiles();
 
-  nsresult ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
-                       nsresult aStatus);
+  nsresult ReaderReady(nsTArray<nsRefPtr<File>>& aFileList, nsresult aStatus);
 
 public: // static
   static already_AddRefed<ArchiveRequest> Create(nsPIDOMWindow* aOwner,
                                                  ArchiveReader* aReader);
 
 private:
   ~ArchiveRequest();
 
   nsresult GetFilenamesResult(JSContext* aCx,
                               JS::Value* aValue,
-                              nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
+                              nsTArray<nsRefPtr<File>>& aFileList);
   nsresult GetFileResult(JSContext* aCx,
                          JS::MutableHandle<JS::Value> aValue,
-                         nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
+                         nsTArray<nsRefPtr<File>>& aFileList);
   nsresult GetFilesResult(JSContext* aCx,
                           JS::MutableHandle<JS::Value> aValue,
-                          nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
+                          nsTArray<nsRefPtr<File>>& aFileList);
 
 protected:
   // The reader:
   nsRefPtr<ArchiveReader> mArchiveReader;
 
   // The operation:
   enum {
     GetFilenames,
--- a/dom/archivereader/ArchiveZipEvent.cpp
+++ b/dom/archivereader/ArchiveZipEvent.cpp
@@ -70,30 +70,32 @@ ArchiveZipItem::GetFilename(nsString& aF
     }
   }
 
   aFilename = mFilenameU;
   return NS_OK;
 }
 
 // From zipItem to File:
-nsIDOMFile*
-ArchiveZipItem::File(ArchiveReader* aArchiveReader)
+already_AddRefed<File>
+ArchiveZipItem::GetFile(ArchiveReader* aArchiveReader)
 {
   nsString filename;
 
   if (NS_FAILED(GetFilename(filename))) {
     return nullptr;
   }
 
-  return new dom::File(aArchiveReader,
+  nsRefPtr<dom::File> file = dom::File::Create(aArchiveReader,
     new ArchiveZipFileImpl(filename,
                            NS_ConvertUTF8toUTF16(GetType()),
                            StrToInt32(mCentralStruct.orglen),
                            mCentralStruct, aArchiveReader->GetFileImpl()));
+  MOZ_ASSERT(file);
+  return file.forget();
 }
 
 uint32_t
 ArchiveZipItem::StrToInt32(const uint8_t* aStr)
 {
   return (uint32_t)( (aStr [0] <<  0) |
                      (aStr [1] <<  8) |
                      (aStr [2] << 16) |
--- a/dom/archivereader/ArchiveZipEvent.h
+++ b/dom/archivereader/ArchiveZipEvent.h
@@ -26,17 +26,18 @@ public:
                  const nsACString& aEncoding);
 protected:
   virtual ~ArchiveZipItem();
 
 public:
   nsresult GetFilename(nsString& aFilename) override;
 
   // From zipItem to File:
-  virtual nsIDOMFile* File(ArchiveReader* aArchiveReader) override;
+  virtual already_AddRefed<File>
+  GetFile(ArchiveReader* aArchiveReader) override;
 
 public: // for the event
   static uint32_t StrToInt32(const uint8_t* aStr);
   static uint16_t StrToInt16(const uint8_t* aStr);
 
 private:
   nsresult ConvertFilename();
 
--- a/dom/base/BlobSet.h
+++ b/dom/base/BlobSet.h
@@ -26,17 +26,17 @@ public:
 
   nsresult AppendVoidPtr(const void* aData, uint32_t aLength);
   nsresult AppendString(const nsAString& aString, bool nativeEOL, JSContext* aCx);
   nsresult AppendBlobImpl(FileImpl* aBlobImpl);
   nsresult AppendBlobImpls(const nsTArray<nsRefPtr<FileImpl>>& aBlobImpls);
 
   nsTArray<nsRefPtr<FileImpl>>& GetBlobImpls() { Flush(); return mBlobImpls; }
 
-  already_AddRefed<File> GetBlobInternal(nsISupports* aParent,
+  already_AddRefed<Blob> GetBlobInternal(nsISupports* aParent,
                                          const nsACString& aContentType);
 
 protected:
   bool ExpandBufferSize(uint64_t aSize)
   {
     using mozilla::CheckedUint32;
 
     if (mDataBufferLen >= mDataLen + aSize) {
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -83,19 +83,19 @@ ConsoleStructuredCloneCallbacksRead(JSCo
     static_cast<ConsoleStructuredCloneData*>(aClosure);
   MOZ_ASSERT(data);
 
   if (aTag == CONSOLE_TAG_BLOB) {
     MOZ_ASSERT(data->mFiles.Length() > aIndex);
 
     JS::Rooted<JS::Value> val(aCx);
     {
-      nsRefPtr<File> file =
-        new File(data->mParent, data->mFiles.ElementAt(aIndex));
-      if (!GetOrCreateDOMReflector(aCx, file, &val)) {
+      nsRefPtr<Blob> blob =
+        Blob::Create(data->mParent, data->mFiles.ElementAt(aIndex));
+      if (!ToJSValue(aCx, blob, &val)) {
         return nullptr;
       }
     }
 
     return &val.toObject();
   }
 
   MOZ_CRASH("No other tags are supported.");
@@ -109,24 +109,24 @@ ConsoleStructuredCloneCallbacksWrite(JSC
                                      JSStructuredCloneWriter* aWriter,
                                      JS::Handle<JSObject*> aObj,
                                      void* aClosure)
 {
   ConsoleStructuredCloneData* data =
     static_cast<ConsoleStructuredCloneData*>(aClosure);
   MOZ_ASSERT(data);
 
-  nsRefPtr<File> file;
-  if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, file)) &&
-      file->Impl()->MayBeClonedToOtherThreads()) {
+  nsRefPtr<Blob> blob;
+  if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
+      blob->Impl()->MayBeClonedToOtherThreads()) {
     if (!JS_WriteUint32Pair(aWriter, CONSOLE_TAG_BLOB, data->mFiles.Length())) {
       return false;
     }
 
-    data->mFiles.AppendElement(file->Impl());
+    data->mFiles.AppendElement(blob->Impl());
     return true;
   }
 
   JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aObj));
   JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
   if (!jsString) {
     return false;
   }
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -119,49 +119,361 @@ nsresult DataOwnerAdapter::Create(DataOw
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ADDREF(*_retval = new DataOwnerAdapter(aDataOwner, stream));
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// mozilla::dom::File implementation
+// mozilla::dom::Blob implementation
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(File)
+NS_IMPL_CYCLE_COLLECTION_CLASS(Blob)
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(File)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Blob)
   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(File)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Blob)
   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(File)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Blob)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(File)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Blob)
   // 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_AMBIGUOUS(nsISupports, nsIDOMBlob)
   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(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(File)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(File)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(Blob)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(Blob)
+
+/* static */ Blob*
+Blob::Create(nsISupports* aParent, FileImpl* aImpl)
+{
+  MOZ_ASSERT(aImpl);
+
+  return aImpl->IsFile() ? new File(aParent, aImpl)
+                         : new Blob(aParent, aImpl);
+}
+
+/* static */ already_AddRefed<Blob>
+Blob::Create(nsISupports* aParent, const nsAString& aContentType,
+             uint64_t aLength)
+{
+  nsRefPtr<Blob> blob = Blob::Create(aParent,
+    new FileImplBase(aContentType, aLength));
+  MOZ_ASSERT(!blob->mImpl->IsFile());
+  return blob.forget();
+}
+
+/* static */ already_AddRefed<Blob>
+Blob::Create(nsISupports* aParent, const nsAString& aContentType,
+             uint64_t aStart, uint64_t aLength)
+{
+  nsRefPtr<Blob> blob = Blob::Create(aParent,
+    new FileImplBase(aContentType, aStart, aLength));
+  MOZ_ASSERT(!blob->mImpl->IsFile());
+  return blob.forget();
+}
+
+/* static */ already_AddRefed<Blob>
+Blob::CreateMemoryBlob(nsISupports* aParent, void* aMemoryBuffer,
+                       uint64_t aLength, const nsAString& aContentType)
+{
+  nsRefPtr<Blob> blob = Blob::Create(aParent,
+    new FileImplMemory(aMemoryBuffer, aLength, aContentType));
+  MOZ_ASSERT(!blob->mImpl->IsFile());
+  return blob.forget();
+}
+
+/* static */ already_AddRefed<Blob>
+Blob::CreateTemporaryBlob(nsISupports* aParent, PRFileDesc* aFD,
+                          uint64_t aStartPos, uint64_t aLength,
+                          const nsAString& aContentType)
+{
+  nsRefPtr<Blob> blob = Blob::Create(aParent,
+    new FileImplTemporaryBlob(aFD, aStartPos, aLength, aContentType));
+  MOZ_ASSERT(!blob->mImpl->IsFile());
+  return blob.forget();
+}
+
+Blob::Blob(nsISupports* aParent, FileImpl* aImpl)
+  : mImpl(aImpl)
+  , mParent(aParent)
+{
+  MOZ_ASSERT(mImpl);
+
+#ifdef DEBUG
+  {
+    nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aParent);
+    if (win) {
+      MOZ_ASSERT(win->IsInnerWindow());
+    }
+  }
+#endif
+}
+
+bool
+Blob::IsFile() const
+{
+  return mImpl->IsFile();
+}
+
+const nsTArray<nsRefPtr<FileImpl>>*
+Blob::GetSubBlobImpls() const
+{
+  return mImpl->GetSubBlobImpls();
+}
+
+already_AddRefed<File>
+Blob::ToFile()
+{
+  if (!mImpl->IsFile()) {
+    return nullptr;
+  }
+
+  nsRefPtr<File> file;
+  if (HasFileInterface()) {
+    file = static_cast<File*>(this);
+  } else {
+    file = new File(mParent, mImpl);
+  }
+
+  return file.forget();
+}
+
+already_AddRefed<File>
+Blob::ToFile(const nsAString& aName) const
+{
+  nsAutoTArray<nsRefPtr<FileImpl>, 1> blobImpls;
+  blobImpls.AppendElement(mImpl);
+
+  nsAutoString contentType;
+  mImpl->GetType(contentType);
+
+  nsRefPtr<MultipartFileImpl> impl =
+    new MultipartFileImpl(blobImpls, aName, contentType);
+
+  nsRefPtr<File> file = new File(mParent, impl);
+  return file.forget();
+}
+
+already_AddRefed<Blob>
+Blob::CreateSlice(uint64_t aStart, uint64_t aLength,
+                  const nsAString& aContentType,
+                  ErrorResult& aRv)
+{
+  nsRefPtr<FileImpl> impl = mImpl->CreateSlice(aStart, aLength,
+                                               aContentType, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  nsRefPtr<Blob> blob = Blob::Create(mParent, impl);
+  return blob.forget();
+}
+
+NS_IMETHODIMP
+Blob::GetSize(uint64_t* aSize)
+{
+  MOZ_ASSERT(aSize);
+
+  ErrorResult rv;
+  *aSize = GetSize(rv);
+  return rv.StealNSResult();
+}
+
+uint64_t
+Blob::GetSize(ErrorResult& aRv)
+{
+  return mImpl->GetSize(aRv);
+}
+
+NS_IMETHODIMP
+Blob::GetType(nsAString &aType)
+{
+  mImpl->GetType(aType);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Blob::Slice(int64_t aStart, int64_t aEnd,
+            const nsAString& aContentType, uint8_t aArgc,
+            nsIDOMBlob **aBlob)
+{
+  Optional<int64_t> start;
+  if (aArgc > 0) {
+    start.Construct(aStart);
+  }
+
+  Optional<int64_t> end;
+  if (aArgc > 1) {
+    end.Construct(aEnd);
+  }
+
+  ErrorResult rv;
+  nsRefPtr<Blob> blob = Slice(start, end, aContentType, rv);
+  if (rv.Failed()) {
+    return rv.StealNSResult();
+  }
+
+  blob.forget(aBlob);
+  return NS_OK;
+}
+
+already_AddRefed<Blob>
+Blob::Slice(const Optional<int64_t>& aStart,
+            const Optional<int64_t>& aEnd,
+            const nsAString& aContentType,
+            ErrorResult& aRv)
+{
+  nsRefPtr<FileImpl> impl =
+    mImpl->Slice(aStart, aEnd, aContentType, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  nsRefPtr<Blob> blob = Blob::Create(mParent, impl);
+  return blob.forget();
+}
+
+NS_IMETHODIMP
+Blob::GetSendInfo(nsIInputStream** aBody,
+                  uint64_t* aContentLength,
+                  nsACString& aContentType,
+                  nsACString& aCharset)
+{
+  return mImpl->GetSendInfo(aBody, aContentLength, aContentType, aCharset);
+}
+
+NS_IMETHODIMP
+Blob::GetMutable(bool* aMutable)
+{
+  return mImpl->GetMutable(aMutable);
+}
+
+NS_IMETHODIMP
+Blob::SetMutable(bool aMutable)
+{
+  return mImpl->SetMutable(aMutable);
+}
+
+JSObject*
+Blob::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return BlobBinding::Wrap(aCx, this, aGivenProto);
+}
+
+/* static */ already_AddRefed<Blob>
+Blob::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl();
+
+  impl->InitializeBlob();
+  MOZ_ASSERT(!impl->IsFile());
+
+  nsRefPtr<Blob> blob = Blob::Create(aGlobal.GetAsSupports(), impl);
+  return blob.forget();
+}
+
+/* static */ already_AddRefed<Blob>
+Blob::Constructor(
+        const GlobalObject& aGlobal,
+        const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+        const BlobPropertyBag& aBag,
+        ErrorResult& aRv)
+{
+  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl();
+
+  impl->InitializeBlob(aGlobal.Context(), aData, aBag.mType,
+                       aBag.mEndings == EndingTypes::Native, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+  MOZ_ASSERT(!impl->IsFile());
+
+  nsRefPtr<Blob> blob = Blob::Create(aGlobal.GetAsSupports(), impl);
+  return blob.forget();
+}
+
+NS_IMETHODIMP_(int64_t)
+Blob::GetFileId()
+{
+  return mImpl->GetFileId();
+}
+
+NS_IMETHODIMP_(void)
+Blob::AddFileInfo(indexedDB::FileInfo* aFileInfo)
+{
+  mImpl->AddFileInfo(aFileInfo);
+}
+
+indexedDB::FileInfo*
+Blob::GetFileInfo(indexedDB::FileManager* aFileManager)
+{
+  return mImpl->GetFileInfo(aFileManager);
+}
+
+NS_IMETHODIMP_(bool)
+Blob::IsMemoryFile()
+{
+  return mImpl->IsMemoryFile();
+}
+
+NS_IMETHODIMP
+Blob::GetInternalStream(nsIInputStream** aStream)
+{
+  return mImpl->GetInternalStream(aStream);
+}
+
+////////////////////////////////////////////////////////////////////////////
+// mozilla::dom::File implementation
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(File)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(File, Blob)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(File, Blob)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(File)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMFile)
+NS_INTERFACE_MAP_END_INHERITING(Blob)
+
+NS_IMPL_ADDREF_INHERITED(File, Blob)
+NS_IMPL_RELEASE_INHERITED(File, Blob)
+
+File::File(nsISupports* aParent, FileImpl* aImpl)
+  : Blob(aParent, aImpl)
+{
+  MOZ_ASSERT(aImpl->IsFile());
+}
+
+/* static */ File*
+File::Create(nsISupports* aParent, FileImpl* aImpl)
+{
+  MOZ_ASSERT(aImpl);
+  MOZ_ASSERT(aImpl->IsFile());
+
+  return new File(aParent, aImpl);
+}
 
 /* static */ already_AddRefed<File>
 File::Create(nsISupports* aParent, const nsAString& aName,
              const nsAString& aContentType, uint64_t aLength,
              int64_t aLastModifiedDate)
 {
   nsRefPtr<File> file = new File(aParent,
     new FileImplBase(aName, aContentType, aLength, aLastModifiedDate));
@@ -173,65 +485,28 @@ File::Create(nsISupports* aParent, const
              const nsAString& aContentType, uint64_t aLength)
 {
   nsRefPtr<File> file = new File(aParent,
     new FileImplBase(aName, aContentType, aLength));
   return file.forget();
 }
 
 /* static */ already_AddRefed<File>
-File::Create(nsISupports* aParent, const nsAString& aContentType,
-             uint64_t aLength)
-{
-  nsRefPtr<File> file = new File(aParent,
-    new FileImplBase(aContentType, aLength));
-  return file.forget();
-}
-
-/* static */ already_AddRefed<File>
-File::Create(nsISupports* aParent, const nsAString& aContentType,
-                uint64_t aStart, uint64_t aLength)
-{
-  nsRefPtr<File> file = new File(aParent,
-    new FileImplBase(aContentType, aStart, aLength));
-  return file.forget();
-}
-
-/* static */ already_AddRefed<File>
 File::CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer,
                        uint64_t aLength, const nsAString& aName,
                        const nsAString& aContentType,
                        int64_t aLastModifiedDate)
 {
   nsRefPtr<File> file = new File(aParent,
     new FileImplMemory(aMemoryBuffer, aLength, aName,
                        aContentType, aLastModifiedDate));
   return file.forget();
 }
 
 /* static */ already_AddRefed<File>
-File::CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer,
-                       uint64_t aLength, const nsAString& aContentType)
-{
-  nsRefPtr<File> file = new File(aParent,
-    new FileImplMemory(aMemoryBuffer, aLength, aContentType));
-  return file.forget();
-}
-
-/* static */ already_AddRefed<File>
-File::CreateTemporaryFileBlob(nsISupports* aParent, PRFileDesc* aFD,
-                              uint64_t aStartPos, uint64_t aLength,
-                              const nsAString& aContentType)
-{
-  nsRefPtr<File> file = new File(aParent,
-    new FileImplTemporaryFileBlob(aFD, aStartPos, aLength, aContentType));
-  return file.forget();
-}
-
-/* static */ already_AddRefed<File>
 File::CreateFromFile(nsISupports* aParent, nsIFile* aFile, bool aTemporary)
 {
   nsRefPtr<File> file = new File(aParent, new FileImplFile(aFile, aTemporary));
   return file.forget();
 }
 
 /* static */ already_AddRefed<File>
 File::CreateFromFile(nsISupports* aParent, const nsAString& aContentType,
@@ -267,84 +542,52 @@ File::CreateFromFile(nsISupports* aParen
 File::CreateFromFile(nsISupports* aParent, nsIFile* aFile,
                      const nsAString& aName, const nsAString& aContentType)
 {
   nsRefPtr<File> file = new File(aParent,
     new FileImplFile(aFile, aName, aContentType));
   return file.forget();
 }
 
-File::File(nsISupports* aParent, FileImpl* aImpl)
-  : mImpl(aImpl)
-  , mParent(aParent)
-{
-  MOZ_ASSERT(mImpl);
-
-#ifdef DEBUG
-  {
-    nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aParent);
-    if (win) {
-      MOZ_ASSERT(win->IsInnerWindow());
-    }
-  }
-#endif
-}
-
-const nsTArray<nsRefPtr<FileImpl>>*
-File::GetSubBlobImpls() const
-{
-  return mImpl->GetSubBlobImpls();
-}
-
-bool
-File::IsSizeUnknown() const
+JSObject*
+File::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
-  return mImpl->IsSizeUnknown();
-}
-
-bool
-File::IsDateUnknown() const
-{
-  return mImpl->IsDateUnknown();
-}
-
-bool
-File::IsFile() const
-{
-  return mImpl->IsFile();
-}
-
-already_AddRefed<File>
-File::CreateSlice(uint64_t aStart, uint64_t aLength,
-                  const nsAString& aContentType,
-                  ErrorResult& aRv)
-{
-  nsRefPtr<FileImpl> impl = mImpl->CreateSlice(aStart, aLength,
-                                               aContentType, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  nsRefPtr<File> file = new File(mParent, impl);
-  return file.forget();
+  return FileBinding::Wrap(aCx, this, aGivenProto);
 }
 
 NS_IMETHODIMP
 File::GetName(nsAString& aFileName)
 {
   mImpl->GetName(aFileName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 File::GetPath(nsAString& aPath)
 {
   return mImpl->GetPath(aPath);
 }
 
+Date
+File::GetLastModifiedDate(ErrorResult& aRv)
+{
+  int64_t value = GetLastModified(aRv);
+  if (aRv.Failed()) {
+    return Date();
+  }
+
+  return Date(value);
+}
+
+int64_t
+File::GetLastModified(ErrorResult& aRv)
+{
+  return mImpl->GetLastModified(aRv);
+}
+
 NS_IMETHODIMP
 File::GetLastModifiedDate(JSContext* aCx,
                           JS::MutableHandle<JS::Value> aDate)
 {
   ErrorResult rv;
   Date value = GetLastModifiedDate(rv);
   if (rv.Failed()) {
     return rv.StealNSResult();
@@ -352,33 +595,16 @@ File::GetLastModifiedDate(JSContext* aCx
 
   if (!value.ToDateObject(aCx, aDate)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
-Date
-File::GetLastModifiedDate(ErrorResult& aRv)
-{
-  int64_t value = GetLastModified(aRv);
-  if (aRv.Failed()) {
-    return Date();
-  }
-
-  return Date(value);
-}
-
-int64_t
-File::GetLastModified(ErrorResult& aRv)
-{
-  return mImpl->GetLastModified(aRv);
-}
-
 NS_IMETHODIMP
 File::GetMozFullPath(nsAString& aFileName)
 {
   ErrorResult rv;
   GetMozFullPath(aFileName, rv);
   return rv.StealNSResult();
 }
 
@@ -392,39 +618,16 @@ NS_IMETHODIMP
 File::GetMozFullPathInternal(nsAString& aFileName)
 {
   ErrorResult rv;
   mImpl->GetMozFullPathInternal(aFileName, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-File::GetSize(uint64_t* aSize)
-{
-  MOZ_ASSERT(aSize);
-
-  ErrorResult rv;
-  *aSize = GetSize(rv);
-  return rv.StealNSResult();
-}
-
-uint64_t
-File::GetSize(ErrorResult& aRv)
-{
-  return mImpl->GetSize(aRv);
-}
-
-NS_IMETHODIMP
-File::GetType(nsAString &aType)
-{
-  mImpl->GetType(aType);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 File::GetMozLastModifiedDate(int64_t* aDate)
 {
   MOZ_ASSERT(aDate);
 
   ErrorResult rv;
   *aDate = GetLastModified(rv);
   return rv.StealNSResult();
 }
@@ -461,147 +664,16 @@ ParseSize(int64_t aSize, int64_t& aStart
     aStart = aEnd = 0;
   }
   else {
     aStart = newStartOffset.value();
     aEnd = newEndOffset.value();
   }
 }
 
-NS_IMETHODIMP
-File::Slice(int64_t aStart, int64_t aEnd,
-            const nsAString& aContentType, uint8_t aArgc,
-            nsIDOMBlob **aBlob)
-{
-  Optional<int64_t> start;
-  if (aArgc > 0) {
-    start.Construct(aStart);
-  }
-
-  Optional<int64_t> end;
-  if (aArgc > 1) {
-    end.Construct(aEnd);
-  }
-
-  ErrorResult rv;
-  nsRefPtr<File> file = Slice(start, end, aContentType, rv);
-  if (rv.Failed()) {
-    return rv.StealNSResult();
-  }
-
-  file.forget(aBlob);
-  return NS_OK;
-}
-
-already_AddRefed<File>
-File::Slice(const Optional<int64_t>& aStart,
-            const Optional<int64_t>& aEnd,
-            const nsAString& aContentType,
-            ErrorResult& aRv)
-{
-  nsRefPtr<FileImpl> impl =
-    mImpl->Slice(aStart, aEnd, aContentType, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  nsRefPtr<File> file = new File(mParent, impl);
-  return file.forget();
-}
-
-NS_IMETHODIMP
-File::GetInternalStream(nsIInputStream** aStream)
-{
-  return mImpl->GetInternalStream(aStream);
-}
-
-NS_IMETHODIMP_(int64_t)
-File::GetFileId()
-{
-  return mImpl->GetFileId();
-}
-
-NS_IMETHODIMP_(void)
-File::AddFileInfo(indexedDB::FileInfo* aFileInfo)
-{
-  mImpl->AddFileInfo(aFileInfo);
-}
-
-indexedDB::FileInfo*
-File::GetFileInfo(indexedDB::FileManager* aFileManager)
-{
-  return mImpl->GetFileInfo(aFileManager);
-}
-
-NS_IMETHODIMP
-File::GetSendInfo(nsIInputStream** aBody,
-                  uint64_t* aContentLength,
-                  nsACString& aContentType,
-                  nsACString& aCharset)
-{
-  return mImpl->GetSendInfo(aBody, aContentLength, aContentType, aCharset);
-}
-
-NS_IMETHODIMP
-File::GetMutable(bool* aMutable)
-{
-  return mImpl->GetMutable(aMutable);
-}
-
-NS_IMETHODIMP
-File::SetMutable(bool aMutable)
-{
-  return mImpl->SetMutable(aMutable);
-}
-
-NS_IMETHODIMP_(bool)
-File::IsMemoryFile()
-{
-  return mImpl->IsMemoryFile();
-}
-
-JSObject*
-File::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
-  return IsFile() ? FileBinding::Wrap(aCx, this, aGivenProto)
-                  : BlobBinding::Wrap(aCx, this, aGivenProto);
-}
-
-/* static */ already_AddRefed<File>
-File::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
-{
-  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl();
-
-  impl->InitializeBlob();
-  MOZ_ASSERT(!impl->IsFile());
-
-  nsRefPtr<File> file = new File(aGlobal.GetAsSupports(), impl);
-  return file.forget();
-}
-
-/* static */ already_AddRefed<File>
-File::Constructor(
-        const GlobalObject& aGlobal,
-        const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
-        const BlobPropertyBag& aBag,
-        ErrorResult& aRv)
-{
-  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl();
-
-  impl->InitializeBlob(aGlobal.Context(), aData, aBag.mType,
-                       aBag.mEndings == EndingTypes::Native, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-  MOZ_ASSERT(!impl->IsFile());
-
-  nsRefPtr<File> file = new File(aGlobal.GetAsSupports(), impl);
-  return file.forget();
-}
-
 /* static */ already_AddRefed<File>
 File::Constructor(
         const GlobalObject& aGlobal,
         const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
         const nsAString& aName,
         const FilePropertyBag& aBag,
         ErrorResult& aRv)
 {
@@ -618,17 +690,17 @@ File::Constructor(
   }
 
   nsRefPtr<File> file = new File(aGlobal.GetAsSupports(), impl);
   return file.forget();
 }
 
 /* static */ already_AddRefed<File>
 File::Constructor(const GlobalObject& aGlobal,
-                  File& aData,
+                  Blob& aData,
                   const ChromeFilePropertyBag& aBag,
                   ErrorResult& aRv)
 {
   if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
@@ -1186,38 +1258,38 @@ FileImplMemory::DataOwner::EnsureMemoryR
   }
 
   RegisterStrongMemoryReporter(new FileImplMemoryDataOwnerMemoryReporter());
 
   sMemoryReporterRegistered = true;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// FileImplTemporaryFileBlob implementation
+// FileImplTemporaryBlob implementation
 
-NS_IMPL_ISUPPORTS_INHERITED0(FileImplTemporaryFileBlob, FileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(FileImplTemporaryBlob, FileImpl)
 
 already_AddRefed<FileImpl>
-FileImplTemporaryFileBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
-                                       const nsAString& aContentType,
-                                       ErrorResult& aRv)
+FileImplTemporaryBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
+                                   const nsAString& aContentType,
+                                   ErrorResult& aRv)
 {
   if (aStart + aLength > mLength) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsRefPtr<FileImpl> impl =
-    new FileImplTemporaryFileBlob(this, aStart + mStartPos,
-                                  aLength, aContentType);
+    new FileImplTemporaryBlob(this, aStart + mStartPos,
+                              aLength, aContentType);
   return impl.forget();
 }
 
 nsresult
-FileImplTemporaryFileBlob::GetInternalStream(nsIInputStream** aStream)
+FileImplTemporaryBlob::GetInternalStream(nsIInputStream** aStream)
 {
   nsCOMPtr<nsIInputStream> stream =
     new nsTemporaryFileInputStream(mFileDescOwner, mStartPos, mStartPos + mLength);
   stream.forget(aStream);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
@@ -1254,20 +1326,20 @@ FileList::Item(uint32_t aIndex, nsIDOMFi
   nsRefPtr<File> file = Item(aIndex);
   file.forget(aFile);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // BlobSet implementation
 
-already_AddRefed<File>
+already_AddRefed<Blob>
 BlobSet::GetBlobInternal(nsISupports* aParent, const nsACString& aContentType)
 {
-  nsRefPtr<File> blob = new File(aParent,
+  nsRefPtr<Blob> blob = Blob::Create(aParent,
     new MultipartFileImpl(GetBlobImpls(),
                           NS_ConvertASCIItoUTF16(aContentType)));
   return blob.forget();
 }
 
 nsresult
 BlobSet::AppendVoidPtr(const void* aData, uint32_t aLength)
 {
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -42,71 +42,159 @@ namespace dom {
 
 namespace indexedDB {
 class FileInfo;
 };
 
 struct BlobPropertyBag;
 struct ChromeFilePropertyBag;
 struct FilePropertyBag;
+class File;
 class FileImpl;
 class OwningArrayBufferOrArrayBufferViewOrBlobOrString;
 
-class File final : public nsIDOMFile
-                 , public nsIXHRSendable
-                 , public nsIMutable
-                 , public nsSupportsWeakReference
-                 , public nsWrapperCache
+class Blob : public nsIDOMBlob
+           , public nsIXHRSendable
+           , public nsIMutable
+           , 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_SCRIPT_HOLDER_CLASS_AMBIGUOUS(File, nsIDOMFile)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Blob, nsIDOMBlob)
+
+  static Blob*
+  Create(nsISupports* aParent, FileImpl* aImpl);
+
+  static already_AddRefed<Blob>
+  Create(nsISupports* aParent, const nsAString& aContentType,
+         uint64_t aLength);
+
+  static already_AddRefed<Blob>
+  Create(nsISupports* aParent, const nsAString& aContentType, uint64_t aStart,
+         uint64_t aLength);
+
+  // The returned Blob takes ownership of aMemoryBuffer. aMemoryBuffer will be
+  // freed by free so it must be allocated by malloc or something
+  // compatible with it.
+  static already_AddRefed<Blob>
+  CreateMemoryBlob(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
+                   const nsAString& aContentType);
+
+  static already_AddRefed<Blob>
+  CreateTemporaryBlob(nsISupports* aParent, PRFileDesc* aFD,
+                      uint64_t aStartPos, uint64_t aLength,
+                      const nsAString& aContentType);
+
+  FileImpl* Impl() const
+  {
+    return mImpl;
+  }
+
+  bool IsFile() const;
+
+  const nsTArray<nsRefPtr<FileImpl>>* GetSubBlobImpls() const;
+
+  // This method returns null if this Blob is not a File; it returns
+  // the same object in case this Blob already implements the File interface;
+  // otherwise it returns a new File object with the same FileImpl.
+  already_AddRefed<File> ToFile();
+
+  // This method creates a new File object with the given name and the same
+  // FileImpl.
+  already_AddRefed<File> ToFile(const nsAString& aName) const;
+
+  already_AddRefed<Blob>
+  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
+              ErrorResult& aRv);
+
+  // WebIDL methods
+  nsISupports* GetParentObject() const
+  {
+    return mParent;
+  }
+
+  // Blob constructor
+  static already_AddRefed<Blob>
+  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+
+  // Blob constructor
+  static already_AddRefed<Blob>
+  Constructor(const GlobalObject& aGlobal,
+              const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+              const BlobPropertyBag& aBag,
+              ErrorResult& aRv);
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
+  uint64_t GetSize(ErrorResult& aRv);
+
+  // XPCOM GetType is OK
+
+  already_AddRefed<Blob> Slice(const Optional<int64_t>& aStart,
+                               const Optional<int64_t>& aEnd,
+                               const nsAString& aContentType,
+                               ErrorResult& aRv);
+
+protected:
+  // File constructor should never be used directly. Use Blob::Create instead.
+  Blob(nsISupports* aParent, FileImpl* aImpl);
+  virtual ~Blob() {};
+
+  virtual bool HasFileInterface() const { return false; }
+
+  // The member is the real backend implementation of this File/Blob.
+  // 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!
+  nsRefPtr<FileImpl> mImpl;
+
+private:
+  nsCOMPtr<nsISupports> mParent;
+};
+
+class File final : public Blob
+                 , public nsIDOMFile
+{
+  friend class Blob;
+
+public:
+  NS_DECL_NSIDOMFILE
+  NS_FORWARD_NSIDOMBLOB(Blob::)
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(File, Blob);
+
+  // Note: FileImpl must be a File in order to use this method.
+  // Check impl->IsFile().
+  static File*
+  Create(nsISupports* aParent, FileImpl* aImpl);
 
   static already_AddRefed<File>
   Create(nsISupports* aParent, const nsAString& aName,
          const nsAString& aContentType, uint64_t aLength,
          int64_t aLastModifiedDate);
 
   static already_AddRefed<File>
   Create(nsISupports* aParent, const nsAString& aName,
          const nsAString& aContentType, uint64_t aLength);
 
-  static already_AddRefed<File>
-  Create(nsISupports* aParent, const nsAString& aContentType,
-         uint64_t aLength);
-
-  static already_AddRefed<File>
-  Create(nsISupports* aParent, const nsAString& aContentType, uint64_t aStart,
-         uint64_t aLength);
-
   // The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
   // freed by free so it must be allocated by malloc or something
   // compatible with it.
   static already_AddRefed<File>
   CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
                    const nsAString& aName, const nsAString& aContentType,
                    int64_t aLastModifiedDate);
 
-  // The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
-  // freed by free so it must be allocated by malloc or something
-  // compatible with it.
-  static already_AddRefed<File>
-  CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
-                   const nsAString& aContentType);
-
-  static already_AddRefed<File>
-  CreateTemporaryFileBlob(nsISupports* aParent, PRFileDesc* aFD,
-                          uint64_t aStartPos, uint64_t aLength,
-                          const nsAString& aContentType);
-
   static already_AddRefed<File>
   CreateFromFile(nsISupports* aParent, nsIFile* aFile, bool aTemporary = false);
 
   static already_AddRefed<File>
   CreateFromFile(nsISupports* aParent, const nsAString& aContentType,
                  uint64_t aLength, nsIFile* aFile,
                  indexedDB::FileInfo* aFileInfo);
 
@@ -118,64 +206,33 @@ public:
   static already_AddRefed<File>
   CreateFromFile(nsISupports* aParent, nsIFile* aFile,
                  indexedDB::FileInfo* aFileInfo);
 
   static already_AddRefed<File>
   CreateFromFile(nsISupports* aParent, nsIFile* aFile, const nsAString& aName,
                  const nsAString& aContentType);
 
-  File(nsISupports* aParent, FileImpl* aImpl);
-
-  FileImpl* Impl() const
-  {
-    return mImpl;
-  }
-
-  const nsTArray<nsRefPtr<FileImpl>>* GetSubBlobImpls() const;
-
-  bool IsSizeUnknown() const;
-
-  bool IsDateUnknown() const;
-
-  bool IsFile() const;
+  // WebIDL methods
 
-  already_AddRefed<File>
-  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
-              ErrorResult& aRv);
-
-  // WebIDL methods
-  nsISupports* GetParentObject() const
-  {
-    return mParent;
-  }
-
-  // Blob constructor
-  static already_AddRefed<File>
-  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
-
-  // Blob constructor
-  static already_AddRefed<File>
-  Constructor(const GlobalObject& aGlobal,
-              const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
-              const BlobPropertyBag& aBag,
-              ErrorResult& aRv);
+  virtual JSObject* WrapObject(JSContext *cx,
+                               JS::Handle<JSObject*> aGivenProto) override;
 
   // File constructor
   static already_AddRefed<File>
   Constructor(const GlobalObject& aGlobal,
               const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
               const nsAString& aName,
               const FilePropertyBag& aBag,
               ErrorResult& aRv);
 
   // File constructor - ChromeOnly
   static already_AddRefed<File>
   Constructor(const GlobalObject& aGlobal,
-              File& aData,
+              Blob& aData,
               const ChromeFilePropertyBag& aBag,
               ErrorResult& aRv);
 
   // File constructor - ChromeOnly
   static already_AddRefed<File>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aData,
               const ChromeFilePropertyBag& aBag,
@@ -183,45 +240,33 @@ public:
 
   // File constructor - ChromeOnly
   static already_AddRefed<File>
   Constructor(const GlobalObject& aGlobal,
               nsIFile* aData,
               const ChromeFilePropertyBag& aBag,
               ErrorResult& aRv);
 
-  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) 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<File> Slice(const Optional<int64_t>& aStart,
-                               const Optional<int64_t>& aEnd,
-                               const nsAString& aContentType,
-                               ErrorResult& aRv);
+protected:
+  virtual bool HasFileInterface() const override { return true; }
 
 private:
+  // File constructor should never be used directly. Use Blob::Create or
+  // File::Create.
+  File(nsISupports* aParent, FileImpl* aImpl);
   ~File() {};
-
-  // The member is the real backend implementation of this File/Blob.
-  // 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!
-  nsRefPtr<FileImpl> mImpl;
-
-  nsCOMPtr<nsISupports> mParent;
 };
 
 // This is the abstract class for any File backend. It must be nsISupports
 // because this class must be ref-counted and it has to work with IPC.
 class FileImpl : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(FILEIMPL_IID)
@@ -580,45 +625,45 @@ private:
   }
 
   ~FileImplMemory() {}
 
   // Used when backed by a memory store
   nsRefPtr<DataOwner> mDataOwner;
 };
 
-class FileImplTemporaryFileBlob final : public FileImplBase
+class FileImplTemporaryBlob final : public FileImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
-  FileImplTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos,
-                            uint64_t aLength, const nsAString& aContentType)
+  FileImplTemporaryBlob(PRFileDesc* aFD, uint64_t aStartPos,
+                        uint64_t aLength, const nsAString& aContentType)
     : FileImplBase(aContentType, aLength)
     , mStartPos(aStartPos)
   {
     mFileDescOwner = new nsTemporaryFileInputStream::FileDescOwner(aFD);
   }
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) override;
 
   virtual already_AddRefed<FileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType, ErrorResult& aRv) override;
 
 private:
-  FileImplTemporaryFileBlob(const FileImplTemporaryFileBlob* aOther,
-                            uint64_t aStart, uint64_t aLength,
-                            const nsAString& aContentType)
+  FileImplTemporaryBlob(const FileImplTemporaryBlob* aOther,
+                        uint64_t aStart, uint64_t aLength,
+                        const nsAString& aContentType)
     : FileImplBase(aContentType, aLength)
     , mStartPos(aStart)
     , mFileDescOwner(aOther->mFileDescOwner)
   {}
 
-  ~FileImplTemporaryFileBlob() {}
+  ~FileImplTemporaryBlob() {}
 
   uint64_t mStartPos;
   nsRefPtr<nsTemporaryFileInputStream::FileDescOwner> mFileDescOwner;
 };
 
 class FileImplFile : public FileImplBase
 {
 public:
@@ -818,17 +863,18 @@ public:
   {
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FileList)
 
   NS_DECL_NSIDOMFILELIST
 
-  virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
+  virtual JSObject* WrapObject(JSContext *cx,
+                               JS::Handle<JSObject*> aGivenProto) override;
 
   nsISupports* GetParentObject()
   {
     return mParent;
   }
 
   void Disconnect()
   {
--- a/dom/base/ImageEncoder.cpp
+++ b/dom/base/ImageEncoder.cpp
@@ -85,18 +85,18 @@ public:
 
   NS_IMETHOD Run() override
   {
     nsresult rv = NS_OK;
     MOZ_ASSERT(NS_IsMainThread());
 
     if (!mFailed) {
       // The correct parentObject has to be set by the mEncodeCompleteCallback.
-      nsRefPtr<File> blob =
-        File::CreateMemoryFile(nullptr, mImgData, mImgSize, mType);
+      nsRefPtr<Blob> blob =
+        Blob::CreateMemoryBlob(nullptr, mImgData, mImgSize, mType);
       MOZ_ASSERT(blob);
 
       rv = mEncodeCompleteCallback->ReceiveBlob(blob.forget());
     }
 
     mEncodeCompleteCallback = nullptr;
 
     mEncoderThread->Shutdown();
--- a/dom/base/ImageEncoder.h
+++ b/dom/base/ImageEncoder.h
@@ -111,17 +111,17 @@ private:
  *  The callback interface of ExtractDataAsync and ExtractDataFromLayersImageAsync.
  *  ReceiveBlob() is called on main thread when encoding is complete.
  */
 class EncodeCompleteCallback
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(EncodeCompleteCallback)
 
-  virtual nsresult ReceiveBlob(already_AddRefed<File> aBlob) = 0;
+  virtual nsresult ReceiveBlob(already_AddRefed<Blob> aBlob) = 0;
 
 protected:
   virtual ~EncodeCompleteCallback() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/base/MessagePort.cpp
+++ b/dom/base/MessagePort.cpp
@@ -119,19 +119,19 @@ PostMessageReadStructuredClone(JSContext
 
       // nsRefPtr<File> 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<File> blob = new File(scInfo->mPort->GetParentObject(),
-                                             blobImpl);
-        if (!GetOrCreateDOMReflector(cx, blob, &val)) {
+        nsRefPtr<Blob> blob = Blob::Create(scInfo->mPort->GetParentObject(),
+                                           blobImpl);
+        if (!ToJSValue(cx, blob, &val)) {
           return nullptr;
         }
       }
 
       return &val.toObject();
     }
   }
 
@@ -163,17 +163,17 @@ PostMessageWriteStructuredClone(JSContex
                                 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.
   {
-    File* blob = nullptr;
+    Blob* blob = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
       FileImpl* blobImpl = blob->Impl();
       if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
           JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
         scInfo->mEvent->StoreISupports(blobImpl);
         return true;
       }
     }
--- a/dom/base/MultipartFileImpl.cpp
+++ b/dom/base/MultipartFileImpl.cpp
@@ -140,18 +140,18 @@ MultipartFileImpl::InitializeBlob(
 {
   mContentType = aContentType;
   BlobSet blobSet;
 
   for (uint32_t i = 0, len = aData.Length(); i < len; ++i) {
     const OwningArrayBufferOrArrayBufferViewOrBlobOrString& data = aData[i];
 
     if (data.IsBlob()) {
-      nsRefPtr<File> file = data.GetAsBlob().get();
-      blobSet.AppendBlobImpl(file->Impl());
+      nsRefPtr<Blob> blob = data.GetAsBlob().get();
+      blobSet.AppendBlobImpl(blob->Impl());
     }
 
     else if (data.IsString()) {
       aRv = blobSet.AppendString(data.GetAsString(), aNativeEOL, aCx);
       if (aRv.Failed()) {
         return;
       }
     }
@@ -276,17 +276,17 @@ MultipartFileImpl::SetMutable(bool aMuta
   }
 
   MOZ_ASSERT_IF(!aMutable, mImmutable);
 
   return NS_OK;
 }
 
 void
-MultipartFileImpl::InitializeChromeFile(File& aBlob,
+MultipartFileImpl::InitializeChromeFile(Blob& aBlob,
                                         const ChromeFilePropertyBag& aBag,
                                         ErrorResult& aRv)
 {
   NS_ASSERTION(!mImmutable, "Something went wrong ...");
 
   if (mImmutable) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
--- a/dom/base/MultipartFileImpl.h
+++ b/dom/base/MultipartFileImpl.h
@@ -62,17 +62,17 @@ public:
 
   void InitializeBlob(
        JSContext* aCx,
        const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
        const nsAString& aContentType,
        bool aNativeEOL,
        ErrorResult& aRv);
 
-  void InitializeChromeFile(File& aData,
+  void InitializeChromeFile(Blob& aData,
                             const ChromeFilePropertyBag& aBag,
                             ErrorResult& aRv);
 
   void InitializeChromeFile(nsPIDOMWindow* aWindow,
                             const nsAString& aData,
                             const ChromeFilePropertyBag& aBag,
                             ErrorResult& aRv);
 
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1208,17 +1208,17 @@ 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()) {
-      File& blob = aData.Value().GetAsBlob();
+      Blob& 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);
       if (NS_FAILED(rv)) {
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -107,17 +107,17 @@ URL::Constructor(const nsAString& aUrl, 
   }
 
   nsRefPtr<URL> url = new URL(uri.forget());
   return url.forget();
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal,
-                     File& aBlob,
+                     Blob& aBlob,
                      const objectURLOptions& aOptions,
                      nsAString& aResult,
                      ErrorResult& aError)
 {
   CreateObjectURLInternal(aGlobal, aBlob.Impl(),
                           NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult,
                           aError);
 }
--- a/dom/base/URL.h
+++ b/dom/base/URL.h
@@ -17,17 +17,17 @@ class nsIURI;
 
 namespace mozilla {
 
 class ErrorResult;
 class DOMMediaStream;
 
 namespace dom {
 
-class File;
+class Blob;
 class MediaSource;
 class GlobalObject;
 struct objectURLOptions;
 
 namespace workers {
 class URLProxy;
 }
 
@@ -56,17 +56,17 @@ public:
   Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
               const nsAString& aBase, ErrorResult& aRv);
   static already_AddRefed<URL>
   Constructor(const nsAString& aUrl, const nsAString& aBase, ErrorResult& aRv);
   static already_AddRefed<URL>
   Constructor(const nsAString& aUrl, nsIURI* aBase, ErrorResult& aRv);
 
   static void CreateObjectURL(const GlobalObject& aGlobal,
-                              File& aBlob,
+                              Blob& aBlob,
                               const objectURLOptions& aOptions,
                               nsAString& aResult,
                               ErrorResult& aError);
   static void CreateObjectURL(const GlobalObject& aGlobal,
                               DOMMediaStream& aStream,
                               const objectURLOptions& aOptions,
                               nsAString& aResult,
                               ErrorResult& aError);
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -2205,17 +2205,17 @@ WebSocket::Send(const nsAString& aData,
 {
   AssertIsOnTargetThread();
 
   NS_ConvertUTF16toUTF8 msgString(aData);
   Send(nullptr, msgString, msgString.Length(), false, aRv);
 }
 
 void
-WebSocket::Send(File& aData, ErrorResult& aRv)
+WebSocket::Send(Blob& aData, ErrorResult& aRv)
 {
   AssertIsOnTargetThread();
 
   nsCOMPtr<nsIInputStream> msgStream;
   nsresult rv = aData.GetInternalStream(getter_AddRefs(msgStream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
--- a/dom/base/WebSocket.h
+++ b/dom/base/WebSocket.h
@@ -23,17 +23,17 @@
 #define DEFAULT_WS_SCHEME_PORT  80
 #define DEFAULT_WSS_SCHEME_PORT 443
 
 class nsIInputStream;
 
 namespace mozilla {
 namespace dom {
 
-class File;
+class Blob;
 
 class WebSocketImpl;
 
 class WebSocket final : public DOMEventTargetHelper
 {
   friend class WebSocketImpl;
 
 public:
@@ -116,17 +116,17 @@ public: // WebIDL interface:
 
   // webIDL: attribute DOMString binaryType;
   dom::BinaryType BinaryType() const;
   void SetBinaryType(dom::BinaryType aData);
 
   // webIDL: void send(DOMString|Blob|ArrayBufferView data);
   void Send(const nsAString& aData,
             ErrorResult& aRv);
-  void Send(File& aData,
+  void Send(Blob& 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/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6085,26 +6085,26 @@ nsContentUtils::CreateArrayBuffer(JSCont
 nsresult
 nsContentUtils::CreateBlobBuffer(JSContext* aCx,
                                  nsISupports* aParent,
                                  const nsACString& aData,
                                  JS::MutableHandle<JS::Value> aBlob)
 {
   uint32_t blobLen = aData.Length();
   void* blobData = malloc(blobLen);
-  nsRefPtr<File> blob;
+  nsRefPtr<Blob> blob;
   if (blobData) {
     memcpy(blobData, aData.BeginReading(), blobLen);
-    blob = mozilla::dom::File::CreateMemoryFile(aParent, blobData, blobLen,
+    blob = mozilla::dom::Blob::CreateMemoryBlob(aParent, blobData, blobLen,
                                                 EmptyString());
   } else {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  if (!GetOrCreateDOMReflector(aCx, blob, aBlob)) {
+  if (!ToJSValue(aCx, blob, aBlob)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 void
 nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr)
--- a/dom/base/nsDOMDataChannel.cpp
+++ b/dom/base/nsDOMDataChannel.cpp
@@ -262,17 +262,17 @@ nsDOMDataChannel::Close()
 void
 nsDOMDataChannel::Send(const nsAString& aData, ErrorResult& aRv)
 {
   NS_ConvertUTF16toUTF8 msgString(aData);
   Send(nullptr, msgString, msgString.Length(), false, aRv);
 }
 
 void
-nsDOMDataChannel::Send(File& aData, ErrorResult& aRv)
+nsDOMDataChannel::Send(Blob& aData, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
 
   nsCOMPtr<nsIInputStream> msgStream;
   nsresult rv = aData.GetInternalStream(getter_AddRefs(msgStream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
--- a/dom/base/nsDOMDataChannel.h
+++ b/dom/base/nsDOMDataChannel.h
@@ -13,17 +13,17 @@
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/net/DataChannelListener.h"
 #include "nsIDOMDataChannel.h"
 #include "nsIInputStream.h"
 
 
 namespace mozilla {
 namespace dom {
-class File;
+class Blob;
 }
 
 class DataChannel;
 };
 
 class nsDOMDataChannel final : public mozilla::DOMEventTargetHelper,
                                public nsIDOMDataChannel,
                                public mozilla::DataChannelListener
@@ -65,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(mozilla::dom::File& aData, mozilla::ErrorResult& aRv);
+  void Send(mozilla::dom::Blob& 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/dom/base/nsDOMFileReader.cpp
+++ b/dom/base/nsDOMFileReader.cpp
@@ -38,23 +38,23 @@ using namespace mozilla::dom;
 #define LOADEND_STR "loadend"
 
 static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileReader)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMFileReader,
                                                   FileIOObject)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFile)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBlob)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMFileReader,
                                                 FileIOObject)
   tmp->mResultArrayBuffer = nullptr;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFile)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBlob)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsDOMFileReader,
                                                DOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultArrayBuffer)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
@@ -178,53 +178,53 @@ nsDOMFileReader::GetResult(JSContext* aC
 NS_IMETHODIMP
 nsDOMFileReader::GetError(nsISupports** aError)
 {
   NS_IF_ADDREF(*aError = GetError());
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::ReadAsArrayBuffer(nsIDOMBlob* aFile, JSContext* aCx)
+nsDOMFileReader::ReadAsArrayBuffer(nsIDOMBlob* aBlob, JSContext* aCx)
 {
-  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<File> file = static_cast<File*>(aFile);
-  ReadAsArrayBuffer(aCx, *file, rv);
+  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
+  ReadAsArrayBuffer(aCx, *blob, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::ReadAsBinaryString(nsIDOMBlob* aFile)
+nsDOMFileReader::ReadAsBinaryString(nsIDOMBlob* aBlob)
 {
-  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<File> file = static_cast<File*>(aFile);
-  ReadAsBinaryString(*file, rv);
+  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
+  ReadAsBinaryString(*blob, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::ReadAsText(nsIDOMBlob* aFile,
+nsDOMFileReader::ReadAsText(nsIDOMBlob* aBlob,
                             const nsAString &aCharset)
 {
-  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<File> file = static_cast<File*>(aFile);
-  ReadAsText(*file, aCharset, rv);
+  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
+  ReadAsText(*blob, aCharset, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::ReadAsDataURL(nsIDOMBlob* aFile)
+nsDOMFileReader::ReadAsDataURL(nsIDOMBlob* aBlob)
 {
-  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<File> file = static_cast<File*>(aFile);
-  ReadAsDataURL(*file, rv);
+  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
+  ReadAsDataURL(*blob, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::Abort()
 {
   ErrorResult rv;
   FileIOObject::Abort(rv);
@@ -236,17 +236,17 @@ nsDOMFileReader::DoAbort(nsAString& aEve
 {
   // Revert status and result attributes
   SetDOMStringToNull(mResult);
   mResultArrayBuffer = nullptr;
 
   if (mAsyncStream) {
     mAsyncStream = nullptr;
   }
-  mFile = nullptr;
+  mBlob = nullptr;
 
   //Clean up memory buffer
   FreeFileData();
 
   // Tell the base class which event to dispatch
   aEvent = NS_LITERAL_STRING(LOADEND_STR);
 }
 
@@ -276,18 +276,18 @@ nsresult
 nsDOMFileReader::DoOnLoadEnd(nsresult aStatus,
                              nsAString& aSuccessEvent,
                              nsAString& aTerminationEvent)
 {
 
   // Make sure we drop all the objects that could hold files open now.
   nsCOMPtr<nsIAsyncInputStream> stream;
   mAsyncStream.swap(stream);
-  nsCOMPtr<nsIDOMBlob> file;
-  mFile.swap(file);
+  nsCOMPtr<nsIDOMBlob> blob;
+  mBlob.swap(blob);
 
   aSuccessEvent = NS_LITERAL_STRING(LOAD_STR);
   aTerminationEvent = NS_LITERAL_STRING(LOADEND_STR);
 
   // Clear out the data if necessary
   if (NS_FAILED(aStatus)) {
     FreeFileData();
     return NS_OK;
@@ -314,23 +314,23 @@ nsDOMFileReader::DoOnLoadEnd(nsresult aS
     case FILE_AS_BINARY:
       break; //Already accumulated mResult
     case FILE_AS_TEXT:
       if (!mFileData) {
         if (mDataLen) {
           rv = NS_ERROR_OUT_OF_MEMORY;
           break;
         }
-        rv = GetAsText(file, mCharset, "", mDataLen, mResult);
+        rv = GetAsText(blob, mCharset, "", mDataLen, mResult);
         break;
       }
-      rv = GetAsText(file, mCharset, mFileData, mDataLen, mResult);
+      rv = GetAsText(blob, mCharset, mFileData, mDataLen, mResult);
       break;
     case FILE_AS_DATAURL:
-      rv = GetAsDataURL(file, mFileData, mDataLen, mResult);
+      rv = GetAsDataURL(blob, mFileData, mDataLen, mResult);
       break;
   }
 
   mResult.SetIsVoid(false);
 
   FreeFileData();
 
   return rv;
@@ -375,45 +375,45 @@ nsDOMFileReader::DoReadData(nsIAsyncInpu
 
   mDataLen += aCount;
   return NS_OK;
 }
 
 // Helper methods
 
 void
-nsDOMFileReader::ReadFileContent(File& aFile,
+nsDOMFileReader::ReadFileContent(Blob& aBlob,
                                  const nsAString &aCharset,
                                  eDataFormat aDataFormat,
                                  ErrorResult& aRv)
 {
   //Implicit abort to clear any other activity going on
   Abort();
   mError = nullptr;
   SetDOMStringToNull(mResult);
   mTransferred = 0;
   mTotal = 0;
   mReadyState = nsIDOMFileReader::EMPTY;
   FreeFileData();
 
-  mFile = &aFile;
+  mBlob = &aBlob;
   mDataFormat = aDataFormat;
   CopyUTF16toUTF8(aCharset, mCharset);
 
   nsresult rv;
 
   nsCOMPtr<nsIStreamTransportService> sts =
     do_GetService(kStreamTransportServiceCID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return;
   }
 
   nsCOMPtr<nsIInputStream> stream;
-  rv = mFile->GetInternalStream(getter_AddRefs(stream));
+  rv = mBlob->GetInternalStream(getter_AddRefs(stream));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return;
   }
 
   nsCOMPtr<nsITransport> transport;
   rv = sts->CreateInputTransport(stream,
                                  /* aStartOffset */ 0,
@@ -435,17 +435,17 @@ nsDOMFileReader::ReadFileContent(File& a
     return;
   }
 
   MOZ_ASSERT(!mAsyncStream);
   mAsyncStream = do_QueryInterface(wrapper);
   MOZ_ASSERT(mAsyncStream);
 
   mTotal = mozilla::dom::kUnknownSize;
-  mFile->GetSize(&mTotal);
+  mBlob->GetSize(&mTotal);
 
   rv = DoAsyncWait(mAsyncStream);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return;
   }
 
   //FileReader should be in loading state here
@@ -457,17 +457,17 @@ nsDOMFileReader::ReadFileContent(File& a
     if (!mFileData) {
       NS_WARNING("Preallocation failed for ReadFileData");
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     }
   }
 }
 
 nsresult
-nsDOMFileReader::GetAsText(nsIDOMBlob *aFile,
+nsDOMFileReader::GetAsText(nsIDOMBlob *aBlob,
                            const nsACString &aCharset,
                            const char *aFileData,
                            uint32_t aDataLen,
                            nsAString& aResult)
 {
   // The BOM sniffing is baked into the "decode" part of the Encoding
   // Standard, which the File API references.
   nsAutoCString encoding;
@@ -475,17 +475,17 @@ nsDOMFileReader::GetAsText(nsIDOMBlob *a
         reinterpret_cast<const unsigned char *>(aFileData),
         aDataLen,
         encoding)) {
     // BOM sniffing failed. Try the API argument.
     if (!EncodingUtils::FindEncodingForLabel(aCharset,
                                              encoding)) {
       // API argument failed. Try the type property of the blob.
       nsAutoString type16;
-      aFile->GetType(type16);
+      aBlob->GetType(type16);
       NS_ConvertUTF16toUTF8 type(type16);
       nsAutoCString specifiedCharset;
       bool haveCharset;
       int32_t charsetStart, charsetEnd;
       NS_ExtractCharsetFromContentType(type,
                                        specifiedCharset,
                                        &haveCharset,
                                        &charsetStart,
@@ -497,26 +497,26 @@ nsDOMFileReader::GetAsText(nsIDOMBlob *a
     }
   }
 
   nsDependentCSubstring data(aFileData, aDataLen);
   return nsContentUtils::ConvertStringFromEncoding(encoding, data, aResult);
 }
 
 nsresult
-nsDOMFileReader::GetAsDataURL(nsIDOMBlob *aFile,
+nsDOMFileReader::GetAsDataURL(nsIDOMBlob *aBlob,
                               const char *aFileData,
                               uint32_t aDataLen,
                               nsAString& aResult)
 {
   aResult.AssignLiteral("data:");
 
   nsresult rv;
   nsString contentType;
-  rv = aFile->GetType(contentType);
+  rv = aBlob->GetType(contentType);
   if (NS_SUCCEEDED(rv) && !contentType.IsEmpty()) {
     aResult.Append(contentType);
   } else {
     aResult.AppendLiteral("application/octet-stream");
   }
   aResult.AppendLiteral(";base64,");
 
   nsCString encodedData;
--- a/dom/base/nsDOMFileReader.h
+++ b/dom/base/nsDOMFileReader.h
@@ -22,28 +22,29 @@
 #include "nsIDOMFileReader.h"
 #include "nsIDOMFileList.h"
 #include "nsCOMPtr.h"
 
 #include "FileIOObject.h"
 
 namespace mozilla {
 namespace dom {
-class File;
+class Blob;
 }
 }
 
 class nsDOMFileReader final : public mozilla::dom::FileIOObject,
                               public nsIDOMFileReader,
                               public nsIInterfaceRequestor,
                               public nsSupportsWeakReference
 {
   typedef mozilla::ErrorResult ErrorResult;
   typedef mozilla::dom::GlobalObject GlobalObject;
-  typedef mozilla::dom::File File;
+  typedef mozilla::dom::Blob Blob;
+
 public:
   nsDOMFileReader();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMFILEREADER
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(mozilla::DOMEventTargetHelper)
@@ -63,27 +64,27 @@ public:
   {
     return GetOwner();
   }
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   // WebIDL
   static already_AddRefed<nsDOMFileReader>
   Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
-  void ReadAsArrayBuffer(JSContext* aCx, File& aBlob, ErrorResult& aRv)
+  void ReadAsArrayBuffer(JSContext* aCx, Blob& aBlob, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
   }
 
-  void ReadAsText(File& aBlob, const nsAString& aLabel, ErrorResult& aRv)
+  void ReadAsText(Blob& aBlob, const nsAString& aLabel, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, aLabel, FILE_AS_TEXT, aRv);
   }
 
-  void ReadAsDataURL(File& aBlob, ErrorResult& aRv)
+  void ReadAsDataURL(Blob& aBlob, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
   }
 
   using FileIOObject::Abort;
 
   // Inherited ReadyState().
 
@@ -97,17 +98,17 @@ 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(File& aBlob, ErrorResult& aRv)
+  void ReadAsBinaryString(Blob& aBlob, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, EmptyString(), FILE_AS_BINARY, aRv);
   }
 
 
   nsresult Init();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsDOMFileReader,
@@ -119,31 +120,33 @@ protected:
 
   enum eDataFormat {
     FILE_AS_ARRAYBUFFER,
     FILE_AS_BINARY,
     FILE_AS_TEXT,
     FILE_AS_DATAURL
   };
 
-  void ReadFileContent(File& aBlob,
+  void ReadFileContent(Blob& 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);
+  nsresult GetAsText(nsIDOMBlob *aBlob, const nsACString &aCharset,
+                     const char *aFileData, uint32_t aDataLen,
+                     nsAString &aResult);
+  nsresult GetAsDataURL(nsIDOMBlob *aBlob, const char *aFileData,
+                        uint32_t aDataLen, nsAString &aResult);
 
   void FreeFileData() {
     free(mFileData);
     mFileData = nullptr;
     mDataLen = 0;
   }
 
   char *mFileData;
-  nsCOMPtr<nsIDOMBlob> mFile;
+  nsCOMPtr<nsIDOMBlob> mBlob;
   nsCString mCharset;
   uint32_t mDataLen;
 
   eDataFormat mDataFormat;
 
   nsString mResult;
 
   JS::Heap<JSObject*> mResultArrayBuffer;
--- a/dom/base/nsFormData.cpp
+++ b/dom/base/nsFormData.cpp
@@ -17,48 +17,44 @@ using namespace mozilla::dom;
 
 nsFormData::nsFormData(nsISupports* aOwner)
   : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr)
   , mOwner(aOwner)
 {
 }
 
 namespace {
+
 // Implements steps 3 and 4 of the "create an entry" algorithm of FormData.
-File*
-CreateNewFileInstance(File& aBlob, const Optional<nsAString>& aFilename)
+already_AddRefed<File>
+CreateNewFileInstance(Blob& aBlob, const Optional<nsAString>& aFilename)
 {
   // Step 3 "If value is a Blob object and not a File object, set value to
   // a new File object, representing the same bytes, whose name attribute value
   // is "blob"."
   // Step 4 "If value is a File object and filename is given, set value to
   // a new File object, representing the same bytes, whose name attribute
   // value is filename."
   nsAutoString filename;
   if (aFilename.WasPassed()) {
     filename = aFilename.Value();
-  } else if (aBlob.IsFile()) {
+  } else {
     // If value is already a File and filename is not passed, the spec says not
     // to create a new instance.
-    return &aBlob;
-  } else {
+    nsRefPtr<File> file = aBlob.ToFile();
+    if (file) {
+      return file.forget();
+    }
+
     filename = NS_LITERAL_STRING("blob");
   }
 
-  nsAutoTArray<nsRefPtr<FileImpl>, 1> blobImpls;
-  blobImpls.AppendElement(aBlob.Impl());
-
-  nsAutoString contentType;
-  aBlob.GetType(contentType);
+  return aBlob.ToFile(filename);
+}
 
-  nsRefPtr<MultipartFileImpl> impl =
-    new MultipartFileImpl(blobImpls, filename, contentType);
-
-  return new File(aBlob.GetParentObject(), impl);
-}
 } // anonymous namespace
 
 // -------------------------------------------------------------------------
 // nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsFormData)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormData)
@@ -106,17 +102,17 @@ nsFormData::GetEncodedSubmission(nsIURI*
 
 void
 nsFormData::Append(const nsAString& aName, const nsAString& aValue)
 {
   AddNameValuePair(aName, aValue);
 }
 
 void
-nsFormData::Append(const nsAString& aName, File& aBlob,
+nsFormData::Append(const nsAString& aName, Blob& aBlob,
                    const Optional<nsAString>& aFilename)
 {
   nsRefPtr<File> file = CreateNewFileInstance(aBlob, aFilename);
   AddNameFilePair(aName, file);
 }
 
 void
 nsFormData::Delete(const nsAString& aName)
@@ -174,16 +170,24 @@ nsFormData::Has(const nsAString& aName)
     if (aName.Equals(mFormData[i].name)) {
       return true;
     }
   }
 
   return false;
 }
 
+nsresult
+nsFormData::AddNameFilePair(const nsAString& aName, File* aFile)
+{
+  FormDataTuple* data = mFormData.AppendElement();
+  SetNameFilePair(data, aName, aFile);
+  return NS_OK;
+}
+
 nsFormData::FormDataTuple*
 nsFormData::RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName)
 {
   FormDataTuple* lastFoundTuple = nullptr;
   uint32_t lastFoundIndex = mFormData.Length();
   // We have to use this slightly awkward for loop since uint32_t >= 0 is an
   // error for being always true.
   for (uint32_t i = mFormData.Length(); i-- > 0; ) {
@@ -197,17 +201,17 @@ nsFormData::RemoveAllOthersAndGetFirstFo
       lastFoundIndex = i;
     }
   }
 
   return lastFoundTuple;
 }
 
 void
-nsFormData::Set(const nsAString& aName, File& aBlob,
+nsFormData::Set(const nsAString& aName, Blob& aBlob,
                 const Optional<nsAString>& aFilename)
 {
   FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
   if (tuple) {
     nsRefPtr<File> file = CreateNewFileInstance(aBlob, aFilename);
     SetNameFilePair(tuple, aName, file);
   } else {
     Append(aName, aBlob, aFilename);
@@ -240,17 +244,17 @@ nsFormData::Append(const nsAString& aNam
     nsCOMPtr<nsISupports> supports;
     nsID *iid;
     rv = aValue->GetAsInterface(&iid, getter_AddRefs(supports));
     NS_ENSURE_SUCCESS(rv, rv);
 
     free(iid);
 
     nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(supports);
-    nsRefPtr<File> blob = static_cast<File*>(domBlob.get());
+    nsRefPtr<Blob> blob = static_cast<Blob*>(domBlob.get());
     if (domBlob) {
       Optional<nsAString> temp;
       Append(aName, *blob, temp);
       return NS_OK;
     }
   }
 
   char16_t* stringData = nullptr;
--- a/dom/base/nsFormData.h
+++ b/dom/base/nsFormData.h
@@ -30,17 +30,19 @@ class GlobalObject;
 class nsFormData final : public nsIDOMFormData,
                          public nsIXHRSendable,
                          public nsFormSubmission,
                          public nsWrapperCache
 {
 private:
   ~nsFormData() {}
 
+  typedef mozilla::dom::Blob Blob;
   typedef mozilla::dom::File File;
+
   struct FormDataTuple
   {
     nsString name;
     nsString stringValue;
     nsRefPtr<File> fileValue;
     bool valueIsFile;
   };
 
@@ -56,21 +58,21 @@ private:
     MOZ_ASSERT(aData);
     aData->name = aName;
     aData->stringValue = aValue;
     aData->valueIsFile = false;
   }
 
   void SetNameFilePair(FormDataTuple* aData,
                        const nsAString& aName,
-                       File* aBlob)
+                       File* aFile)
   {
     MOZ_ASSERT(aData);
     aData->name = aName;
-    aData->fileValue = aBlob;
+    aData->fileValue = aFile;
     aData->valueIsFile = true;
   }
 
   void ExtractValue(const FormDataTuple& aTuple,
                     mozilla::dom::OwningFileOrUSVString* aOutValue);
 public:
   explicit nsFormData(nsISupports* aOwner = nullptr);
 
@@ -90,43 +92,38 @@ 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, File& aBlob,
+  void Append(const nsAString& aName, Blob& aBlob,
               const mozilla::dom::Optional<nsAString>& aFilename);
   void Delete(const nsAString& aName);
   void Get(const nsAString& aName, mozilla::dom::Nullable<mozilla::dom::OwningFileOrUSVString>& aOutValue);
   void GetAll(const nsAString& aName, nsTArray<mozilla::dom::OwningFileOrUSVString>& aValues);
   bool Has(const nsAString& aName);
-  void Set(const nsAString& aName, File& aBlob,
+  void Set(const nsAString& aName, Blob& aBlob,
            const mozilla::dom::Optional<nsAString>& aFilename);
   void Set(const nsAString& aName, const nsAString& aValue);
 
   // nsFormSubmission
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream) override;
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) override
   {
     FormDataTuple* data = mFormData.AppendElement();
     SetNameValuePair(data, aName, aValue);
     return NS_OK;
   }
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   File* aBlob) override
-  {
-    FormDataTuple* data = mFormData.AppendElement();
-    SetNameFilePair(data, aName, aBlob);
-    return NS_OK;
-  }
+                                   File* aFile) override;
 
   typedef bool (*FormDataEntryCallback)(const nsString& aName, bool aIsFile,
                                         const nsString& aValue,
                                         File* aFile, void* aClosure);
 
   uint32_t
   Length() const
   {
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -207,17 +207,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<nsRefPtr<File>>& blobs = aData.mClosure.mBlobs;
+  const nsTArray<nsRefPtr<Blob>>& 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]);
@@ -264,17 +264,17 @@ UnpackClonedMessageData(const ClonedMess
         static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
       MOZ_ASSERT(blob);
 
       nsRefPtr<FileImpl> blobImpl = blob->GetBlobImpl();
       MOZ_ASSERT(blobImpl);
 
       // This object will be duplicated with a correct parent before being
       // exposed to JS.
-      nsRefPtr<File> domBlob = new File(nullptr, blobImpl);
+      nsRefPtr<Blob> domBlob = Blob::Create(nullptr, blobImpl);
       cloneData.mClosure.mBlobs.AppendElement(domBlob);
     }
   }
   return cloneData;
 }
 
 StructuredCloneData
 mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aData)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8058,18 +8058,18 @@ PostMessageReadStructuredClone(JSContext
 
       // nsRefPtr<File> 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<File> blob = new File(scInfo->window, blobImpl);
-        if (!GetOrCreateDOMReflector(cx, blob, &val)) {
+        nsRefPtr<Blob> blob = Blob::Create(scInfo->window, blobImpl);
+        if (!ToJSValue(cx, blob, &val)) {
           return nullptr;
         }
       }
 
       return &val.toObject();
     }
   }
 
@@ -8101,17 +8101,17 @@ PostMessageWriteStructuredClone(JSContex
                                 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.
   {
-    File* blob = nullptr;
+    Blob* blob = nullptr;
     if (scInfo->subsumes && NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
       FileImpl* blobImpl = blob->Impl();
       if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
           JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
         scInfo->event->StoreISupports(blobImpl);
         return true;
       }
     }
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -423,17 +423,17 @@ nsXMLHttpRequest::InitParameters(bool aA
 
 void
 nsXMLHttpRequest::ResetResponse()
 {
   mResponseXML = nullptr;
   mResponseBody.Truncate();
   mResponseText.Truncate();
   mResponseBlob = nullptr;
-  mDOMFile = nullptr;
+  mDOMBlob = nullptr;
   mBlobSet = nullptr;
   mResultArrayBuffer = nullptr;
   mArrayBufferBuilder.reset();
   mResultJSON.setUndefined();
   mDataAvailable = 0;
   mLoadTransferred = 0;
   mResponseBodyDecodedPos = 0;
 }
@@ -474,17 +474,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseXML)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCORSPreflightChannel)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXMLParserStreamListener)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseBlob)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMFile)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMBlob)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationCallbacks)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannelEventSink)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProgressEventSink)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUpload)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
@@ -496,17 +496,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannel)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseXML)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCORSPreflightChannel)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mXMLParserStreamListener)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseBlob)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMFile)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMBlob)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNotificationCallbacks)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannelEventSink)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressEventSink)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mUpload)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
@@ -784,25 +784,25 @@ nsXMLHttpRequest::CreateResponseParsedJS
 
   mResultJSON = value;
   return NS_OK;
 }
 
 void
 nsXMLHttpRequest::CreatePartialBlob()
 {
-  if (mDOMFile) {
+  if (mDOMBlob) {
     // 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;
+      mResponseBlob = mDOMBlob;
     } else {
       ErrorResult rv;
-      mResponseBlob = mDOMFile->CreateSlice(0, mDataAvailable,
+      mResponseBlob = mDOMBlob->CreateSlice(0, mDataAvailable,
                                             EmptyString(), rv);
     }
     return;
   }
 
   // mBlobSet can be null if the request has been canceled
   if (!mBlobSet) {
     return;
@@ -1824,17 +1824,17 @@ nsXMLHttpRequest::StreamReaderFunc(nsIIn
     NS_WARNING("XMLHttpRequest cannot read from stream: no closure or writeCount");
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv = NS_OK;
 
   if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
       xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
-    if (!xmlHttpRequest->mDOMFile) {
+    if (!xmlHttpRequest->mDOMBlob) {
       if (!xmlHttpRequest->mBlobSet) {
         xmlHttpRequest->mBlobSet = new BlobSet();
       }
       rv = xmlHttpRequest->mBlobSet->AppendVoidPtr(fromRawSegment, count);
     }
     // Clear the cache so that the blob size is updated.
     if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
       xmlHttpRequest->mResponseBlob = nullptr;
@@ -1894,31 +1894,31 @@ nsXMLHttpRequest::StreamReaderFunc(nsIIn
     *writeCount = count;
   } else {
     *writeCount = 0;
   }
 
   return rv;
 }
 
-bool nsXMLHttpRequest::CreateDOMFile(nsIRequest *request)
+bool nsXMLHttpRequest::CreateDOMBlob(nsIRequest *request)
 {
   nsCOMPtr<nsIFile> file;
   nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(request);
   if (fc) {
     fc->GetFile(getter_AddRefs(file));
   }
 
   if (!file)
     return false;
 
   nsAutoCString contentType;
   mChannel->GetContentType(contentType);
 
-  mDOMFile = File::CreateFromFile(GetOwner(), file, EmptyString(),
+  mDOMBlob = File::CreateFromFile(GetOwner(), file, EmptyString(),
                                   NS_ConvertASCIItoUTF16(contentType));
 
   mBlobSet = nullptr;
   NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
   return true;
 }
 
 NS_IMETHODIMP
@@ -1931,30 +1931,30 @@ nsXMLHttpRequest::OnDataAvailable(nsIReq
   NS_ENSURE_ARG_POINTER(inStr);
 
   MOZ_ASSERT(mContext.get() == ctxt,"start context different from OnDataAvailable context");
 
   mProgressSinceLastProgressEvent = true;
 
   bool cancelable = false;
   if ((mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
-       mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) && !mDOMFile) {
-    cancelable = CreateDOMFile(request);
+       mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) && !mDOMBlob) {
+    cancelable = CreateDOMBlob(request);
     // The nsIStreamListener contract mandates us
     // to read from the stream before returning.
   }
 
   uint32_t totalRead;
   nsresult rv = inStr->ReadSegments(nsXMLHttpRequest::StreamReaderFunc,
                                     (void*)this, count, &totalRead);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (cancelable) {
     // We don't have to read from the local file for the blob response
-    mDOMFile->GetSize(&mDataAvailable);
+    mDOMBlob->GetSize(&mDataAvailable);
     ChangeState(XML_HTTP_REQUEST_LOADING);
     return request->Cancel(NS_OK);
   }
 
   mDataAvailable += totalRead;
 
   ChangeState(XML_HTTP_REQUEST_LOADING);
   
@@ -2241,22 +2241,22 @@ nsXMLHttpRequest::OnStopRequest(nsIReque
   // until the parser is done.
   if (!mIsHtml) {
     MaybeDispatchProgressEvents(true);
   }
 
   if (NS_SUCCEEDED(status) &&
       (mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
        mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB)) {
-    if (!mDOMFile) {
-      CreateDOMFile(request);
+    if (!mDOMBlob) {
+      CreateDOMBlob(request);
     }
-    if (mDOMFile) {
-      mResponseBlob = mDOMFile;
-      mDOMFile = nullptr;
+    if (mDOMBlob) {
+      mResponseBlob = mDOMBlob;
+      mDOMBlob = nullptr;
     } else {
       // mBlobSet can be null if the channel is non-file non-cacheable
       // 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.
--- a/dom/base/nsXMLHttpRequest.h
+++ b/dom/base/nsXMLHttpRequest.h
@@ -46,18 +46,18 @@ class nsFormData;
 class nsIJARChannel;
 class nsILoadGroup;
 class nsIUnicodeDecoder;
 class nsIJSID;
 
 namespace mozilla {
 
 namespace dom {
+class Blob;
 class BlobSet;
-class File;
 }
 
 // A helper for building up an ArrayBuffer object's data
 // before creating the ArrayBuffer itself.  Will do doubling
 // based reallocation, up to an optional maximum growth given.
 //
 // When all the data has been appended, call getArrayBuffer,
 // passing in the JSContext* for which the ArrayBuffer object
@@ -347,17 +347,17 @@ 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(mozilla::dom::File& aBlob) : mType(Blob)
+    explicit RequestBody(mozilla::dom::Blob& aBlob) : mType(Blob)
     {
       mValue.mBlob = &aBlob;
     }
     explicit RequestBody(nsIDocument* aDocument) : mType(Document)
     {
       mValue.mDocument = aDocument;
     }
     explicit RequestBody(const nsAString& aString) : mType(DOMString)
@@ -381,17 +381,17 @@ private:
       Document,
       DOMString,
       FormData,
       InputStream
     };
     union Value {
       const mozilla::dom::ArrayBuffer* mArrayBuffer;
       const mozilla::dom::ArrayBufferView* mArrayBufferView;
-      mozilla::dom::File* mBlob;
+      mozilla::dom::Blob* mBlob;
       nsIDocument* mDocument;
       const nsAString* mString;
       nsFormData* mFormData;
       nsIInputStream* mStream;
     };
 
     Type GetType() const
     {
@@ -445,17 +445,17 @@ public:
     aRv = Send(RequestBody(&aArrayBuffer));
   }
   void Send(JSContext* /*aCx*/,
             const mozilla::dom::ArrayBufferView& aArrayBufferView,
             ErrorResult& aRv)
   {
     aRv = Send(RequestBody(&aArrayBufferView));
   }
-  void Send(JSContext* /*aCx*/, mozilla::dom::File& aBlob, ErrorResult& aRv)
+  void Send(JSContext* /*aCx*/, mozilla::dom::Blob& aBlob, ErrorResult& aRv)
   {
     aRv = Send(RequestBody(aBlob));
   }
   void Send(JSContext* /*aCx*/, nsIDocument& aDoc, ErrorResult& aRv)
   {
     aRv = Send(RequestBody(&aDoc));
   }
   void Send(JSContext* aCx, const nsAString& aString, ErrorResult& aRv)
@@ -601,17 +601,17 @@ protected:
   static NS_METHOD StreamReaderFunc(nsIInputStream* in,
                 void* closure,
                 const char* fromRawSegment,
                 uint32_t toOffset,
                 uint32_t count,
                 uint32_t *writeCount);
   nsresult CreateResponseParsedJSON(JSContext* aCx);
   void CreatePartialBlob();
-  bool CreateDOMFile(nsIRequest *request);
+  bool CreateDOMBlob(nsIRequest *request);
   // Change the state of the object with this. The broadcast argument
   // determines if the onreadystatechange listener should be called.
   nsresult ChangeState(uint32_t aState, bool aBroadcast = true);
   already_AddRefed<nsILoadGroup> GetLoadGroup() const;
   nsIURI *GetBaseURI();
 
   already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel();
   already_AddRefed<nsIJARChannel> GetCurrentJARChannel();
@@ -703,22 +703,22 @@ 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.
-  nsRefPtr<mozilla::dom::File> mResponseBlob;
+  nsRefPtr<mozilla::dom::Blob> 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::File> mDOMFile;
+  nsRefPtr<mozilla::dom::Blob> mDOMBlob;
   // We stream data to mBlobSet when response type is "blob" or "moz-blob"
-  // and mDOMFile is null.
+  // and mDOMBlob is null.
   nsAutoPtr<mozilla::dom::BlobSet> mBlobSet;
 
   nsString mOverrideMimeType;
 
   /**
    * The notification callbacks the channel had when Send() was
    * called.  We want to forward things here as needed.
    */
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -133,17 +133,16 @@ DOMInterfaces = {
     },
 },
 
 'BarProp': {
     'headerFile': 'mozilla/dom/BarProps.h',
 },
 
 'Blob': {
-    'nativeType': 'mozilla::dom::File',
     'headerFile': 'mozilla/dom/File.h',
 },
 
 'BatteryManager': {
     'nativeType': 'mozilla::dom::battery::BatteryManager',
     'headerFile': 'BatteryManager.h'
 },
 
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -207,17 +207,17 @@ public:
 
     SerializedStructuredCloneBuffer& buffer = message.data();
     buffer.data = mData->mBuffer.data();
     buffer.dataLength = mData->mBuffer.nbytes();
 
     PBackgroundChild* backgroundManager = mActor->Manager();
     MOZ_ASSERT(backgroundManager);
 
-    const nsTArray<nsRefPtr<File>>& blobs = mData->mClosure.mBlobs;
+    const nsTArray<nsRefPtr<Blob>>& blobs = mData->mClosure.mBlobs;
 
     if (!blobs.IsEmpty()) {
       message.blobsChild().SetCapacity(blobs.Length());
 
       for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
         PBlobChild* blobChild =
           BackgroundChild::GetOrCreateActorForBlob(backgroundManager, blobs[i]);
         MOZ_ASSERT(blobChild);
@@ -536,17 +536,17 @@ BroadcastChannel::PostMessageInternal(JS
 {
   nsRefPtr<BroadcastChannelMessage> data = new BroadcastChannelMessage();
 
   if (!WriteStructuredClone(aCx, aMessage, data->mBuffer, data->mClosure)) {
     aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
     return;
   }
 
-  const nsTArray<nsRefPtr<File>>& blobs = data->mClosure.mBlobs;
+  const nsTArray<nsRefPtr<Blob>>& blobs = data->mClosure.mBlobs;
   for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
     if (!blobs[i]->Impl()->MayBeClonedToOtherThreads()) {
       aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
       return;
     }
   }
 
   PostMessageData(data);
--- a/dom/broadcastchannel/BroadcastChannelChild.cpp
+++ b/dom/broadcastchannel/BroadcastChannelChild.cpp
@@ -37,26 +37,26 @@ BroadcastChannelChild::~BroadcastChannel
   MOZ_ASSERT(!mBC);
 }
 
 bool
 BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData)
 {
   // Make sure to retrieve all blobs from the message before returning to avoid
   // leaking their actors.
-  nsTArray<nsRefPtr<File>> files;
+  nsTArray<nsRefPtr<Blob>> blobs;
   if (!aData.blobsChild().IsEmpty()) {
-    files.SetCapacity(aData.blobsChild().Length());
+    blobs.SetCapacity(aData.blobsChild().Length());
 
     for (uint32_t i = 0, len = aData.blobsChild().Length(); i < len; ++i) {
       nsRefPtr<FileImpl> impl =
         static_cast<BlobChild*>(aData.blobsChild()[i])->GetBlobImpl();
 
-      nsRefPtr<File> file = new File(mBC ? mBC->GetOwner() : nullptr, impl);
-      files.AppendElement(file);
+      nsRefPtr<Blob> blob = Blob::Create(mBC ? mBC->GetOwner() : nullptr, impl);
+      blobs.AppendElement(blob);
     }
   }
 
   nsCOMPtr<DOMEventTargetHelper> helper = mBC;
   nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(helper);
 
   // This object has been already closed by content or is going to be deleted
   // soon. No notify is required.
@@ -87,17 +87,17 @@ BroadcastChannelChild::RecvNotify(const 
   }
 
   JSContext* cx = jsapi.cx();
 
   const SerializedStructuredCloneBuffer& buffer = aData.data();
   StructuredCloneData cloneData;
   cloneData.mData = buffer.data;
   cloneData.mDataLength = buffer.dataLength;
-  cloneData.mClosure.mBlobs.SwapElements(files);
+  cloneData.mClosure.mBlobs.SwapElements(blobs);
 
   JS::Rooted<JS::Value> value(cx, JS::NullValue());
   if (cloneData.mDataLength && !ReadStructuredClone(cx, cloneData, &value)) {
     JS_ClearPendingException(cx);
     return false;
   }
 
   RootedDictionary<MessageEventInit> init(cx);
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -1400,17 +1400,17 @@ nsDOMCameraControl::OnTakePictureComplet
   MOZ_ASSERT(aPicture);
 
   nsRefPtr<Promise> promise = mTakePicturePromise.forget();
   if (promise) {
     nsCOMPtr<nsIDOMBlob> picture = aPicture;
     promise->MaybeResolve(picture);
   }
 
-  nsRefPtr<File> blob = static_cast<File*>(aPicture);
+  nsRefPtr<Blob> blob = static_cast<Blob*>(aPicture);
   BlobEventInit eventInit;
   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
@@ -355,17 +355,17 @@ DOMCameraControlListener::OnTakePictureC
         mData = (uint8_t*) malloc(aLength);
         memcpy(mData, aData, aLength);
     }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) override
     {
       nsCOMPtr<nsIDOMBlob> picture =
-        File::CreateMemoryFile(mDOMCameraControl.get(),
+        Blob::CreateMemoryBlob(mDOMCameraControl.get(),
                                static_cast<void*>(mData),
                                static_cast<uint64_t>(mLength),
                                mMimeType);
       aDOMCameraControl->OnTakePictureComplete(picture);
       mData = NULL;
     }
 
   protected:
--- a/dom/devicestorage/DeviceStorage.h
+++ b/dom/devicestorage/DeviceStorage.h
@@ -24,16 +24,17 @@
 #define DEVICESTORAGE_CRASHES    "crashes"
 
 class nsIInputStream;
 class nsIOutputStream;
 
 namespace mozilla {
 class EventListenerManager;
 namespace dom {
+class Blob;
 struct DeviceStorageEnumerationParameters;
 class DOMCursor;
 class DOMRequest;
 class Promise;
 class DeviceStorageFileSystem;
 } // namespace dom
 namespace ipc {
 class FileDescriptor;
@@ -217,25 +218,26 @@ public:
     return GetOwner();
   }
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   IMPL_EVENT_HANDLER(change)
 
   already_AddRefed<DOMRequest>
-  Add(nsIDOMBlob* aBlob, ErrorResult& aRv);
+  Add(mozilla::dom::Blob* aBlob, ErrorResult& aRv);
   already_AddRefed<DOMRequest>
-  AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath, ErrorResult& aRv);
+  AddNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
-  AppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath, ErrorResult& aRv);
+  AppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
+              ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
-  AddOrAppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
+  AddOrAppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
                    const int32_t aRequestType, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
   Get(const nsAString& aPath, ErrorResult& aRv)
   {
     return GetInternal(aPath, false, aRv);
   }
   already_AddRefed<DOMRequest>
--- a/dom/devicestorage/DeviceStorageRequestChild.cpp
+++ b/dom/devicestorage/DeviceStorageRequestChild.cpp
@@ -100,17 +100,18 @@ DeviceStorageRequestChild::
       break;
     }
 
     case DeviceStorageResponseValue::TBlobResponse:
     {
       BlobResponse r = aValue;
       BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
       nsRefPtr<FileImpl> bloblImpl = actor->GetBlobImpl();
-      nsRefPtr<File> blob = new File(mRequest->GetParentObject(), bloblImpl);
+      nsRefPtr<Blob> blob = Blob::Create(mRequest->GetParentObject(),
+                                         bloblImpl);
 
       AutoJSContext cx;
 
       JS::Rooted<JSObject*> obj(cx, blob->WrapObject(cx, JS::NullPtr()));
       MOZ_ASSERT(obj);
 
       JS::Rooted<JS::Value> result(cx, JS::ObjectValue(*obj));
       mRequest->FireSuccess(result);
--- a/dom/devicestorage/DeviceStorageRequestParent.cpp
+++ b/dom/devicestorage/DeviceStorageRequestParent.cpp
@@ -518,22 +518,22 @@ nsresult
 DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsString mime;
   CopyASCIItoUTF16(mMimeType, mime);
 
   nsString fullPath;
   mFile->GetFullPath(fullPath);
-  nsRefPtr<File> blob = new File(nullptr,
+  nsRefPtr<FileImpl> blob =
     new FileImplFile(fullPath, mime, mLength, mFile->mFile,
-                     mLastModificationDate));
+                     mLastModificationDate);
 
   ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
-  BlobParent* actor = cp->GetOrCreateActorForBlob(blob);
+  BlobParent* actor = cp->GetOrCreateActorForFileImpl(blob);
   if (!actor) {
     ErrorResponse response(NS_LITERAL_STRING(POST_ERROR_EVENT_UNKNOWN));
     unused << mParent->Send__delete__(mParent, response);
     return NS_OK;
   }
 
   BlobResponse response;
   response.blobParent() = actor;
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -269,17 +269,17 @@ DeviceStorageTypeChecker::InitFromBundle
     getter_Copies(mMusicExtensions));
   aBundle->GetStringFromName(
     NS_ConvertASCIItoUTF16(DEVICESTORAGE_VIDEOS).get(),
     getter_Copies(mVideosExtensions));
 }
 
 
 bool
-DeviceStorageTypeChecker::Check(const nsAString& aType, nsIDOMBlob* aBlob)
+DeviceStorageTypeChecker::Check(const nsAString& aType, Blob* aBlob)
 {
   MOZ_ASSERT(aBlob);
 
   nsString mimeType;
   if (NS_FAILED(aBlob->GetType(mimeType))) {
     return false;
   }
 
@@ -1919,17 +1919,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 File(aWindow,
+  nsCOMPtr<nsIDOMBlob> blob = Blob::Create(aWindow,
     new FileImplFile(fullPath, aFile->mMimeType,
                      aFile->mLength, aFile->mFile,
                      aFile->mLastModifiedDate));
   return InterfaceToJsval(aWindow, blob, &NS_GET_IID(nsIDOMBlob));
 }
 
 bool
 StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString,
@@ -2871,17 +2871,17 @@ public:
     MOZ_ASSERT(mDeviceStorage);
   }
 
   DeviceStorageRequest(const DeviceStorageRequestType aRequestType,
                        nsPIDOMWindow* aWindow,
                        nsIPrincipal* aPrincipal,
                        DeviceStorageFile* aFile,
                        DOMRequest* aRequest,
-                       nsIDOMBlob* aBlob = nullptr)
+                       Blob* aBlob = nullptr)
     : mRequestType(aRequestType)
     , mWindow(aWindow)
     , mPrincipal(aPrincipal)
     , mFile(aFile)
     , mRequest(aRequest)
     , mBlob(aBlob)
     , mRequester(new nsContentPermissionRequester(mWindow))
   {
@@ -3043,17 +3043,17 @@ public:
           r = new PostErrorEvent(mRequest.forget(),
                                  POST_ERROR_EVENT_ILLEGAL_TYPE);
           return NS_DispatchToCurrentThread(r);
         }
 
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
           BlobChild* actor
             = ContentChild::GetSingleton()->GetOrCreateActorForBlob(
-              static_cast<File*>(mBlob.get()));
+              static_cast<Blob*>(mBlob.get()));
           if (!actor) {
             return NS_ERROR_FAILURE;
           }
 
           DeviceStorageAddParams params;
           params.blobChild() = actor;
           params.type() = mFile->mStorageType;
           params.storageName() = mFile->mStorageName;
@@ -3089,17 +3089,17 @@ public:
           r = new PostErrorEvent(mRequest.forget(),
                                  POST_ERROR_EVENT_ILLEGAL_TYPE);
           return NS_DispatchToCurrentThread(r);
         }
 
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
           BlobChild* actor
             = ContentChild::GetSingleton()->GetOrCreateActorForBlob(
-              static_cast<File*>(mBlob.get()));
+              static_cast<Blob*>(mBlob.get()));
           if (!actor) {
             return NS_ERROR_FAILURE;
           }
 
           DeviceStorageAppendParams params;
           params.blobChild() = actor;
           params.type() = mFile->mStorageType;
           params.storageName() = mFile->mStorageName;
@@ -3326,17 +3326,17 @@ private:
   ~DeviceStorageRequest() {}
 
   int32_t mRequestType;
   nsCOMPtr<nsPIDOMWindow> mWindow;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsRefPtr<DeviceStorageFile> mFile;
 
   nsRefPtr<DOMRequest> mRequest;
-  nsCOMPtr<nsIDOMBlob> mBlob;
+  nsRefPtr<Blob> mBlob;
   nsRefPtr<nsDOMDeviceStorage> mDeviceStorage;
   nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
   nsCOMPtr<nsIContentPermissionRequester> mRequester;
 };
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageRequest)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
   NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
@@ -3736,23 +3736,23 @@ nsDOMDeviceStorage::IsAvailable()
   nsRefPtr<DeviceStorageFile> dsf(new DeviceStorageFile(mStorageType, mStorageName));
   return dsf->IsAvailable();
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::Add(nsIDOMBlob *aBlob, nsIDOMDOMRequest * *_retval)
 {
   ErrorResult rv;
-  nsRefPtr<DOMRequest> request = Add(aBlob, rv);
+  nsRefPtr<DOMRequest> request = Add(static_cast<Blob*>(aBlob), rv);
   request.forget(_retval);
   return rv.StealNSResult();
 }
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::Add(nsIDOMBlob* aBlob, ErrorResult& aRv)
+nsDOMDeviceStorage::Add(Blob* aBlob, ErrorResult& aRv)
 {
   if (!aBlob) {
     return nullptr;
   }
 
   nsCOMPtr<nsIMIMEService> mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID);
   if (!mimeSvc) {
     aRv.Throw(NS_ERROR_FAILURE);
@@ -3785,40 +3785,40 @@ nsDOMDeviceStorage::Add(nsIDOMBlob* aBlo
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::AddNamed(nsIDOMBlob *aBlob,
                              const nsAString & aPath,
                              nsIDOMDOMRequest * *_retval)
 {
   ErrorResult rv;
-  nsRefPtr<DOMRequest> request = AddNamed(aBlob, aPath, rv);
+  nsRefPtr<DOMRequest> request = AddNamed(static_cast<Blob*>(aBlob), aPath, rv);
   request.forget(_retval);
   return rv.StealNSResult();
 }
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
+nsDOMDeviceStorage::AddNamed(Blob* aBlob, const nsAString& aPath,
                              ErrorResult& aRv)
 {
   return AddOrAppendNamed(aBlob, aPath,
                           DEVICE_STORAGE_REQUEST_CREATE, aRv);
 }
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::AppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
+nsDOMDeviceStorage::AppendNamed(Blob* aBlob, const nsAString& aPath,
                                 ErrorResult& aRv)
 {
   return AddOrAppendNamed(aBlob, aPath,
                           DEVICE_STORAGE_REQUEST_APPEND, aRv);
 }
 
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::AddOrAppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
+nsDOMDeviceStorage::AddOrAppendNamed(Blob* aBlob, const nsAString& aPath,
                                      const int32_t aRequestType, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // if the blob is null here, bail
   if (!aBlob) {
     return nullptr;
   }
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -28,16 +28,20 @@ class nsPIDOMWindow;
 #include "nsIStringBundle.h"
 #include "mozilla/Mutex.h"
 #include "prtime.h"
 #include "DeviceStorage.h"
 #include "mozilla/StaticPtr.h"
 
 namespace mozilla {
 class ErrorResult;
+
+namespace dom {
+class Blob;
+}
 } // namespace mozilla
 
 #define POST_ERROR_EVENT_FILE_EXISTS                 "NoModificationAllowedError"
 #define POST_ERROR_EVENT_FILE_DOES_NOT_EXIST         "NotFoundError"
 #define POST_ERROR_EVENT_FILE_NOT_ENUMERABLE         "TypeMismatchError"
 #define POST_ERROR_EVENT_PERMISSION_DENIED           "SecurityError"
 #define POST_ERROR_EVENT_ILLEGAL_TYPE                "TypeMismatchError"
 #define POST_ERROR_EVENT_UNKNOWN                     "Unknown"
@@ -152,17 +156,17 @@ class DeviceStorageTypeChecker final
 public:
   static DeviceStorageTypeChecker* CreateOrGet();
 
   DeviceStorageTypeChecker();
   ~DeviceStorageTypeChecker();
 
   void InitFromBundle(nsIStringBundle* aBundle);
 
-  bool Check(const nsAString& aType, nsIDOMBlob* aBlob);
+  bool Check(const nsAString& aType, mozilla::dom::Blob* aBlob);
   bool Check(const nsAString& aType, nsIFile* aFile);
   bool Check(const nsAString& aType, const nsString& aPath);
   void GetTypeFromFile(nsIFile* aFile, nsAString& aType);
   void GetTypeFromFileName(const nsAString& aFileName, nsAString& aType);
 
   static nsresult GetPermissionForType(const nsAString& aType, nsACString& aPermissionResult);
   static nsresult GetAccessForRequest(const DeviceStorageRequestType aRequestType, nsACString& aAccessResult);
   static bool IsVolumeBased(const nsAString& aType);
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -303,17 +303,21 @@ DataTransfer::GetFiles(ErrorResult& aRv)
       nsRefPtr<File> domFile;
       if (file) {
         domFile = File::CreateFromFile(GetParentObject(), file);
       } else {
         nsCOMPtr<FileImpl> fileImpl = do_QueryInterface(supports);
         if (!fileImpl) {
           continue;
         }
-        domFile = new File(GetParentObject(), static_cast<FileImpl*>(fileImpl.get()));
+
+        MOZ_ASSERT(fileImpl->IsFile());
+
+        domFile = File::Create(GetParentObject(), fileImpl);
+        MOZ_ASSERT(domFile);
       }
 
       if (!mFiles->Append(domFile)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return nullptr;
       }
     }
   }
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -441,20 +441,20 @@ ExtractFromArrayBufferView(const ArrayBu
   aBuffer.ComputeLengthAndData();
   //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
   return NS_NewByteInputStream(aStream,
                                reinterpret_cast<char*>(aBuffer.Data()),
                                aBuffer.Length(), NS_ASSIGNMENT_COPY);
 }
 
 nsresult
-ExtractFromBlob(const File& aFile, nsIInputStream** aStream,
+ExtractFromBlob(const Blob& aBlob, nsIInputStream** aStream,
                 nsCString& aContentType)
 {
-  nsRefPtr<FileImpl> impl = aFile.Impl();
+  nsRefPtr<FileImpl> impl = aBlob.Impl();
   nsresult rv = impl->GetInternalStream(aStream);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsAutoString type;
   impl->GetType(type);
   aContentType = NS_ConvertUTF16toUTF8(type);
@@ -768,17 +768,17 @@ private:
       body.BeginReading(bodyIter);
       body.EndReading(bodyEnd);
       char *p = copy;
       while (bodyIter != bodyEnd) {
         *p++ = *bodyIter++;
       }
       p = nullptr;
 
-      nsRefPtr<File> file =
+      nsRefPtr<Blob> file =
         File::CreateMemoryFile(mParentObject,
                                reinterpret_cast<void *>(copy), body.Length(),
                                NS_ConvertUTF8toUTF16(mFilename),
                                NS_ConvertUTF8toUTF16(mContentType), /* aLastModifiedDate */ 0);
       Optional<nsAString> dummy;
       mFormData->Append(name, *file, dummy);
     }
 
@@ -905,17 +905,17 @@ ExtractByteStreamFromBody(const OwningAr
 
   if (aBodyInit.IsArrayBuffer()) {
     const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
     return ExtractFromArrayBuffer(buf, aStream);
   } else if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream);
   } else if (aBodyInit.IsBlob()) {
-    const File& blob = aBodyInit.GetAsBlob();
+    const Blob& blob = aBodyInit.GetAsBlob();
     return ExtractFromBlob(blob, aStream, aContentType);
   } else if (aBodyInit.IsFormData()) {
     nsFormData& form = aBodyInit.GetAsFormData();
     return ExtractFromFormData(form, aStream, aContentType);
   } else if (aBodyInit.IsUSVString()) {
     nsAutoString str;
     str.Assign(aBodyInit.GetAsUSVString());
     return ExtractFromUSVString(str, aStream, aContentType);
@@ -937,17 +937,17 @@ ExtractByteStreamFromBody(const ArrayBuf
 
   if (aBodyInit.IsArrayBuffer()) {
     const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
     return ExtractFromArrayBuffer(buf, aStream);
   } else if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream);
   } else if (aBodyInit.IsBlob()) {
-    const File& blob = aBodyInit.GetAsBlob();
+    const Blob& blob = aBodyInit.GetAsBlob();
     return ExtractFromBlob(blob, aStream, aContentType);
   } else if (aBodyInit.IsFormData()) {
     nsFormData& form = aBodyInit.GetAsFormData();
     return ExtractFromFormData(form, aStream, aContentType);
   } else if (aBodyInit.IsUSVString()) {
     nsAutoString str;
     str.Assign(aBodyInit.GetAsUSVString());
     return ExtractFromUSVString(str, aStream, aContentType);
@@ -1502,19 +1502,20 @@ FetchBody<Derived>::ContinueConsumeBody(
       JS::Rooted<JS::Value> val(cx);
       val.setObjectOrNull(arrayBuffer);
       localPromise->MaybeResolve(cx, val);
       // ArrayBuffer takes over ownership.
       autoFree.Reset();
       return;
     }
     case CONSUME_BLOB: {
-      nsRefPtr<File> blob =
-        File::CreateMemoryFile(DerivedClass()->GetParentObject(),
-                               reinterpret_cast<void *>(aResult), aResultLength, NS_ConvertUTF8toUTF16(mMimeType));
+      nsRefPtr<dom::Blob> blob =
+        Blob::CreateMemoryBlob(DerivedClass()->GetParentObject(),
+                               reinterpret_cast<void *>(aResult), aResultLength,
+                               NS_ConvertUTF8toUTF16(mMimeType));
 
       if (!blob) {
         localPromise->MaybeReject(NS_ERROR_DOM_UNKNOWN_ERR);
         return;
       }
 
       localPromise->MaybeResolve(blob);
       // File takes over ownership.
--- a/dom/filehandle/FileHandle.cpp
+++ b/dom/filehandle/FileHandle.cpp
@@ -617,20 +617,20 @@ FileHandleBase::GetInputStream(const Arr
   }
 
   *aInputLength = length;
   return stream.forget();
 }
 
 // static
 already_AddRefed<nsIInputStream>
-FileHandleBase::GetInputStream(const File& aValue, uint64_t* aInputLength,
+FileHandleBase::GetInputStream(const Blob& aValue, uint64_t* aInputLength,
                                ErrorResult& aRv)
 {
-  File& file = const_cast<File&>(aValue);
+  Blob& file = const_cast<Blob&>(aValue);
   uint64_t length = file.GetSize(aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   nsCOMPtr<nsIInputStream> stream;
   aRv = file.GetInternalStream(getter_AddRefs(stream));
   if (aRv.Failed()) {
--- a/dom/filehandle/FileHandle.h
+++ b/dom/filehandle/FileHandle.h
@@ -20,17 +20,17 @@
 #include "nsIRunnable.h"
 #include "nsTArray.h"
 
 class nsAString;
 
 namespace mozilla {
 namespace dom {
 
-class File;
+class Blob;
 class FileHelper;
 class FileRequestBase;
 class FileService;
 class FinishHelper;
 class MetadataHelper;
 class MutableFileBase;
 
 /**
@@ -235,17 +235,17 @@ protected:
   nsresult
   Finish();
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(const ArrayBuffer& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 
   static already_AddRefed<nsIInputStream>
-  GetInputStream(const File& aValue, uint64_t* aInputLength,
+  GetInputStream(const Blob& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(const nsAString& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 };
 
 class FinishHelper 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,
-                               File* aBlobData,
+                               Blob* aBlobData,
                                InfallibleTArray<uint8_t>& aArrayData,
                                bool replace,
                                ErrorResult& aRv)
   : FileSystemTaskBase(aFileSystem)
   , mTargetRealPath(aPath)
   , mReplace(replace)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
@@ -122,19 +122,17 @@ CreateFileTask::GetRequestParams(const n
   }
   return param;
 }
 
 FileSystemResponseValue
 CreateFileTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
-  nsRefPtr<File> file = new File(mFileSystem->GetWindow(),
-                                       mTargetFileImpl);
-  BlobParent* actor = GetBlobParent(file);
+  BlobParent* actor = GetBlobParent(mTargetFileImpl);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
 
@@ -298,18 +296,18 @@ CreateFileTask::HandlerCallback()
     nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
       mErrorValue);
     mPromise->MaybeRejectBrokenly(domError);
     mPromise = nullptr;
     mBlobData = nullptr;
     return;
   }
 
-  nsCOMPtr<nsIDOMFile> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
-  mPromise->MaybeResolve(file);
+  nsRefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetFileImpl);
+  mPromise->MaybeResolve(blob);
   mPromise = nullptr;
   mBlobData = nullptr;
 }
 
 void
 CreateFileTask::GetPermissionAccessType(nsCString& aAccess) const
 {
   if (mReplace) {
--- a/dom/filesystem/CreateFileTask.h
+++ b/dom/filesystem/CreateFileTask.h
@@ -11,27 +11,27 @@
 #include "nsAutoPtr.h"
 #include "mozilla/ErrorResult.h"
 
 class nsIInputStream;
 
 namespace mozilla {
 namespace dom {
 
-class File;
+class Blob;
 class FileImpl;
 class Promise;
 
 class CreateFileTask final
   : public FileSystemTaskBase
 {
 public:
   CreateFileTask(FileSystemBase* aFileSystem,
                  const nsAString& aPath,
-                 File* aBlobData,
+                 Blob* 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.
-  nsRefPtr<File> mBlobData;
+  nsRefPtr<Blob> mBlobData;
 
   nsCOMPtr<nsIInputStream> mBlobStream;
   InfallibleTArray<uint8_t> mArrayData;
   bool mReplace;
 
   // This cannot be a File because this object is created on a different
   // thread and File is not thread-safe. Let's use the FileImpl instead.
   nsRefPtr<FileImpl> mTargetFileImpl;
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -95,17 +95,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<File> blobData;
+  nsRefPtr<Blob> 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());
--- a/dom/filesystem/FileSystemTaskBase.cpp
+++ b/dom/filesystem/FileSystemTaskBase.cpp
@@ -149,33 +149,43 @@ bool
 FileSystemTaskBase::Recv__delete__(const FileSystemResponseValue& aValue)
 {
   SetRequestResult(aValue);
   HandlerCallback();
   return true;
 }
 
 BlobParent*
-FileSystemTaskBase::GetBlobParent(nsIDOMFile* aFile) const
+FileSystemTaskBase::GetBlobParent(FileImpl* aFile) const
 {
   MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
              "Only call from parent process!");
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   MOZ_ASSERT(aFile);
 
   // Load the lazy dom file data from the parent before sending to the child.
   nsString mimeType;
   aFile->GetType(mimeType);
-  uint64_t fileSize;
-  aFile->GetSize(&fileSize);
-  int64_t lastModifiedDate;
-  aFile->GetMozLastModifiedDate(&lastModifiedDate);
+
+  // We call GetSize and GetLastModified to prepopulate the value in the
+  // FileImpl.
+  {
+    ErrorResult rv;
+    aFile->GetSize(rv);
+    rv.SuppressException();
+  }
+
+  {
+    ErrorResult rv;
+    aFile->GetLastModified(rv);
+    rv.SuppressException();
+  }
 
   ContentParent* cp = static_cast<ContentParent*>(mRequestParent->Manager());
-  return cp->GetOrCreateActorForBlob(static_cast<File*>(aFile));
+  return cp->GetOrCreateActorForFileImpl(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/FileSystemTaskBase.h
+++ b/dom/filesystem/FileSystemTaskBase.h
@@ -6,22 +6,21 @@
 
 #ifndef mozilla_dom_FileSystemTaskBase_h
 #define mozilla_dom_FileSystemTaskBase_h
 
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/FileSystemRequestParent.h"
 #include "mozilla/dom/PFileSystemRequestChild.h"
 
-class nsIDOMFile;
-
 namespace mozilla {
 namespace dom {
 
 class BlobParent;
+class FileImpl;
 class FileSystemBase;
 class FileSystemParams;
 
 /*
  * The base class to implement a Task class.
  * The task is used to handle the OOP (out of process) operations.
  * The file system operations can only be performed in the parent process. When
  * performing such a parent-process-only operation, a task will delivered the
@@ -200,17 +199,17 @@ protected:
   bool
   HasError() const { return mErrorValue != NS_OK; }
 
   // Overrides PFileSystemRequestChild
   virtual bool
   Recv__delete__(const FileSystemResponseValue& value) override;
 
   BlobParent*
-  GetBlobParent(nsIDOMFile* aFile) const;
+  GetBlobParent(FileImpl* aFile) const;
 
   nsresult mErrorValue;
 
   nsRefPtr<FileSystemBase> mFileSystem;
   nsRefPtr<FileSystemRequestParent> mRequestParent;
 private:
   /*
    * After finishing the task operation, handle the task result.
--- a/dom/filesystem/GetFileOrDirectoryTask.cpp
+++ b/dom/filesystem/GetFileOrDirectoryTask.cpp
@@ -77,18 +77,17 @@ GetFileOrDirectoryTask::GetRequestParams
 FileSystemResponseValue
 GetFileOrDirectoryTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mIsDirectory) {
     return FileSystemDirectoryResponse(mTargetRealPath);
   }
 
-  nsRefPtr<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
-  BlobParent* actor = GetBlobParent(file);
+  BlobParent* actor = GetBlobParent(mTargetFileImpl);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
 
@@ -209,18 +208,18 @@ GetFileOrDirectoryTask::HandlerCallback(
 
   if (mIsDirectory) {
     nsRefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
     mPromise->MaybeResolve(dir);
     mPromise = nullptr;
     return;
   }
 
-  nsRefPtr<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
-  mPromise->MaybeResolve(file);
+  nsRefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetFileImpl);
+  mPromise->MaybeResolve(blob);
   mPromise = nullptr;
 }
 
 void
 GetFileOrDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
 {
   aAccess.AssignLiteral("read");
 }
--- a/dom/filesystem/RemoveTask.cpp
+++ b/dom/filesystem/RemoveTask.cpp
@@ -87,19 +87,20 @@ 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<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
+    nsRefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(),
+                                       mTargetFileImpl);
     BlobChild* actor
-      = ContentChild::GetSingleton()->GetOrCreateActorForBlob(file);
+      = ContentChild::GetSingleton()->GetOrCreateActorForBlob(blob);
     if (actor) {
       param.target() = actor;
     }
   } else {
     param.target() = mTargetRealPath;
   }
   return param;
 }
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -550,29 +550,29 @@ HTMLCanvasElement::ToBlob(JSContext* aCx
   class EncodeCallback : public EncodeCompleteCallback
   {
   public:
     EncodeCallback(nsIGlobalObject* aGlobal, FileCallback* aCallback)
       : mGlobal(aGlobal)
       , mFileCallback(aCallback) {}
 
     // This is called on main thread.
-    nsresult ReceiveBlob(already_AddRefed<File> aBlob)
+    nsresult ReceiveBlob(already_AddRefed<Blob> aBlob)
     {
-      nsRefPtr<File> blob = aBlob;
+      nsRefPtr<Blob> blob = aBlob;
       uint64_t size;
       nsresult rv = blob->GetSize(&size);
       if (NS_SUCCEEDED(rv)) {
         AutoJSAPI jsapi;
         if (jsapi.Init(mGlobal)) {
           JS_updateMallocCounter(jsapi.cx(), size);
         }
       }
 
-      nsRefPtr<File> newBlob = new File(mGlobal, blob->Impl());
+      nsRefPtr<Blob> newBlob = Blob::Create(mGlobal, blob->Impl());
 
       mozilla::ErrorResult error;
       mFileCallback->Call(*newBlob, error);
 
       mGlobal = nullptr;
       mFileCallback = nullptr;
 
       return error.StealNSResult();
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -556,17 +556,18 @@ public:
     if (mCanceled) { // The last progress event may have canceled us
       return NS_OK;
     }
 
     // Recreate File 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 File(global, mFileList[i]->Impl());
+      mFileList[i] = File::Create(global, mFileList[i]->Impl());
+      MOZ_ASSERT(mFileList[i]);
     }
 
     // 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(),
@@ -2342,17 +2343,20 @@ HTMLInputElement::MozSetFileArray(const 
 {
   nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
   MOZ_ASSERT(global);
   if (!global) {
     return;
   }
   nsTArray<nsRefPtr<File>> files;
   for (uint32_t i = 0; i < aFiles.Length(); ++i) {
-    files.AppendElement(new File(global, aFiles[i].get()->Impl()));
+    nsRefPtr<File> file = File::Create(global, aFiles[i].get()->Impl());
+    MOZ_ASSERT(file);
+
+    files.AppendElement(file);
   }
   SetFiles(files, true);
 }
 
 void
 HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv)
 {
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
@@ -6013,17 +6017,19 @@ HTMLInputElement::RestoreState(nsPresSta
         {
           const nsTArray<nsRefPtr<FileImpl>>& fileImpls = inputState->GetFileImpls();
 
           nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
           MOZ_ASSERT(global);
 
           nsTArray<nsRefPtr<File>> files;
           for (uint32_t i = 0, len = fileImpls.Length(); i < len; ++i) {
-            nsRefPtr<File> file = new File(global, fileImpls[i]);
+            nsRefPtr<File> file = File::Create(global, fileImpls[i]);
+            MOZ_ASSERT(file);
+
             files.AppendElement(file);
           }
 
           SetFiles(files, true);
         }
         break;
       case VALUE_MODE_VALUE:
       case VALUE_MODE_DEFAULT:
--- a/dom/html/nsFormSubmission.cpp
+++ b/dom/html/nsFormSubmission.cpp
@@ -72,21 +72,22 @@ public:
     : nsEncodingFormSubmission(aCharset, aOriginatingElement),
       mMethod(aMethod),
       mDocument(aDocument),
       mWarnedFileControl(false)
   {
   }
 
   virtual nsresult AddNameValuePair(const nsAString& aName,
-                                    const nsAString& aValue);
+                                    const nsAString& aValue) override;
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   File* aBlob);
+                                   File* aFile) override;
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
-                                        nsIInputStream** aPostDataStream);
+                                        nsIInputStream** aPostDataStream)
+                                                                       override;
 
   virtual bool SupportsIsindexSubmission()
   {
     return true;
   }
 
   virtual nsresult AddIsindex(const nsAString& aValue);
 
@@ -160,26 +161,26 @@ nsFSURLEncoded::AddIsindex(const nsAStri
     mQueryString += NS_LITERAL_CSTRING("&isindex=") + convValue;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsFSURLEncoded::AddNameFilePair(const nsAString& aName,
-                                File* aBlob)
+                                File* aFile)
 {
   if (!mWarnedFileControl) {
     SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nullptr, 0);
     mWarnedFileControl = true;
   }
 
   nsAutoString filename;
-  if (aBlob && aBlob->IsFile()) {
-    aBlob->GetName(filename);
+  if (aFile) {
+    aFile->GetName(filename);
   }
 
   return AddNameValuePair(aName, filename);
 }
 
 static void
 HandleMailtoSubject(nsCString& aPath) {
 
@@ -434,62 +435,59 @@ nsFSMultipartFormData::AddNameValuePair(
                  + nameStr + NS_LITERAL_CSTRING("\"" CRLF CRLF)
                  + valueStr + NS_LITERAL_CSTRING(CRLF);
 
   return NS_OK;
 }
 
 nsresult
 nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
-                                       File* aBlob)
+                                       File* aFile)
 {
   // Encode the control name
   nsAutoCString nameStr;
   nsresult rv = EncodeVal(aName, nameStr, true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCString filename, contentType;
   nsCOMPtr<nsIInputStream> fileStream;
-  if (aBlob) {
-    // Since Bug 1127150, any Blob received from FormData must be a File
-    // instance with a valid name (possibly "blob").
-    MOZ_ASSERT(aBlob->IsFile());
+  if (aFile) {
     nsAutoString filename16;
-    rv = aBlob->GetName(filename16);
+    rv = aFile->GetName(filename16);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsAutoString filepath16;
-    rv = aBlob->GetPath(filepath16);
+    rv = aFile->GetPath(filepath16);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     if (!filepath16.IsEmpty()) {
       // File.path includes trailing "/"
       filename16 = filepath16 + filename16;
     }
 
     rv = EncodeVal(filename16, filename, true);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Get content type
     nsAutoString contentType16;
-    rv = aBlob->GetType(contentType16);
+    rv = aFile->GetType(contentType16);
     if (NS_FAILED(rv) || contentType16.IsEmpty()) {
       contentType16.AssignLiteral("application/octet-stream");
     }
     contentType.Adopt(nsLinebreakConverter::
                       ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(),
                                         nsLinebreakConverter::eLinebreakAny,
                                         nsLinebreakConverter::eLinebreakSpace));
 
     // Get input stream
-    rv = aBlob->GetInternalStream(getter_AddRefs(fileStream));
+    rv = aFile->GetInternalStream(getter_AddRefs(fileStream));
     NS_ENSURE_SUCCESS(rv, rv);
     if (fileStream) {
       // Create buffered stream (for efficiency)
       nsCOMPtr<nsIInputStream> bufferedStream;
       rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
                                      fileStream, 8192);
       NS_ENSURE_SUCCESS(rv, rv);
 
@@ -514,17 +512,17 @@ nsFSMultipartFormData::AddNameFilePair(c
        + nameStr + NS_LITERAL_CSTRING("\"; filename=\"")
        + filename + NS_LITERAL_CSTRING("\"" CRLF)
        + NS_LITERAL_CSTRING("Content-Type: ")
        + contentType + NS_LITERAL_CSTRING(CRLF CRLF);
 
   // We should not try to append an invalid stream. That will happen for example
   // if we try to update a file that actually do not exist.
   uint64_t size;
-  if (fileStream && NS_SUCCEEDED(aBlob->GetSize(&size))) {
+  if (fileStream && NS_SUCCEEDED(aFile->GetSize(&size))) {
     // We need to dump the data up to this point into the POST data stream here,
     // since we're about to add the file input stream
     AddPostDataStream();
 
     mPostDataStream->AppendStream(fileStream);
     mTotalLength += size;
   }
 
@@ -582,21 +580,22 @@ class nsFSTextPlain : public nsEncodingF
 {
 public:
   nsFSTextPlain(const nsACString& aCharset, nsIContent* aOriginatingElement)
     : nsEncodingFormSubmission(aCharset, aOriginatingElement)
   {
   }
 
   virtual nsresult AddNameValuePair(const nsAString& aName,
-                                    const nsAString& aValue);
+                                    const nsAString& aValue) override;
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   File* aBlob);
+                                   File* aFile) override;
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
-                                        nsIInputStream** aPostDataStream);
+                                        nsIInputStream** aPostDataStream)
+                                                                       override;
 
 private:
   nsString mBody;
 };
 
 nsresult
 nsFSTextPlain::AddNameValuePair(const nsAString& aName,
                                 const nsAString& aValue)
@@ -607,21 +606,21 @@ nsFSTextPlain::AddNameValuePair(const ns
   mBody.Append(aName + NS_LITERAL_STRING("=") + aValue +
                NS_LITERAL_STRING(CRLF));
 
   return NS_OK;
 }
 
 nsresult
 nsFSTextPlain::AddNameFilePair(const nsAString& aName,
-                               File* aBlob)
+                               File* aFile)
 {
   nsAutoString filename;
-  if (aBlob && aBlob->IsFile()) {
-    aBlob->GetName(filename);
+  if (aFile) {
+    aFile->GetName(filename);
   }
 
   AddNameValuePair(aName, filename);
   return NS_OK;
 }
 
 nsresult
 nsFSTextPlain::GetEncodedSubmission(nsIURI* aURI,
--- a/dom/html/nsFormSubmission.h
+++ b/dom/html/nsFormSubmission.h
@@ -43,20 +43,20 @@ public:
    */
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) = 0;
 
   /**
    * Submit a name/file pair
    *
    * @param aName the name of the parameter
-   * @param aBlob the file to submit. The file's name will be used
+   * @param aFile the file to submit. The file's name will be used
    */
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   mozilla::dom::File* aBlob) = 0;
+                                   mozilla::dom::File* aFile) = 0;
 
   /**
    * Reports whether the instance supports AddIsindex().
    *
    * @return true if supported.
    */
   virtual bool SupportsIsindexSubmission()
   {
@@ -155,17 +155,17 @@ public:
    */
   nsFSMultipartFormData(const nsACString& aCharset,
                         nsIContent* aOriginatingElement);
   ~nsFSMultipartFormData();
  
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) override;
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   mozilla::dom::File* aBlob) override;
+                                   mozilla::dom::File* aFile) override;
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream) override;
 
   void GetContentType(nsACString& aContentType)
   {
     aContentType =
       NS_LITERAL_CSTRING("multipart/form-data; boundary=") + mBoundary;
   }
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -609,34 +609,34 @@ ConvertActorsToBlobs(IDBDatabase* aDatab
     aFiles.SetCapacity(count);
 
     for (uint32_t index = 0; index < count; index++) {
       BlobChild* actor = static_cast<BlobChild*>(blobs[index]);
 
       nsRefPtr<FileImpl> blobImpl = actor->GetBlobImpl();
       MOZ_ASSERT(blobImpl);
 
-      nsRefPtr<File> blob = new File(aDatabase->GetOwner(), blobImpl);
+      nsRefPtr<Blob> blob = Blob::Create(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);
 
         blob->AddFileInfo(fileInfo);
       }
 
       aDatabase->NoteReceivedBlob(blob);
 
       StructuredCloneFile* file = aFiles.AppendElement();
       MOZ_ASSERT(file);
 
-      file->mFile.swap(blob);
+      file->mBlob.swap(blob);
       file->mFileInfo.swap(fileInfo);
     }
   }
 }
 
 void
 DispatchErrorEvent(IDBRequest* aRequest,
                    nsresult aErrorCode,
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -7713,16 +7713,17 @@ public:
     //   2. The nsExternalHelperAppService guesses the content type based only
     //      on the file extension. Our stored files have no extension so the
     //      current code path fails and sets the content type to the empty
     //      string.
     //
     // So, this is a hack to keep the nsExternalHelperAppService out of the
     // picture entirely. Eventually we should probably fix this some other way.
     mContentType.Truncate();
+    mIsFile = false;
   }
 
 private:
   ~NonMainThreadHackBlobImpl()
   { }
 };
 
 class QuotaClient final
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -954,17 +954,17 @@ IDBDatabase::AbortTransactions(bool aSho
       transaction->GetCallerLocation(filename, &lineNo);
 
       LogWarning(kWarningMessage, filename, lineNo);
     }
   }
 }
 
 PBackgroundIDBDatabaseFileChild*
-IDBDatabase::GetOrCreateFileActorForBlob(File* aBlob)
+IDBDatabase::GetOrCreateFileActorForBlob(Blob* aBlob)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aBlob);
   MOZ_ASSERT(mBackgroundActor);
 
   // We use the File'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 File
@@ -1063,17 +1063,17 @@ IDBDatabase::NoteFinishedFileActor(PBack
       return PL_DHASH_NEXT;
     }
   };
 
   mFileActors.Enumerate(&Helper::Remove, aFileActor);
 }
 
 void
-IDBDatabase::NoteReceivedBlob(File* aBlob)
+IDBDatabase::NoteReceivedBlob(Blob* aBlob)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aBlob);
   MOZ_ASSERT(mBackgroundActor);
 
 #ifdef DEBUG
   {
     nsRefPtr<FileImpl> blobImpl = aBlob->Impl();
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -23,17 +23,17 @@ class nsPIDOMWindow;
 
 namespace mozilla {
 
 class ErrorResult;
 class EventChainPostVisitor;
 
 namespace dom {
 
-class File;
+class Blob;
 class DOMStringList;
 struct IDBObjectStoreParameters;
 template <class> class Optional;
 class StringOrStringSequence;
 
 namespace indexedDB {
 
 class BackgroundDatabaseChild;
@@ -172,23 +172,23 @@ public:
 
   void
   UnregisterTransaction(IDBTransaction* aTransaction);
 
   void
   AbortTransactions(bool aShouldWarn);
 
   PBackgroundIDBDatabaseFileChild*
-  GetOrCreateFileActorForBlob(File* aBlob);
+  GetOrCreateFileActorForBlob(Blob* aBlob);
 
   void
   NoteFinishedFileActor(PBackgroundIDBDatabaseFileChild* aFileActor);
 
   void
-  NoteReceivedBlob(File* aBlob);
+  NoteReceivedBlob(Blob* 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
@@ -335,18 +335,20 @@ IDBMutableFile::CreateFileObject(IDBFile
   nsRefPtr<FileImpl> impl =
     new FileImplSnapshot(mName,
                          mType,
                          aMetadataParams,
                          mFile,
                          aFileHandle,
                          mFileInfo);
 
-  nsCOMPtr<nsIDOMFile> fileSnapshot = new File(GetOwner(), impl);
-  return fileSnapshot.forget();
+  nsRefPtr<File> file = File::Create(GetOwner(), impl);
+  MOZ_ASSERT(file);
+
+  return file.forget();
 }
 
 already_AddRefed<DOMRequest>
 IDBMutableFile::GetFile(ErrorResult& aError)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (QuotaManager::IsShuttingDown() || FileService::IsShuttingDown()) {
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -57,17 +57,17 @@ namespace indexedDB {
 using namespace mozilla::dom::quota;
 using namespace mozilla::dom::workers;
 using namespace mozilla::ipc;
 
 struct IDBObjectStore::StructuredCloneWriteInfo
 {
   struct BlobOrFileInfo
   {
-    nsRefPtr<File> mBlob;
+    nsRefPtr<Blob> mBlob;
     nsRefPtr<FileInfo> mFileInfo;
 
     bool
     operator==(const BlobOrFileInfo& aOther) const
     {
       return this->mBlob == aOther.mBlob && this->mFileInfo == aOther.mFileInfo;
     }
   };
@@ -295,17 +295,17 @@ StructuredCloneWriteCallback(JSContext* 
       newBlobOrFileInfo =
         cloneWriteInfo->mBlobOrFileInfos.AppendElement();
     newBlobOrFileInfo->mFileInfo.swap(fileInfo);
 
     return true;
   }
 
   {
-    File* blob = nullptr;
+    Blob* 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)));
@@ -327,25 +327,26 @@ StructuredCloneWriteCallback(JSContext* 
                               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 (blob->IsFile()) {
+      nsRefPtr<File> file = blob->ToFile();
+      if (file) {
         int64_t lastModifiedDate;
         MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
-          blob->GetMozLastModifiedDate(&lastModifiedDate)));
+          file->GetMozLastModifiedDate(&lastModifiedDate)));
 
         lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate);
 
         nsString name;
-        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetName(name)));
+        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(file->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())) {
@@ -397,21 +398,21 @@ GetAddInfoCallback(JSContext* aCx, void*
                                                 &data->mCloneWriteInfo)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   return NS_OK;
 }
 
 BlobChild*
-ActorFromRemoteBlob(File* aBlob)
+ActorFromRemoteFileImpl(FileImpl* aImpl)
 {
-  MOZ_ASSERT(aBlob);
+  MOZ_ASSERT(aImpl);
 
-  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob->Impl());
+  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aImpl);
   if (remoteBlob) {
     BlobChild* actor = remoteBlob->GetBlobChild();
     MOZ_ASSERT(actor);
 
     if (actor->GetContentManager()) {
       return nullptr;
     }
 
@@ -423,36 +424,36 @@ ActorFromRemoteBlob(File* aBlob)
 
     return actor;
   }
 
   return nullptr;
 }
 
 bool
-ResolveMysteryFile(File* aBlob,
+ResolveMysteryFile(FileImpl* aImpl,
                    const nsString& aName,
                    const nsString& aContentType,
                    uint64_t aSize,
                    uint64_t aLastModifiedDate)
 {
-  BlobChild* actor = ActorFromRemoteBlob(aBlob);
+  BlobChild* actor = ActorFromRemoteFileImpl(aImpl);
   if (actor) {
     return actor->SetMysteryBlobInfo(aName, aContentType,
                                      aSize, aLastModifiedDate);
   }
   return true;
 }
 
 bool
-ResolveMysteryBlob(File* aBlob,
+ResolveMysteryBlob(FileImpl* aImpl,
                    const nsString& aContentType,
                    uint64_t aSize)
 {
-  BlobChild* actor = ActorFromRemoteBlob(aBlob);
+  BlobChild* actor = ActorFromRemoteFileImpl(aImpl);
   if (actor) {
     return actor->SetMysteryBlobInfo(aContentType, aSize);
   }
   return true;
 }
 
 bool
 StructuredCloneReadString(JSStructuredCloneReader* aReader,
@@ -600,17 +601,17 @@ public:
                           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(aFile.mBlob);
 
     // 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 File object.
     nsCOMPtr<nsISupports> parent;
     if (NS_IsMainThread()) {
       if (aDatabase && aDatabase->GetParentObject()) {
         parent = aDatabase->GetParentObject();
       } else {
@@ -622,46 +623,49 @@ public:
 
       WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
       MOZ_ASSERT(globalScope);
 
       parent = do_QueryObject(globalScope);
     }
 
     MOZ_ASSERT(parent);
-    nsRefPtr<File> file = new File(parent, aFile.mFile->Impl());
 
     if (aData.tag == SCTAG_DOM_BLOB) {
-      if (NS_WARN_IF(!ResolveMysteryBlob(aFile.mFile,
+      if (NS_WARN_IF(!ResolveMysteryBlob(aFile.mBlob->Impl(),
                                          aData.type,
                                          aData.size))) {
         return false;
       }
 
+      MOZ_ASSERT(!aFile.mBlob->IsFile());
+
       JS::Rooted<JS::Value> wrappedBlob(aCx);
-      if (!GetOrCreateDOMReflector(aCx, aFile.mFile, &wrappedBlob)) {
+      if (!ToJSValue(aCx, aFile.mBlob, &wrappedBlob)) {
         return false;
       }
 
       aResult.set(&wrappedBlob.toObject());
       return true;
     }
 
-    MOZ_ASSERT(aFile.mFile->IsFile());
-
-    if (NS_WARN_IF(!ResolveMysteryFile(aFile.mFile,
+    if (NS_WARN_IF(!ResolveMysteryFile(aFile.mBlob->Impl(),
                                        aData.name,
                                        aData.type,
                                        aData.size,
                                        aData.lastModifiedDate))) {
       return false;
     }
 
+    MOZ_ASSERT(aFile.mBlob->IsFile());
+    nsRefPtr<File> file = aFile.mBlob->ToFile();
+    MOZ_ASSERT(file);
+
     JS::Rooted<JS::Value> wrappedFile(aCx);
-    if (!GetOrCreateDOMReflector(aCx, aFile.mFile, &wrappedFile)) {
+    if (!ToJSValue(aCx, file, &wrappedFile)) {
       return false;
     }
 
     aResult.set(&wrappedFile.toObject());
     return true;
   }
 };
 
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -10,27 +10,27 @@
 #include "js/StructuredClone.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 
-class File;
+class Blob;
 
 namespace indexedDB {
 
 class FileInfo;
 class IDBDatabase;
 class SerializedStructuredCloneReadInfo;
 
 struct StructuredCloneFile
 {
-  nsRefPtr<File> mFile;
+  nsRefPtr<Blob> mBlob;
   nsRefPtr<FileInfo> mFileInfo;
 
   // In IndexedDatabaseInlines.h
   inline
   StructuredCloneFile();
 
   // In IndexedDatabaseInlines.h
   inline
--- a/dom/indexedDB/IndexedDatabaseInlines.h
+++ b/dom/indexedDB/IndexedDatabaseInlines.h
@@ -31,17 +31,17 @@ StructuredCloneFile::~StructuredCloneFil
 {
   MOZ_COUNT_DTOR(StructuredCloneFile);
 }
 
 inline
 bool
 StructuredCloneFile::operator==(const StructuredCloneFile& aOther) const
 {
-  return this->mFile == aOther.mFile &&
+  return this->mBlob == aOther.mBlob &&
          this->mFileInfo == aOther.mFileInfo;
 }
 
 inline
 StructuredCloneReadInfo::StructuredCloneReadInfo()
   : mDatabase(nullptr)
 {
   MOZ_COUNT_CTOR(StructuredCloneReadInfo);
--- a/dom/ipc/FilePickerParent.cpp
+++ b/dom/ipc/FilePickerParent.cpp
@@ -112,20 +112,19 @@ FilePickerParent::FileSizeAndDateRunnabl
 
 void
 FilePickerParent::SendFiles(const nsTArray<nsRefPtr<FileImpl>>& aFiles)
 {
   nsIContentParent* parent = TabParent::GetFrom(Manager())->Manager();
   InfallibleTArray<PBlobParent*> files;
 
   for (unsigned i = 0; i < aFiles.Length(); i++) {
-    nsRefPtr<File> file = new File(nullptr, aFiles[i]);
-    BlobParent* blob = parent->GetOrCreateActorForBlob(file);
-    if (blob) {
-      files.AppendElement(blob);
+    BlobParent* blobParent = parent->GetOrCreateActorForFileImpl(aFiles[i]);
+    if (blobParent) {
+      files.AppendElement(blobParent);
     }
   }
 
   InputFiles infiles;
   infiles.filesParent().SwapElements(files);
   unused << Send__delete__(this, infiles, mResult);
 }
 
--- a/dom/ipc/StructuredCloneUtils.cpp
+++ b/dom/ipc/StructuredCloneUtils.cpp
@@ -46,33 +46,33 @@ Read(JSContext* aCx, JSStructuredCloneRe
     // nsRefPtr<File> 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<File> blob = closure->mBlobs[aData];
+      nsRefPtr<Blob> blob = closure->mBlobs[aData];
 
 #ifdef DEBUG
       {
-        // File should not be mutable.
+        // Blob should not be mutable.
         bool isMutable;
         MOZ_ASSERT(NS_SUCCEEDED(blob->GetMutable(&isMutable)));
         MOZ_ASSERT(!isMutable);
       }
 #endif
 
       // Let's create a new blob with the correct parent.
       nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
       MOZ_ASSERT(global);
 
-      nsRefPtr<File> newBlob = new File(global, blob->Impl());
-      if (!GetOrCreateDOMReflector(aCx, newBlob, &val)) {
+      nsRefPtr<Blob> newBlob = Blob::Create(global, blob->Impl());
+      if (!ToJSValue(aCx, newBlob, &val)) {
         return nullptr;
       }
     }
 
     return &val.toObject();
   }
 
   return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr);
@@ -84,17 +84,17 @@ Write(JSContext* aCx, JSStructuredCloneW
 {
   MOZ_ASSERT(aClosure);
 
   StructuredCloneClosure* closure =
     static_cast<StructuredCloneClosure*>(aClosure);
 
   // See if the wrapped native is a File/Blob.
   {
-    File* blob = nullptr;
+    Blob* 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;
     }
   }
--- a/dom/ipc/StructuredCloneUtils.h
+++ b/dom/ipc/StructuredCloneUtils.h
@@ -14,17 +14,17 @@
 #include "js/StructuredClone.h"
 
 namespace mozilla {
 namespace dom {
 
 struct
 StructuredCloneClosure
 {
-  nsTArray<nsRefPtr<File>> mBlobs;
+  nsTArray<nsRefPtr<Blob>> mBlobs;
 };
 
 struct
 StructuredCloneData
 {
   StructuredCloneData() : mData(nullptr), mDataLength(0) {}
   uint64_t* mData;
   size_t mDataLength;
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -88,25 +88,34 @@ nsIContentChild::AllocPBlobChild(const B
 bool
 nsIContentChild::DeallocPBlobChild(PBlobChild* aActor)
 {
   BlobChild::Destroy(aActor);
   return true;
 }
 
 BlobChild*
-nsIContentChild::GetOrCreateActorForBlob(File* aBlob)
+nsIContentChild::GetOrCreateActorForBlob(Blob* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
 
   nsRefPtr<FileImpl> blobImpl = aBlob->Impl();
   MOZ_ASSERT(blobImpl);
 
-  BlobChild* actor = BlobChild::GetOrCreate(this, blobImpl);
+  return GetOrCreateActorForFileImpl(blobImpl);
+}
+
+BlobChild*
+nsIContentChild::GetOrCreateActorForFileImpl(FileImpl* aImpl)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aImpl);
+
+  BlobChild* actor = BlobChild::GetOrCreate(this, aImpl);
   NS_ENSURE_TRUE(actor, nullptr);
 
   return actor;
 }
 
 bool
 nsIContentChild::RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
--- a/dom/ipc/nsIContentChild.h
+++ b/dom/ipc/nsIContentChild.h
@@ -27,31 +27,33 @@ namespace mozilla {
 
 namespace jsipc {
 class PJavaScriptChild;
 class CpowEntry;
 } // jsipc
 
 namespace dom {
 
+class Blob;
 class BlobChild;
 class BlobConstructorParams;
 class ClonedMessageData;
-class File;
+class FileImpl;
 class IPCTabContext;
 class PBlobChild;
 class PBrowserChild;
 
 class nsIContentChild : public nsISupports
                       , public CPOWManagerGetter
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTCHILD_IID)
 
-  BlobChild* GetOrCreateActorForBlob(File* aBlob);
+  BlobChild* GetOrCreateActorForBlob(Blob* aBlob);
+  BlobChild* GetOrCreateActorForFileImpl(FileImpl* aImpl);
 
   virtual PBlobChild* SendPBlobConstructor(
     PBlobChild* aActor,
     const BlobConstructorParams& aParams) = 0;
 
   virtual bool
   SendPBrowserConstructor(PBrowserChild* aActor,
                           const TabId& aTabId,
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -154,25 +154,34 @@ nsIContentParent::AllocPBlobParent(const
 bool
 nsIContentParent::DeallocPBlobParent(PBlobParent* aActor)
 {
   BlobParent::Destroy(aActor);
   return true;
 }
 
 BlobParent*
-nsIContentParent::GetOrCreateActorForBlob(File* aBlob)
+nsIContentParent::GetOrCreateActorForBlob(Blob* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
 
   nsRefPtr<FileImpl> blobImpl = aBlob->Impl();
   MOZ_ASSERT(blobImpl);
 
-  BlobParent* actor = BlobParent::GetOrCreate(this, blobImpl);
+  return GetOrCreateActorForFileImpl(blobImpl);
+}
+
+BlobParent*
+nsIContentParent::GetOrCreateActorForFileImpl(FileImpl* aImpl)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aImpl);
+
+  BlobParent* actor = BlobParent::GetOrCreate(this, aImpl);
   NS_ENSURE_TRUE(actor, nullptr);
 
   return actor;
 }
 
 bool
 nsIContentParent::RecvSyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -28,34 +28,36 @@ namespace mozilla {
 
 namespace jsipc {
 class PJavaScriptParent;
 class CpowEntry;
 } // namespace jsipc
 
 namespace dom {
 
+class Blob;
 class BlobConstructorParams;
 class BlobParent;
 class ContentParent;
-class File;
+class FileImpl;
 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(File* aBlob);
+  BlobParent* GetOrCreateActorForBlob(Blob* aBlob);
+  BlobParent* GetOrCreateActorForFileImpl(FileImpl* aImpl);
 
   virtual ContentParentId ChildID() = 0;
   virtual bool IsForApp() = 0;
   virtual bool IsForBrowser() = 0;
 
   MOZ_WARN_UNUSED_RESULT
   virtual PBlobParent* SendPBlobConstructor(
     PBlobParent* aActor,
--- a/dom/media/EncodedBufferCache.cpp
+++ b/dom/media/EncodedBufferCache.cpp
@@ -34,41 +34,41 @@ EncodedBufferCache::AppendBuffer(nsTArra
         NS_WARNING("Failed to write media cache block!");
       }
     }
     mEncodedBuffers.Clear();
   }
 
 }
 
-already_AddRefed<dom::File>
+already_AddRefed<dom::Blob>
 EncodedBufferCache::ExtractBlob(nsISupports* aParent,
                                 const nsAString &aContentType)
 {
   MutexAutoLock lock(mMutex);
-  nsRefPtr<dom::File> blob;
+  nsRefPtr<dom::Blob> blob;
   if (mTempFileEnabled) {
     // generate new temporary file to write
-    blob = dom::File::CreateTemporaryFileBlob(aParent, mFD, 0, mDataSize,
-                                              aContentType);
+    blob = dom::Blob::CreateTemporaryBlob(aParent, mFD, 0, mDataSize,
+                                          aContentType);
     // fallback to memory blob
     mTempFileEnabled = false;
     mDataSize = 0;
     mFD = nullptr;
   } else {
     void* blobData = 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::File::CreateMemoryFile(aParent, blobData, mDataSize,
+      blob = dom::Blob::CreateMemoryBlob(aParent, blobData, mDataSize,
                                          aContentType);
       mEncodedBuffers.Clear();
     } else
       return nullptr;
   }
   mDataSize = 0;
   return blob.forget();
 }
--- a/dom/media/EncodedBufferCache.h
+++ b/dom/media/EncodedBufferCache.h
@@ -11,17 +11,17 @@
 #include "nsTArray.h"
 #include "mozilla/Mutex.h"
 
 struct PRFileDesc;
 
 namespace mozilla {
 
 namespace dom {
-class File;
+class Blob;
 }
 
 /**
  * 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.
  */
@@ -36,17 +36,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<dom::File> ExtractBlob(nsISupports* aParent, const nsAString &aContentType);
+  already_AddRefed<dom::Blob> 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/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -1012,17 +1012,17 @@ MediaRecorder::CreateAndDispatchBlobEven
     nsRefPtr<nsIDOMBlob> blob = aBlob;
     return NS_ERROR_DOM_SECURITY_ERR;
   }
   BlobEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
 
   nsCOMPtr<nsIDOMBlob> blob = aBlob;
-  init.mData = static_cast<File*>(blob.get());
+  init.mData = static_cast<Blob*>(blob.get());
 
   nsRefPtr<BlobEvent> event =
     BlobEvent::Constructor(this,
                            NS_LITERAL_STRING("dataavailable"),
                            init);
   event->SetTrusted(true);
   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
--- a/dom/media/imagecapture/CaptureTask.cpp
+++ b/dom/media/imagecapture/CaptureTask.cpp
@@ -10,28 +10,28 @@
 #include "mozilla/dom/ImageEncoder.h"
 #include "mozilla/dom/VideoStreamTrack.h"
 #include "gfxUtils.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 
 nsresult
-CaptureTask::TaskComplete(already_AddRefed<dom::File> aBlob, nsresult aRv)
+CaptureTask::TaskComplete(already_AddRefed<dom::Blob> aBlob, nsresult aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   DetachStream();
 
   nsresult rv;
-  nsRefPtr<dom::File> blob(aBlob);
+  nsRefPtr<dom::Blob> blob(aBlob);
 
   // We have to set the parent because the blob has been generated with a valid one.
   if (blob) {
-    blob = new dom::File(mImageCapture->GetParentObject(), blob->Impl());
+    blob = dom::Blob::Create(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)) {
@@ -98,19 +98,19 @@ CaptureTask::NotifyQueuedTrackChanges(Me
   }
 
   // Callback for encoding complete, it calls on main thread.
   class EncodeComplete : public dom::EncodeCompleteCallback
   {
   public:
     explicit EncodeComplete(CaptureTask* aTask) : mTask(aTask) {}
 
-    nsresult ReceiveBlob(already_AddRefed<dom::File> aBlob) override
+    nsresult ReceiveBlob(already_AddRefed<dom::Blob> aBlob) override
     {
-      nsRefPtr<dom::File> blob(aBlob);
+      nsRefPtr<dom::Blob> blob(aBlob);
       mTask->TaskComplete(blob.forget(), NS_OK);
       mTask = nullptr;
       return NS_OK;
     }
 
   protected:
     nsRefPtr<CaptureTask> mTask;
   };
--- a/dom/media/imagecapture/CaptureTask.h
+++ b/dom/media/imagecapture/CaptureTask.h
@@ -8,17 +8,17 @@
 #define CAPTURETASK_H
 
 #include "DOMMediaStream.h"
 #include "MediaStreamGraph.h"
 
 namespace mozilla {
 
 namespace dom {
-class File;
+class Blob;
 class ImageCapture;
 }
 
 /**
  * CaptureTask retrieves image from MediaStream and encodes the image to jpeg in
  * ImageEncoder. The whole procedures start at AttachStream(), it will add this
  * class into MediaStream and retrieves an image in MediaStreamGraph thread.
  * Once the image is retrieved, it will be sent to ImageEncoder and the encoded
@@ -45,17 +45,17 @@ public:
 
   // CaptureTask methods.
 
   // It is called when aBlob is ready to post back to script in company with
   // aRv == NS_OK. If aRv is not NS_OK, it will post an error event to script.
   //
   // Note:
   //   this function should be called on main thread.
-  nsresult TaskComplete(already_AddRefed<dom::File> aBlob, nsresult aRv);
+  nsresult TaskComplete(already_AddRefed<dom::Blob> aBlob, nsresult aRv);
 
   // Add listeners into MediaStream and PrincipalChangeObserver. It should be on
   // main thread only.
   void AttachStream();
 
   // Remove listeners from MediaStream and PrincipalChangeObserver. It should be
   // on main thread only.
   void DetachStream();
--- a/dom/media/imagecapture/ImageCapture.cpp
+++ b/dom/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(File* aBlob)
+ImageCapture::PostBlobEvent(Blob* 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/dom/media/imagecapture/ImageCapture.h
+++ b/dom/media/imagecapture/ImageCapture.h
@@ -25,17 +25,17 @@ PRLogModuleInfo* GetICLog();
 #ifndef IC_LOG
 #define IC_LOG(...)
 #endif
 
 #endif // PR_LOGGING
 
 namespace dom {
 
-class File;
+class Blob;
 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.
  *
@@ -73,17 +73,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(File* aBlob);
+  nsresult PostBlobEvent(Blob* 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/dom/mobilemessage/MmsMessage.cpp
+++ b/dom/mobilemessage/MmsMessage.cpp
@@ -89,20 +89,20 @@ MmsMessage::MmsMessage(const mobilemessa
     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()) {
       nsRefPtr<FileImpl> impl = static_cast<BlobParent*>(element.contentParent())->GetBlobImpl();
-      att.mContent = new File(nullptr, impl);
+      att.mContent = Blob::Create(nullptr, impl);
     } else if (element.contentChild()) {
       nsRefPtr<FileImpl> impl = static_cast<BlobChild*>(element.contentChild())->GetBlobImpl();
-      att.mContent = new File(nullptr, impl);
+      att.mContent = Blob::Create(nullptr, impl);
     } else {
       NS_WARNING("MmsMessage: Unable to get attachment content.");
     }
     mAttachments.AppendElement(att);
   }
 
   len = aData.deliveryInfo().Length();
   mDeliveryInfo.SetCapacity(len);
@@ -385,20 +385,23 @@ 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.
-    if (element.content->IsDateUnknown()) {
-      int64_t date;
-      if (NS_FAILED(element.content->GetMozLastModifiedDate(&date))) {
+    nsRefPtr<FileImpl> impl = element.content->Impl();
+    if (impl && impl->IsDateUnknown()) {
+      ErrorResult rv;
+      impl->GetLastModified(rv);
+      if (rv.Failed()) {
         NS_WARNING("Failed to get last modified date!");
+        rv.SuppressException();
       }
     }
 
     mma.contentParent() = aParent->GetOrCreateActorForBlob(element.content);
     if (!mma.contentParent()) {
       return false;
     }
     aData.attachments().AppendElement(mma);
@@ -572,20 +575,20 @@ MmsMessage::GetAttachments(JSContext* aC
       return NS_ERROR_FAILURE;
     }
 
     // Get |attachment.mContent|.
 
     // Duplicating the File with the correct parent object.
     nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
     MOZ_ASSERT(global);
-    nsRefPtr<File> newBlob = new File(global, attachment.content->Impl());
+    nsRefPtr<Blob> newBlob = Blob::Create(global, attachment.content->Impl());
 
     JS::Rooted<JS::Value> val(aCx);
-    if (!GetOrCreateDOMReflector(aCx, newBlob, &val)) {
+    if (!ToJSValue(aCx, newBlob, &val)) {
       return NS_ERROR_FAILURE;
     }
 
     if (!JS_DefineProperty(aCx, attachmentObj, "content", val, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
     if (!JS_DefineElement(aCx, attachments, i, attachmentObj, JSPROP_ENUMERATE)) {
--- a/dom/mobilemessage/MmsMessage.h
+++ b/dom/mobilemessage/MmsMessage.h
@@ -12,34 +12,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 File;
+class Blob;
 
 namespace mobilemessage {
 class MmsMessageData;
 } // namespace mobilemessage
 
 class ContentParent;
 
 class MmsMessage final : public nsIDOMMozMmsMessage
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMOZMMSMESSAGE
 
   // If this is changed, change the WebIDL dictionary as well.
   struct Attachment final
   {
-    nsRefPtr<File> content;
+    nsRefPtr<Blob> content;
     nsString id;
     nsString location;
 
     explicit Attachment(const MmsAttachment& aAttachment) :
       content(aAttachment.mContent),
       id(aAttachment.mId),
       location(aAttachment.mLocation)
     {}
--- a/dom/mobilemessage/ipc/SmsParent.cpp
+++ b/dom/mobilemessage/ipc/SmsParent.cpp
@@ -60,18 +60,18 @@ MmsAttachmentDataToJSObject(JSContext* a
   // 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);
   {
     nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aContext));
     MOZ_ASSERT(global);
 
-    nsRefPtr<File> blob = new File(global, blobImpl);
-    if (!GetOrCreateDOMReflector(aContext, blob, &content)) {
+    nsRefPtr<Blob> blob = Blob::Create(global, blobImpl);
+    if (!ToJSValue(aContext, blob, &content)) {
       return nullptr;
     }
   }
 
   if (!JS_DefineProperty(aContext, obj, "content", content, 0)) {
     return nullptr;
   }
 
--- a/dom/network/UDPSocket.cpp
+++ b/dom/network/UDPSocket.cpp
@@ -332,17 +332,17 @@ UDPSocket::Send(const StringOrBlobOrArra
     remotePort = mRemotePort.Value();
   } else {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return false;
   }
 
   nsCOMPtr<nsIInputStream> stream;
   if (aData.IsBlob()) {
-    File& blob = aData.GetAsBlob();
+    Blob& blob = aData.GetAsBlob();
 
     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);
--- a/dom/workers/FileReaderSync.cpp
+++ b/dom/workers/FileReaderSync.cpp
@@ -47,17 +47,17 @@ FileReaderSync::WrapObject(JSContext* aC
                            JS::MutableHandle<JSObject*> aReflector)
 {
   return FileReaderSyncBinding_workers::Wrap(aCx, this, aGivenProto, aReflector);
 }
 
 void
 FileReaderSync::ReadAsArrayBuffer(JSContext* aCx,
                                   JS::Handle<JSObject*> aScopeObj,
-                                  File& aBlob,
+                                  Blob& aBlob,
                                   JS::MutableHandle<JSObject*> aRetval,
                                   ErrorResult& aRv)
 {
   uint64_t blobSize;
   nsresult rv = aBlob.GetSize(&blobSize);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
@@ -90,17 +90,17 @@ FileReaderSync::ReadAsArrayBuffer(JSCont
     return;
   }
   bufferData.release();
 
   aRetval.set(arrayBuffer);
 }
 
 void
-FileReaderSync::ReadAsBinaryString(File& aBlob,
+FileReaderSync::ReadAsBinaryString(Blob& aBlob,
                                    nsAString& aResult,
                                    ErrorResult& aRv)
 {
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = aBlob.GetInternalStream(getter_AddRefs(stream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
@@ -120,17 +120,17 @@ FileReaderSync::ReadAsBinaryString(File&
     if (aResult.Length() - oldLength != numRead) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return;
     }
   } while (numRead > 0);
 }
 
 void
-FileReaderSync::ReadAsText(File& aBlob,
+FileReaderSync::ReadAsText(Blob& aBlob,
                            const Optional<nsAString>& aEncoding,
                            nsAString& aResult,
                            ErrorResult& aRv)
 {
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = aBlob.GetInternalStream(getter_AddRefs(stream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
@@ -190,17 +190,17 @@ FileReaderSync::ReadAsText(File& aBlob,
   rv = ConvertStream(stream, encoding.get(), aResult);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 }
 
 void
-FileReaderSync::ReadAsDataURL(File& aBlob, nsAString& aResult,
+FileReaderSync::ReadAsDataURL(Blob& aBlob, nsAString& aResult,
                               ErrorResult& aRv)
 {
   nsAutoString scratchResult;
   scratchResult.AssignLiteral("data:");
 
   nsString contentType;
   aBlob.GetType(contentType);
 
--- a/dom/workers/FileReaderSync.h
+++ b/dom/workers/FileReaderSync.h
@@ -10,17 +10,17 @@
 #include "Workers.h"
 
 class nsIInputStream;
 
 namespace mozilla {
 class ErrorResult;
 
 namespace dom {
-class File;
+class Blob;
 class GlobalObject;
 template<typename> class Optional;
 }
 }
 
 BEGIN_WORKERS_NAMESPACE
 
 class FileReaderSync final
@@ -38,19 +38,19 @@ private:
 
 public:
   static already_AddRefed<FileReaderSync>
   Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
 
   bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector);
 
   void ReadAsArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aScopeObj,
-                         File& aBlob, JS::MutableHandle<JSObject*> aRetval,
+                         Blob& aBlob, JS::MutableHandle<JSObject*> aRetval,
                          ErrorResult& aRv);
-  void ReadAsBinaryString(File& aBlob, nsAString& aResult, ErrorResult& aRv);
-  void ReadAsText(File& aBlob, const Optional<nsAString>& aEncoding,
+  void ReadAsBinaryString(Blob& aBlob, nsAString& aResult, ErrorResult& aRv);
+  void ReadAsText(Blob& aBlob, const Optional<nsAString>& aEncoding,
                   nsAString& aResult, ErrorResult& aRv);
-  void ReadAsDataURL(File& aBlob, nsAString& aResult, ErrorResult& aRv);
+  void ReadAsDataURL(Blob& aBlob, nsAString& aResult, ErrorResult& aRv);
 };
 
 END_WORKERS_NAMESPACE
 
 #endif // mozilla_dom_workers_filereadersync_h__
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -407,17 +407,17 @@ PushMessageData::Text(nsAString& aData)
 
 void
 PushMessageData::ArrayBuffer(JSContext* cx, JS::MutableHandle<JSObject*> aRetval)
 {
   //todo bug 1149195.  Don't be lazy.
    NS_ABORT();
 }
 
-mozilla::dom::File*
+mozilla::dom::Blob*
 PushMessageData::Blob()
 {
   //todo bug 1149195.  Don't be lazy.
   NS_ABORT();
   return nullptr;
 }
 
 PushEvent::PushEvent(EventTarget* aOwner)
--- a/dom/workers/ServiceWorkerEvents.h
+++ b/dom/workers/ServiceWorkerEvents.h
@@ -20,18 +20,19 @@
 #endif
 
 #include "nsProxyRelease.h"
 
 class nsIInterceptedChannel;
 
 namespace mozilla {
 namespace dom {
-  class Request;
-  class ResponseOrPromise;
+class Blob;
+class Request;
+class ResponseOrPromise;
 } // namespace dom
 } // namespace mozilla
 
 BEGIN_WORKERS_NAMESPACE
 
 class ServiceWorkerClient;
 
 class FetchEvent final : public Event
@@ -171,17 +172,17 @@ public:
 
   nsISupports* GetParentObject() const {
     return nullptr;
   }
 
   void Json(JSContext* cx, JS::MutableHandle<JSObject*> aRetval);
   void Text(nsAString& aData);
   void ArrayBuffer(JSContext* cx, JS::MutableHandle<JSObject*> aRetval);
-  mozilla::dom::File* Blob();
+  mozilla::dom::Blob* Blob();
 
   explicit PushMessageData(const nsAString& aData);
 private:
   ~PushMessageData();
 
 };
 
 class PushEvent final : public ExtendableEvent
--- a/dom/workers/URL.cpp
+++ b/dom/workers/URL.cpp
@@ -875,17 +875,17 @@ URL::SetHash(const nsAString& aHash, Err
 
   if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
     JS_ReportPendingException(mWorkerPrivate->GetJSContext());
   }
 }
 
 // static
 void
-URL::CreateObjectURL(const GlobalObject& aGlobal, File& aBlob,
+URL::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
                      const mozilla::dom::objectURLOptions& aOptions,
                      nsAString& aResult, mozilla::ErrorResult& aRv)
 {
   JSContext* cx = aGlobal.Context();
   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
 
   nsRefPtr<FileImpl> blobImpl = aBlob.Impl();
   MOZ_ASSERT(blobImpl);
--- a/dom/workers/URL.h
+++ b/dom/workers/URL.h
@@ -10,17 +10,17 @@
 #include "Workers.h"
 
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/URLSearchParams.h"
 
 namespace mozilla {
 namespace dom {
-class File;
+class Blob;
 struct objectURLOptions;
 }
 }
 
 BEGIN_WORKERS_NAMESPACE
 
 class URLProxy;
 class ConstructorRunnable;
@@ -56,17 +56,17 @@ public:
   Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
               const Optional<nsAString>& 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,
-                  File& aArg, const objectURLOptions& aOptions,
+                  Blob& aArg, const objectURLOptions& aOptions,
                   nsAString& aResult, ErrorResult& aRv);
 
   static void
   RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl,
                   ErrorResult& aRv);
 
   void GetHref(nsAString& aHref, ErrorResult& aRv) const;
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -392,17 +392,17 @@ EnsureBlobForBackgroundManager(FileImpl*
     }
 
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
   }
 
   return blobImpl.forget();
 }
 
-already_AddRefed<File>
+already_AddRefed<Blob>
 ReadBlobOrFileNoWrap(JSContext* aCx,
                      JSStructuredCloneReader* aReader,
                      bool aIsMainThread)
 {
   MOZ_ASSERT(aCx);
   MOZ_ASSERT(aReader);
 
   nsRefPtr<FileImpl> blobImpl;
@@ -431,27 +431,27 @@ ReadBlobOrFileNoWrap(JSContext* aCx,
     MOZ_ASSERT(workerPrivate);
 
     WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
     MOZ_ASSERT(globalScope);
 
     parent = do_QueryObject(globalScope);
   }
 
-  nsRefPtr<File> blob = new File(parent, blobImpl);
+  nsRefPtr<Blob> blob = Blob::Create(parent, blobImpl);
   return blob.forget();
 }
 
 void
 ReadBlobOrFile(JSContext* aCx,
                JSStructuredCloneReader* aReader,
                bool aIsMainThread,
                JS::MutableHandle<JSObject*> aBlobOrFile)
 {
-  nsRefPtr<File> blob = ReadBlobOrFileNoWrap(aCx, aReader, aIsMainThread);
+  nsRefPtr<Blob> blob = ReadBlobOrFileNoWrap(aCx, aReader, aIsMainThread);
   aBlobOrFile.set(blob->WrapObject(aCx, JS::NullPtr()));
 }
 
 // See WriteFormData for serialization format.
 void
 ReadFormData(JSContext* aCx,
              JSStructuredCloneReader* aReader,
              bool aIsMainThread,
@@ -490,17 +490,17 @@ ReadFormData(JSContext* aCx,
     MOZ_ALWAYS_TRUE(JS_ReadUint32Pair(aReader, &isFile, &dummy));
 
     nsAutoString name;
     MOZ_ALWAYS_TRUE(ReadString(aReader, name));
 
     if (isFile) {
       // Read out the tag since the blob reader isn't expecting it.
       MOZ_ALWAYS_TRUE(JS_ReadUint32Pair(aReader, &dummy, &dummy));
-      nsRefPtr<File> blob = ReadBlobOrFileNoWrap(aCx, aReader, aIsMainThread);
+      nsRefPtr<Blob> blob = ReadBlobOrFileNoWrap(aCx, aReader, aIsMainThread);
       MOZ_ASSERT(blob);
       formData->Append(name, *blob, thirdArg);
     } else {
       nsAutoString value;
       MOZ_ALWAYS_TRUE(ReadString(aReader, value));
       formData->Append(name, value);
     }
   }
@@ -641,17 +641,17 @@ struct WorkerStructuredCloneCallbacks
     NS_ASSERTION(aClosure, "Null pointer!");
 
     // We'll stash any nsISupports pointers that need to be AddRef'd here.
     auto* clonedObjects =
       static_cast<nsTArray<nsCOMPtr<nsISupports>>*>(aClosure);
 
     // See if this is a Blob/File object.
     {
-      nsRefPtr<File> blob;
+      nsRefPtr<Blob> blob;
       if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
         FileImpl* blobImpl = blob->Impl();
         MOZ_ASSERT(blobImpl);
 
         if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) {
           return true;
         }
       }
@@ -733,17 +733,17 @@ struct MainThreadWorkerStructuredCloneCa
     NS_ASSERTION(aClosure, "Null pointer!");
 
     // We'll stash any nsISupports pointers that need to be AddRef'd here.
     auto* clonedObjects =
       static_cast<nsTArray<nsCOMPtr<nsISupports>>*>(aClosure);
 
     // See if this is a Blob/File object.
     {
-      nsRefPtr<File> blob;
+      nsRefPtr<Blob> blob;
       if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
         FileImpl* blobImpl = blob->Impl();
         MOZ_ASSERT(blobImpl);
 
         if (!blobImpl->MayBeClonedToOtherThreads()) {
           NS_WARNING("Not all the blob implementations can be sent between threads.");
         } else if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) {
           return true;
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -2151,17 +2151,17 @@ XMLHttpRequest::Send(JS::Handle<JSObject
     aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
     return;
   }
 
   SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv);
 }
 
 void
-XMLHttpRequest::Send(File& aBody, ErrorResult& aRv)
+XMLHttpRequest::Send(Blob& aBody, ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   JSContext* cx = mWorkerPrivate->GetJSContext();
 
   if (mCanceled) {
     aRv.ThrowUncatchableException();
     return;
   }
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -14,17 +14,17 @@
 
 #include "mozilla/dom/TypedArray.h"
 
 #include "js/StructuredClone.h"
 #include "nsXMLHttpRequest.h"
 
 namespace mozilla {
 namespace dom {
-class File;
+class Blob;
 }
 }
 
 BEGIN_WORKERS_NAMESPACE
 
 class Proxy;
 class XMLHttpRequestUpload;
 class WorkerPrivate;
@@ -166,17 +166,17 @@ public:
 
   void
   Send(const nsAString& aBody, ErrorResult& aRv);
 
   void
   Send(JS::Handle<JSObject*> aBody, ErrorResult& aRv);
 
   void
-  Send(File& aBody, ErrorResult& aRv);
+  Send(Blob& aBody, ErrorResult& aRv);
 
   void
   Send(nsFormData& aBody, ErrorResult& aRv);
 
   void
   Send(const ArrayBuffer& aBody, ErrorResult& aRv);
 
   void
--- a/ipc/glue/BackgroundImpl.cpp
+++ b/ipc/glue/BackgroundImpl.cpp
@@ -916,17 +916,17 @@ BackgroundChild::GetOrCreateActorForBlob
 {
   MOZ_ASSERT(aBackgroundActor);
   MOZ_ASSERT(aBlob);
   MOZ_ASSERT(GetForCurrentThread(),
              "BackgroundChild not created on this thread yet!");
   MOZ_ASSERT(aBackgroundActor == GetForCurrentThread(),
              "BackgroundChild is bound to a different thread!");
 
-  nsRefPtr<FileImpl> blobImpl = static_cast<File*>(aBlob)->Impl();
+  nsRefPtr<FileImpl> blobImpl = static_cast<Blob*>(aBlob)->Impl();
   MOZ_ASSERT(blobImpl);
 
   BlobChild* actor = BlobChild::GetOrCreate(aBackgroundActor, blobImpl);
   if (NS_WARN_IF(!actor)) {
     return nullptr;
   }
 
   return actor;
--- a/js/xpconnect/src/ExportHelpers.cpp
+++ b/js/xpconnect/src/ExportHelpers.cpp
@@ -111,18 +111,18 @@ StackScopedCloneRead(JSContext* cx, JSSt
 
         nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(cx));
         MOZ_ASSERT(global);
 
         // nsRefPtr<File> needs to go out of scope before toObjectOrNull() is called because
         // otherwise the static analysis thinks it can gc the JSObject via the stack.
         JS::Rooted<JS::Value> val(cx);
         {
-            nsRefPtr<File> blob = new File(global, cloneData->mBlobImpls[idx]);
-            if (!GetOrCreateDOMReflector(cx, blob, &val)) {
+            nsRefPtr<Blob> blob = Blob::Create(global, cloneData->mBlobImpls[idx]);
+            if (!ToJSValue(cx, blob, &val)) {
                 return nullptr;
             }
         }
 
         return val.toObjectOrNull();
     }
 
     if (tag == SCTAG_DOM_NFC_NDEF) {
@@ -173,17 +173,17 @@ bool IsFileList(JSObject* obj)
 static bool
 StackScopedCloneWrite(JSContext* cx, JSStructuredCloneWriter* writer,
                       Handle<JSObject*> obj, void* closure)
 {
     MOZ_ASSERT(closure, "Null pointer!");
     StackScopedCloneData* cloneData = static_cast<StackScopedCloneData*>(closure);
 
     {
-        File* blob = nullptr;
+        Blob* blob = nullptr;
         if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
             FileImpl* blobImpl = blob->Impl();
             MOZ_ASSERT(blobImpl);
 
             if (!cloneData->mBlobImpls.AppendElement(blobImpl))
                 return false;
 
             size_t idx = cloneData->mBlobImpls.Length() - 1;
--- a/widget/nsFilePickerProxy.cpp
+++ b/widget/nsFilePickerProxy.cpp
@@ -153,19 +153,22 @@ nsFilePickerProxy::Recv__delete__(const 
 {
   if (aFiles.type() == MaybeInputFiles::TInputFiles) {
     const InfallibleTArray<PBlobChild*>& files = aFiles.get_InputFiles().filesChild();
     for (uint32_t i = 0; i < files.Length(); ++i) {
       BlobChild* actor = static_cast<BlobChild*>(files[i]);
       nsRefPtr<FileImpl> blobImpl = actor->GetBlobImpl();
       NS_ENSURE_TRUE(blobImpl, true);
 
-      nsCOMPtr<nsIDOMBlob> blob = new File(mParent, blobImpl);
-      nsCOMPtr<nsIDOMFile> file(do_QueryInterface(blob));
-      NS_ENSURE_TRUE(file, true);
+      if (!blobImpl->IsFile()) {
+        return true;
+      }
+
+      nsRefPtr<File> file = File::Create(mParent, blobImpl);
+      MOZ_ASSERT(file);
 
       mDomfiles.AppendObject(file);
     }
   }
 
   if (mCallback) {
     mCallback->Done(aResult);
     mCallback = nullptr;