Backout revisions 4287533203fb and 96a3ebfe09d8 (bug 1159401) for bustage.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 11 May 2015 11:43:59 -0400
changeset 243381 49678aa590e25ac6b76e365adf81041ca790d85d
parent 243380 5b68de5f1dc9af107c2afd6557c5bee1b5e60142
child 243382 6bc3e88e0107e6b7d653919d943449a42da3b6be
push id12900
push usercbook@mozilla.com
push dateTue, 12 May 2015 14:40:23 +0000
treeherderfx-team@5f6263cb1e50 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1159401
milestone40.0a1
backs out4287533203fb5c458e8b6281013a97dd1d421295
96a3ebfe09d801bbc47206d31e10b8e470faa333
Backout revisions 4287533203fb and 96a3ebfe09d8 (bug 1159401) for bustage. CLOSED TREE
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/nsIDOMFile.idl
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<nsRefPtr<File>> fileList;
+  nsTArray<nsCOMPtr<nsIDOMFile> > 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<File> file = item->GetFile(mArchiveReader);
+      nsRefPtr<nsIDOMFile> file = item->File(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 already_AddRefed<File> GetFile(ArchiveReader* aArchiveReader) = 0;
+  virtual nsIDOMFile* File(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,
-                           Blob& aBlob,
+                           File& 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(Blob& aBlob, nsPIDOMWindow* aWindow,
+ArchiveReader::ArchiveReader(File& 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<nsRefPtr<File>>& aFileList,
+ArchiveReader::Ready(nsTArray<nsCOMPtr<nsIDOMFile> >& 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, Blob& aBlob,
+  Constructor(const GlobalObject& aGlobal, File& aBlob,
               const ArchiveReaderOptions& aOptions, ErrorResult& aError);
 
-  ArchiveReader(Blob& aBlob, nsPIDOMWindow* aWindow,
+  ArchiveReader(File& aBlob, nsPIDOMWindow* aWindow,
                 const nsACString& aEncoding);
 
   nsIDOMWindow* GetParentObject() const
   {
     return mWindow;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -64,17 +64,18 @@ public: // for the ArchiveRequest:
   nsresult RegisterRequest(ArchiveRequest* aRequest);
 
 public: // For events:
   FileImpl* GetFileImpl() const
   {
     return mFileImpl;
   }
 
-  void Ready(nsTArray<nsRefPtr<File>>& aFileList, nsresult aStatus);
+  void Ready(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
+             nsresult aStatus);
 
 private:
   ~ArchiveReader();
 
   already_AddRefed<ArchiveRequest> GenerateArchiveRequest();
 
   nsresult OpenArchive();
 
@@ -102,17 +103,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<nsRefPtr<File>> fileList;
+    nsTArray<nsCOMPtr<nsIDOMFile> > 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<nsRefPtr<File>>& aFileList,
+ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
                             nsresult aStatus)
 {
   if (NS_FAILED(aStatus)) {
     FireError(aStatus);
     return NS_OK;
   }
 
   nsresult rv;
@@ -169,28 +169,28 @@ ArchiveRequest::ReaderReady(nsTArray<nsR
   }
 
   return NS_OK;
 }
 
 nsresult
 ArchiveRequest::GetFilenamesResult(JSContext* aCx,
                                    JS::Value* aValue,
-                                   nsTArray<nsRefPtr<File>>& aFileList)
+                                   nsTArray<nsCOMPtr<nsIDOMFile> >& 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) {
-    nsRefPtr<File> file = aFileList[i];
+    nsCOMPtr<nsIDOMFile> 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,56 +206,52 @@ ArchiveRequest::GetFilenamesResult(JSCon
 
   *aValue = OBJECT_TO_JSVAL(array);
   return NS_OK;
 }
 
 nsresult
 ArchiveRequest::GetFileResult(JSContext* aCx,
                               JS::MutableHandle<JS::Value> aValue,
-                              nsTArray<nsRefPtr<File>>& aFileList)
+                              nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
 {
   for (uint32_t i = 0; i < aFileList.Length(); ++i) {
-    nsRefPtr<File> file = aFileList[i];
+    nsCOMPtr<nsIDOMFile> file = aFileList[i];
 
     nsString filename;
     nsresult rv = file->GetName(filename);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (filename == mFilename) {
-      if (!ToJSValue(aCx, file, aValue)) {
-        return NS_ERROR_FAILURE;
-      }
-
-      return NS_OK;
+      return nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile),
+                                        aValue);
     }
   }
 
   return NS_ERROR_FAILURE;
 }
 
 nsresult
 ArchiveRequest::GetFilesResult(JSContext* aCx,
                                JS::MutableHandle<JS::Value> aValue,
-                               nsTArray<nsRefPtr<File>>& aFileList)
+                               nsTArray<nsCOMPtr<nsIDOMFile> >& 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) {
-    nsRefPtr<File> file = aFileList[i];
+    nsCOMPtr<nsIDOMFile> file = aFileList[i];
 
     JS::Rooted<JS::Value> value(aCx);
-    if (!ToJSValue(aCx, file, &value)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    if (!JS_DefineElement(aCx, array, i, value, JSPROP_ENUMERATE)) {
+    nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile),
+                                             &value);
+    if (NS_FAILED(rv) ||
+        !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,34 +44,35 @@ 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<nsRefPtr<File>>& aFileList, nsresult aStatus);
+  nsresult ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
+                       nsresult aStatus);
 
 public: // static
   static already_AddRefed<ArchiveRequest> Create(nsPIDOMWindow* aOwner,
                                                  ArchiveReader* aReader);
 
 private:
   ~ArchiveRequest();
 
   nsresult GetFilenamesResult(JSContext* aCx,
                               JS::Value* aValue,
-                              nsTArray<nsRefPtr<File>>& aFileList);
+                              nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
   nsresult GetFileResult(JSContext* aCx,
                          JS::MutableHandle<JS::Value> aValue,
-                         nsTArray<nsRefPtr<File>>& aFileList);
+                         nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
   nsresult GetFilesResult(JSContext* aCx,
                           JS::MutableHandle<JS::Value> aValue,
-                          nsTArray<nsRefPtr<File>>& aFileList);
+                          nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
 
 protected:
   // The reader:
   nsRefPtr<ArchiveReader> mArchiveReader;
 
   // The operation:
   enum {
     GetFilenames,
--- a/dom/archivereader/ArchiveZipEvent.cpp
+++ b/dom/archivereader/ArchiveZipEvent.cpp
@@ -70,32 +70,30 @@ ArchiveZipItem::GetFilename(nsString& aF
     }
   }
 
   aFilename = mFilenameU;
   return NS_OK;
 }
 
 // From zipItem to File:
-already_AddRefed<File>
-ArchiveZipItem::GetFile(ArchiveReader* aArchiveReader)
+nsIDOMFile*
+ArchiveZipItem::File(ArchiveReader* aArchiveReader)
 {
   nsString filename;
 
   if (NS_FAILED(GetFilename(filename))) {
     return nullptr;
   }
 
-  nsRefPtr<dom::File> file = dom::File::Create(aArchiveReader,
+  return new dom::File(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,18 +26,17 @@ public:
                  const nsACString& aEncoding);
 protected:
   virtual ~ArchiveZipItem();
 
 public:
   nsresult GetFilename(nsString& aFilename) override;
 
   // From zipItem to File:
-  virtual already_AddRefed<File>
-  GetFile(ArchiveReader* aArchiveReader) override;
+  virtual nsIDOMFile* File(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<Blob> GetBlobInternal(nsISupports* aParent,
+  already_AddRefed<File> 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<Blob> blob =
-        Blob::Create(data->mParent, data->mFiles.ElementAt(aIndex));
-      if (!ToJSValue(aCx, blob, &val)) {
+      nsRefPtr<File> file =
+        new File(data->mParent, data->mFiles.ElementAt(aIndex));
+      if (!GetOrCreateDOMReflector(aCx, file, &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<Blob> blob;
-  if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
-      blob->Impl()->MayBeClonedToOtherThreads()) {
+  nsRefPtr<File> file;
+  if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, file)) &&
+      file->Impl()->MayBeClonedToOtherThreads()) {
     if (!JS_WriteUint32Pair(aWriter, CONSOLE_TAG_BLOB, data->mFiles.Length())) {
       return false;
     }
 
-    data->mFiles.AppendElement(blob->Impl());
+    data->mFiles.AppendElement(file->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,361 +119,49 @@ nsresult DataOwnerAdapter::Create(DataOw
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ADDREF(*_retval = new DataOwnerAdapter(aDataOwner, stream));
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// mozilla::dom::Blob implementation
+// mozilla::dom::File implementation
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(Blob)
+NS_IMPL_CYCLE_COLLECTION_CLASS(File)
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Blob)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(File)
   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(Blob)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(File)
   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(Blob)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(File)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Blob)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(File)
   // 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, nsIDOMBlob)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, IsFile())
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY(nsIMutable)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
-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);
-}
+NS_IMPL_CYCLE_COLLECTING_ADDREF(File)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(File)
 
 /* 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));
@@ -485,28 +173,65 @@ 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,
@@ -542,35 +267,101 @@ 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();
 }
 
-JSObject*
-File::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+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
 {
-  return FileBinding::Wrap(aCx, this, 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();
 }
 
 NS_IMETHODIMP
 File::GetName(nsAString& aFileName)
 {
   mImpl->GetName(aFileName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 File::GetPath(nsAString& aPath)
 {
   return mImpl->GetPath(aPath);
 }
 
+NS_IMETHODIMP
+File::GetLastModifiedDate(JSContext* aCx,
+                          JS::MutableHandle<JS::Value> aDate)
+{
+  ErrorResult rv;
+  Date value = GetLastModifiedDate(rv);
+  if (rv.Failed()) {
+    return rv.StealNSResult();
+  }
+
+  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();
   }
 
@@ -579,33 +370,16 @@ File::GetLastModifiedDate(ErrorResult& a
 
 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();
-  }
-
-  if (!value.ToDateObject(aCx, aDate)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 File::GetMozFullPath(nsAString& aFileName)
 {
   ErrorResult rv;
   GetMozFullPath(aFileName, rv);
   return rv.StealNSResult();
 }
 
 void
@@ -618,16 +392,39 @@ 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();
 }
@@ -664,16 +461,147 @@ 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)
 {
@@ -690,17 +618,17 @@ File::Constructor(
   }
 
   nsRefPtr<File> file = new File(aGlobal.GetAsSupports(), impl);
   return file.forget();
 }
 
 /* static */ already_AddRefed<File>
 File::Constructor(const GlobalObject& aGlobal,
-                  Blob& aData,
+                  File& aData,
                   const ChromeFilePropertyBag& aBag,
                   ErrorResult& aRv)
 {
   if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
@@ -1258,38 +1186,38 @@ FileImplMemory::DataOwner::EnsureMemoryR
   }
 
   RegisterStrongMemoryReporter(new FileImplMemoryDataOwnerMemoryReporter());
 
   sMemoryReporterRegistered = true;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// FileImplTemporaryBlob implementation
+// FileImplTemporaryFileBlob implementation
 
-NS_IMPL_ISUPPORTS_INHERITED0(FileImplTemporaryBlob, FileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(FileImplTemporaryFileBlob, FileImpl)
 
 already_AddRefed<FileImpl>
-FileImplTemporaryBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
-                                   const nsAString& aContentType,
-                                   ErrorResult& aRv)
+FileImplTemporaryFileBlob::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 FileImplTemporaryBlob(this, aStart + mStartPos,
-                              aLength, aContentType);
+    new FileImplTemporaryFileBlob(this, aStart + mStartPos,
+                                  aLength, aContentType);
   return impl.forget();
 }
 
 nsresult
-FileImplTemporaryBlob::GetInternalStream(nsIInputStream** aStream)
+FileImplTemporaryFileBlob::GetInternalStream(nsIInputStream** aStream)
 {
   nsCOMPtr<nsIInputStream> stream =
     new nsTemporaryFileInputStream(mFileDescOwner, mStartPos, mStartPos + mLength);
   stream.forget(aStream);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
@@ -1326,20 +1254,20 @@ FileList::Item(uint32_t aIndex, nsIDOMFi
   nsRefPtr<File> file = Item(aIndex);
   file.forget(aFile);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // BlobSet implementation
 
-already_AddRefed<Blob>
+already_AddRefed<File>
 BlobSet::GetBlobInternal(nsISupports* aParent, const nsACString& aContentType)
 {
-  nsRefPtr<Blob> blob = Blob::Create(aParent,
+  nsRefPtr<File> blob = new File(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,159 +42,71 @@ namespace dom {
 
 namespace indexedDB {
 class FileInfo;
 };
 
 struct BlobPropertyBag;
 struct ChromeFilePropertyBag;
 struct FilePropertyBag;
-class File;
 class FileImpl;
 class OwningArrayBufferOrArrayBufferViewOrBlobOrString;
 
-class Blob : public nsIDOMBlob
-           , public nsIXHRSendable
-           , public nsIMutable
-           , public nsSupportsWeakReference
-           , public nsWrapperCache
+class File final : public nsIDOMFile
+                 , 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(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);
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(File, nsIDOMFile)
 
   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);
 
@@ -206,33 +118,64 @@ 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);
 
-  // WebIDL methods
+  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;
 
-  virtual JSObject* WrapObject(JSContext *cx,
-                               JS::Handle<JSObject*> aGivenProto) override;
+  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);
 
   // 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,
-              Blob& aData,
+              File& aData,
               const ChromeFilePropertyBag& aBag,
               ErrorResult& aRv);
 
   // File constructor - ChromeOnly
   static already_AddRefed<File>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aData,
               const ChromeFilePropertyBag& aBag,
@@ -240,33 +183,45 @@ 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);
 
-protected:
-  virtual bool HasFileInterface() const override { return true; }
+  already_AddRefed<File> Slice(const Optional<int64_t>& aStart,
+                               const Optional<int64_t>& aEnd,
+                               const nsAString& aContentType,
+                               ErrorResult& aRv);
 
 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)
@@ -625,45 +580,45 @@ private:
   }
 
   ~FileImplMemory() {}
 
   // Used when backed by a memory store
   nsRefPtr<DataOwner> mDataOwner;
 };
 
-class FileImplTemporaryBlob final : public FileImplBase
+class FileImplTemporaryFileBlob final : public FileImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
-  FileImplTemporaryBlob(PRFileDesc* aFD, uint64_t aStartPos,
-                        uint64_t aLength, const nsAString& aContentType)
+  FileImplTemporaryFileBlob(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:
-  FileImplTemporaryBlob(const FileImplTemporaryBlob* aOther,
-                        uint64_t aStart, uint64_t aLength,
-                        const nsAString& aContentType)
+  FileImplTemporaryFileBlob(const FileImplTemporaryFileBlob* aOther,
+                            uint64_t aStart, uint64_t aLength,
+                            const nsAString& aContentType)
     : FileImplBase(aContentType, aLength)
     , mStartPos(aStart)
     , mFileDescOwner(aOther->mFileDescOwner)
   {}
 
-  ~FileImplTemporaryBlob() {}
+  ~FileImplTemporaryFileBlob() {}
 
   uint64_t mStartPos;
   nsRefPtr<nsTemporaryFileInputStream::FileDescOwner> mFileDescOwner;
 };
 
 class FileImplFile : public FileImplBase
 {
 public:
@@ -863,18 +818,17 @@ 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<Blob> blob =
-        Blob::CreateMemoryBlob(nullptr, mImgData, mImgSize, mType);
+      nsRefPtr<File> blob =
+        File::CreateMemoryFile(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<Blob> aBlob) = 0;
+  virtual nsresult ReceiveBlob(already_AddRefed<File> 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<Blob> blob = Blob::Create(scInfo->mPort->GetParentObject(),
-                                           blobImpl);
-        if (!ToJSValue(cx, blob, &val)) {
+        nsRefPtr<File> blob = new File(scInfo->mPort->GetParentObject(),
+                                             blobImpl);
+        if (!GetOrCreateDOMReflector(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.
   {
-    Blob* blob = nullptr;
+    File* 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<Blob> blob = data.GetAsBlob().get();
-      blobSet.AppendBlobImpl(blob->Impl());
+      nsRefPtr<File> file = data.GetAsBlob().get();
+      blobSet.AppendBlobImpl(file->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(Blob& aBlob,
+MultipartFileImpl::InitializeChromeFile(File& 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(Blob& aData,
+  void InitializeChromeFile(File& 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()) {
-      Blob& blob = aData.Value().GetAsBlob();
+      File& 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,
-                     Blob& aBlob,
+                     File& 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 Blob;
+class File;
 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,
-                              Blob& aBlob,
+                              File& 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(Blob& aData, ErrorResult& aRv)
+WebSocket::Send(File& 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 Blob;
+class File;
 
 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(Blob& aData,
+  void Send(File& 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<Blob> blob;
+  nsRefPtr<File> blob;
   if (blobData) {
     memcpy(blobData, aData.BeginReading(), blobLen);
-    blob = mozilla::dom::Blob::CreateMemoryBlob(aParent, blobData, blobLen,
+    blob = mozilla::dom::File::CreateMemoryFile(aParent, blobData, blobLen,
                                                 EmptyString());
   } else {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  if (!ToJSValue(aCx, blob, aBlob)) {
+  if (!GetOrCreateDOMReflector(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(Blob& aData, ErrorResult& aRv)
+nsDOMDataChannel::Send(File& 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 Blob;
+class File;
 }
 
 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::Blob& aData, mozilla::ErrorResult& aRv);
+  void Send(mozilla::dom::File& 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(mBlob)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFile)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMFileReader,
                                                 FileIOObject)
   tmp->mResultArrayBuffer = nullptr;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBlob)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFile)
 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* aBlob, JSContext* aCx)
+nsDOMFileReader::ReadAsArrayBuffer(nsIDOMBlob* aFile, JSContext* aCx)
 {
-  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
-  ReadAsArrayBuffer(aCx, *blob, rv);
+  nsRefPtr<File> file = static_cast<File*>(aFile);
+  ReadAsArrayBuffer(aCx, *file, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::ReadAsBinaryString(nsIDOMBlob* aBlob)
+nsDOMFileReader::ReadAsBinaryString(nsIDOMBlob* aFile)
 {
-  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
-  ReadAsBinaryString(*blob, rv);
+  nsRefPtr<File> file = static_cast<File*>(aFile);
+  ReadAsBinaryString(*file, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::ReadAsText(nsIDOMBlob* aBlob,
+nsDOMFileReader::ReadAsText(nsIDOMBlob* aFile,
                             const nsAString &aCharset)
 {
-  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
-  ReadAsText(*blob, aCharset, rv);
+  nsRefPtr<File> file = static_cast<File*>(aFile);
+  ReadAsText(*file, aCharset, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::ReadAsDataURL(nsIDOMBlob* aBlob)
+nsDOMFileReader::ReadAsDataURL(nsIDOMBlob* aFile)
 {
-  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
-  ReadAsDataURL(*blob, rv);
+  nsRefPtr<File> file = static_cast<File*>(aFile);
+  ReadAsDataURL(*file, 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;
   }
-  mBlob = nullptr;
+  mFile = 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> blob;
-  mBlob.swap(blob);
+  nsCOMPtr<nsIDOMBlob> file;
+  mFile.swap(file);
 
   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(blob, mCharset, "", mDataLen, mResult);
+        rv = GetAsText(file, mCharset, "", mDataLen, mResult);
         break;
       }
-      rv = GetAsText(blob, mCharset, mFileData, mDataLen, mResult);
+      rv = GetAsText(file, mCharset, mFileData, mDataLen, mResult);
       break;
     case FILE_AS_DATAURL:
-      rv = GetAsDataURL(blob, mFileData, mDataLen, mResult);
+      rv = GetAsDataURL(file, 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(Blob& aBlob,
+nsDOMFileReader::ReadFileContent(File& aFile,
                                  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();
 
-  mBlob = &aBlob;
+  mFile = &aFile;
   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 = mBlob->GetInternalStream(getter_AddRefs(stream));
+  rv = mFile->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(Blob& a
     return;
   }
 
   MOZ_ASSERT(!mAsyncStream);
   mAsyncStream = do_QueryInterface(wrapper);
   MOZ_ASSERT(mAsyncStream);
 
   mTotal = mozilla::dom::kUnknownSize;
-  mBlob->GetSize(&mTotal);
+  mFile->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(Blob& a
     if (!mFileData) {
       NS_WARNING("Preallocation failed for ReadFileData");
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     }
   }
 }
 
 nsresult
-nsDOMFileReader::GetAsText(nsIDOMBlob *aBlob,
+nsDOMFileReader::GetAsText(nsIDOMBlob *aFile,
                            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;
-      aBlob->GetType(type16);
+      aFile->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 *aBlob,
+nsDOMFileReader::GetAsDataURL(nsIDOMBlob *aFile,
                               const char *aFileData,
                               uint32_t aDataLen,
                               nsAString& aResult)
 {
   aResult.AssignLiteral("data:");
 
   nsresult rv;
   nsString contentType;
-  rv = aBlob->GetType(contentType);
+  rv = aFile->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,29 +22,28 @@
 #include "nsIDOMFileReader.h"
 #include "nsIDOMFileList.h"
 #include "nsCOMPtr.h"
 
 #include "FileIOObject.h"
 
 namespace mozilla {
 namespace dom {
-class Blob;
+class File;
 }
 }
 
 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::Blob Blob;
-
+  typedef mozilla::dom::File File;
 public:
   nsDOMFileReader();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMFILEREADER
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(mozilla::DOMEventTargetHelper)
@@ -64,27 +63,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, Blob& aBlob, ErrorResult& aRv)
+  void ReadAsArrayBuffer(JSContext* aCx, File& aBlob, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
   }
 
-  void ReadAsText(Blob& aBlob, const nsAString& aLabel, ErrorResult& aRv)
+  void ReadAsText(File& aBlob, const nsAString& aLabel, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, aLabel, FILE_AS_TEXT, aRv);
   }
 
-  void ReadAsDataURL(Blob& aBlob, ErrorResult& aRv)
+  void ReadAsDataURL(File& aBlob, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
   }
 
   using FileIOObject::Abort;
 
   // Inherited ReadyState().
 
@@ -98,17 +97,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(Blob& aBlob, ErrorResult& aRv)
+  void ReadAsBinaryString(File& aBlob, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, EmptyString(), FILE_AS_BINARY, aRv);
   }
 
 
   nsresult Init();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsDOMFileReader,
@@ -120,33 +119,31 @@ protected:
 
   enum eDataFormat {
     FILE_AS_ARRAYBUFFER,
     FILE_AS_BINARY,
     FILE_AS_TEXT,
     FILE_AS_DATAURL
   };
 
-  void ReadFileContent(Blob& aBlob,
+  void ReadFileContent(File& aBlob,
                        const nsAString &aCharset, eDataFormat aDataFormat,
                        ErrorResult& aRv);
-  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);
+  nsresult GetAsText(nsIDOMBlob *aFile, const nsACString &aCharset,
+                     const char *aFileData, uint32_t aDataLen, nsAString &aResult);
+  nsresult GetAsDataURL(nsIDOMBlob *aFile, const char *aFileData, uint32_t aDataLen, nsAString &aResult);
 
   void FreeFileData() {
     free(mFileData);
     mFileData = nullptr;
     mDataLen = 0;
   }
 
   char *mFileData;
-  nsCOMPtr<nsIDOMBlob> mBlob;
+  nsCOMPtr<nsIDOMBlob> mFile;
   nsCString mCharset;
   uint32_t mDataLen;
 
   eDataFormat mDataFormat;
 
   nsString mResult;
 
   JS::Heap<JSObject*> mResultArrayBuffer;
--- a/dom/base/nsFormData.cpp
+++ b/dom/base/nsFormData.cpp
@@ -17,44 +17,48 @@ 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.
-already_AddRefed<File>
-CreateNewFileInstance(Blob& aBlob, const Optional<nsAString>& aFilename)
+File*
+CreateNewFileInstance(File& 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 {
+  } else if (aBlob.IsFile()) {
     // If value is already a File and filename is not passed, the spec says not
     // to create a new instance.
-    nsRefPtr<File> file = aBlob.ToFile();
-    if (file) {
-      return file.forget();
-    }
-
+    return &aBlob;
+  } else {
     filename = NS_LITERAL_STRING("blob");
   }
 
-  return aBlob.ToFile(filename);
+  nsAutoTArray<nsRefPtr<FileImpl>, 1> blobImpls;
+  blobImpls.AppendElement(aBlob.Impl());
+
+  nsAutoString contentType;
+  aBlob.GetType(contentType);
+
+  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)
@@ -102,17 +106,17 @@ nsFormData::GetEncodedSubmission(nsIURI*
 
 void
 nsFormData::Append(const nsAString& aName, const nsAString& aValue)
 {
   AddNameValuePair(aName, aValue);
 }
 
 void
-nsFormData::Append(const nsAString& aName, Blob& aBlob,
+nsFormData::Append(const nsAString& aName, File& aBlob,
                    const Optional<nsAString>& aFilename)
 {
   nsRefPtr<File> file = CreateNewFileInstance(aBlob, aFilename);
   AddNameFilePair(aName, file);
 }
 
 void
 nsFormData::Delete(const nsAString& aName)
@@ -170,24 +174,16 @@ 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; ) {
@@ -201,17 +197,17 @@ nsFormData::RemoveAllOthersAndGetFirstFo
       lastFoundIndex = i;
     }
   }
 
   return lastFoundTuple;
 }
 
 void
-nsFormData::Set(const nsAString& aName, Blob& aBlob,
+nsFormData::Set(const nsAString& aName, File& 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);
@@ -244,17 +240,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<Blob> blob = static_cast<Blob*>(domBlob.get());
+    nsRefPtr<File> blob = static_cast<File*>(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,19 +30,17 @@ 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;
   };
 
@@ -58,21 +56,21 @@ private:
     MOZ_ASSERT(aData);
     aData->name = aName;
     aData->stringValue = aValue;
     aData->valueIsFile = false;
   }
 
   void SetNameFilePair(FormDataTuple* aData,
                        const nsAString& aName,
-                       File* aFile)
+                       File* aBlob)
   {
     MOZ_ASSERT(aData);
     aData->name = aName;
-    aData->fileValue = aFile;
+    aData->fileValue = aBlob;
     aData->valueIsFile = true;
   }
 
   void ExtractValue(const FormDataTuple& aTuple,
                     mozilla::dom::OwningFileOrUSVString* aOutValue);
 public:
   explicit nsFormData(nsISupports* aOwner = nullptr);
 
@@ -92,38 +90,43 @@ 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, Blob& aBlob,
+  void Append(const nsAString& aName, File& 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, Blob& aBlob,
+  void Set(const nsAString& aName, File& 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* aFile) override;
+                                   File* aBlob) override
+  {
+    FormDataTuple* data = mFormData.AppendElement();
+    SetNameFilePair(data, aName, aBlob);
+    return NS_OK;
+  }
 
   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<Blob>>& blobs = aData.mClosure.mBlobs;
+  const nsTArray<nsRefPtr<File>>& 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<Blob> domBlob = Blob::Create(nullptr, blobImpl);
+      nsRefPtr<File> domBlob = new File(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<Blob> blob = Blob::Create(scInfo->window, blobImpl);
-        if (!ToJSValue(cx, blob, &val)) {
+        nsRefPtr<File> blob = new File(scInfo->window, blobImpl);
+        if (!GetOrCreateDOMReflector(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.
   {
-    Blob* blob = nullptr;
+    File* 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/nsIDOMFile.idl
+++ b/dom/base/nsIDOMFile.idl
@@ -49,22 +49,18 @@ interface nsIDOMBlob : nsISupports
   // Called before the blob is stored in a database to decide if it can be
   // shared or needs to be copied. It can be called on any thread.
   [notxpcom] FileInfo getFileInfo(in FileManager aFileManager);
 
   // Return true if this blob is a memory file.
   [notxpcom] bool isMemoryFile();
 };
 
-// We want to avoid multiple inheritance of nsIDOMBlob so we can downcast from
-// nsIDOMBlob to Blob safely.  Our chain is:
-//  - Blob -> nsIDOMBlob
-//  - File -> nsIDOMFile and Blob
-[scriptable, builtinclass, uuid(cc28cf12-f1d4-44ff-843f-9289aa14613b)]
-interface nsIDOMFile : nsISupports
+[scriptable, builtinclass, uuid(74657f92-aa61-492b-8649-fd1cca62e255)]
+interface nsIDOMFile : nsIDOMBlob
 {
   readonly attribute DOMString name;
 
   readonly attribute DOMString path;
 
   [implicit_jscontext]
   readonly attribute jsval lastModifiedDate;
 
--- 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;
-  mDOMBlob = nullptr;
+  mDOMFile = 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(mDOMBlob)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMFile)
   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(mDOMBlob)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMFile)
   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 (mDOMBlob) {
+  if (mDOMFile) {
     // Use progress info to determine whether load is complete, but use
     // mDataAvailable to ensure a slice is created based on the uncompressed
     // data count.
     if (mLoadTotal == mLoadTransferred) {
-      mResponseBlob = mDOMBlob;
+      mResponseBlob = mDOMFile;
     } else {
       ErrorResult rv;
-      mResponseBlob = mDOMBlob->CreateSlice(0, mDataAvailable,
+      mResponseBlob = mDOMFile->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->mDOMBlob) {
+    if (!xmlHttpRequest->mDOMFile) {
       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::CreateDOMBlob(nsIRequest *request)
+bool nsXMLHttpRequest::CreateDOMFile(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);
 
-  mDOMBlob = File::CreateFromFile(GetOwner(), file, EmptyString(),
+  mDOMFile = 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) && !mDOMBlob) {
-    cancelable = CreateDOMBlob(request);
+       mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) && !mDOMFile) {
+    cancelable = CreateDOMFile(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
-    mDOMBlob->GetSize(&mDataAvailable);
+    mDOMFile->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 (!mDOMBlob) {
-      CreateDOMBlob(request);
+    if (!mDOMFile) {
+      CreateDOMFile(request);
     }
-    if (mDOMBlob) {
-      mResponseBlob = mDOMBlob;
-      mDOMBlob = nullptr;
+    if (mDOMFile) {
+      mResponseBlob = mDOMFile;
+      mDOMFile = 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::Blob& aBlob) : mType(Blob)
+    explicit RequestBody(mozilla::dom::File& 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::Blob* mBlob;
+      mozilla::dom::File* 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::Blob& aBlob, ErrorResult& aRv)
+  void Send(JSContext* /*aCx*/, mozilla::dom::File& 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 CreateDOMBlob(nsIRequest *request);
+  bool CreateDOMFile(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::Blob> mResponseBlob;
+  nsRefPtr<mozilla::dom::File> 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::Blob> mDOMBlob;
+  nsRefPtr<mozilla::dom::File> mDOMFile;
   // We stream data to mBlobSet when response type is "blob" or "moz-blob"
-  // and mDOMBlob is null.
+  // and mDOMFile 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,16 +133,17 @@ 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<Blob>>& blobs = mData->mClosure.mBlobs;
+    const nsTArray<nsRefPtr<File>>& 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<Blob>>& blobs = data->mClosure.mBlobs;
+  const nsTArray<nsRefPtr<File>>& 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<Blob>> blobs;
+  nsTArray<nsRefPtr<File>> files;
   if (!aData.blobsChild().IsEmpty()) {
-    blobs.SetCapacity(aData.blobsChild().Length());
+    files.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<Blob> blob = Blob::Create(mBC ? mBC->GetOwner() : nullptr, impl);
-      blobs.AppendElement(blob);
+      nsRefPtr<File> file = new File(mBC ? mBC->GetOwner() : nullptr, impl);
+      files.AppendElement(file);
     }
   }
 
   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(blobs);
+  cloneData.mClosure.mBlobs.SwapElements(files);
 
   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<Blob> blob = static_cast<Blob*>(aPicture);
+  nsRefPtr<File> blob = static_cast<File*>(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 =
-        Blob::CreateMemoryBlob(mDOMCameraControl.get(),
+        File::CreateMemoryFile(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,17 +24,16 @@
 #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;
@@ -218,26 +217,25 @@ public:
     return GetOwner();
   }
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   IMPL_EVENT_HANDLER(change)
 
   already_AddRefed<DOMRequest>
-  Add(mozilla::dom::Blob* aBlob, ErrorResult& aRv);
+  Add(nsIDOMBlob* aBlob, ErrorResult& aRv);
   already_AddRefed<DOMRequest>
-  AddNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath, ErrorResult& aRv);
+  AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
-  AppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
-              ErrorResult& aRv);
+  AppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
-  AddOrAppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
+  AddOrAppendNamed(nsIDOMBlob* 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,18 +100,17 @@ DeviceStorageRequestChild::
       break;
     }
 
     case DeviceStorageResponseValue::TBlobResponse:
     {
       BlobResponse r = aValue;
       BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
       nsRefPtr<FileImpl> bloblImpl = actor->GetBlobImpl();
-      nsRefPtr<Blob> blob = Blob::Create(mRequest->GetParentObject(),
-                                         bloblImpl);
+      nsRefPtr<File> blob = new File(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<FileImpl> blob =
+  nsRefPtr<File> blob = new File(nullptr,
     new FileImplFile(fullPath, mime, mLength, mFile->mFile,
-                     mLastModificationDate);
+                     mLastModificationDate));
 
   ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
-  BlobParent* actor = cp->GetOrCreateActorForFileImpl(blob);
+  BlobParent* actor = cp->GetOrCreateActorForBlob(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, Blob* aBlob)
+DeviceStorageTypeChecker::Check(const nsAString& aType, nsIDOMBlob* 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 = Blob::Create(aWindow,
+  nsCOMPtr<nsIDOMBlob> blob = new File(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,
-                       Blob* aBlob = nullptr)
+                       nsIDOMBlob* 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<Blob*>(mBlob.get()));
+              static_cast<File*>(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<Blob*>(mBlob.get()));
+              static_cast<File*>(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;
-  nsRefPtr<Blob> mBlob;
+  nsCOMPtr<nsIDOMBlob> 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(static_cast<Blob*>(aBlob), rv);
+  nsRefPtr<DOMRequest> request = Add(aBlob, rv);
   request.forget(_retval);
   return rv.StealNSResult();
 }
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::Add(Blob* aBlob, ErrorResult& aRv)
+nsDOMDeviceStorage::Add(nsIDOMBlob* 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(Blob* aBlob, Err
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::AddNamed(nsIDOMBlob *aBlob,
                              const nsAString & aPath,
                              nsIDOMDOMRequest * *_retval)
 {
   ErrorResult rv;
-  nsRefPtr<DOMRequest> request = AddNamed(static_cast<Blob*>(aBlob), aPath, rv);
+  nsRefPtr<DOMRequest> request = AddNamed(aBlob, aPath, rv);
   request.forget(_retval);
   return rv.StealNSResult();
 }
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::AddNamed(Blob* aBlob, const nsAString& aPath,
+nsDOMDeviceStorage::AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
                              ErrorResult& aRv)
 {
   return AddOrAppendNamed(aBlob, aPath,
                           DEVICE_STORAGE_REQUEST_CREATE, aRv);
 }
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::AppendNamed(Blob* aBlob, const nsAString& aPath,
+nsDOMDeviceStorage::AppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
                                 ErrorResult& aRv)
 {
   return AddOrAppendNamed(aBlob, aPath,
                           DEVICE_STORAGE_REQUEST_APPEND, aRv);
 }
 
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::AddOrAppendNamed(Blob* aBlob, const nsAString& aPath,
+nsDOMDeviceStorage::AddOrAppendNamed(nsIDOMBlob* 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,20 +28,16 @@ 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"
@@ -156,17 +152,17 @@ class DeviceStorageTypeChecker final
 public:
   static DeviceStorageTypeChecker* CreateOrGet();
 
   DeviceStorageTypeChecker();
   ~DeviceStorageTypeChecker();
 
   void InitFromBundle(nsIStringBundle* aBundle);
 
-  bool Check(const nsAString& aType, mozilla::dom::Blob* aBlob);
+  bool Check(const nsAString& aType, nsIDOMBlob* 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,21 +303,17 @@ DataTransfer::GetFiles(ErrorResult& aRv)
       nsRefPtr<File> domFile;
       if (file) {
         domFile = File::CreateFromFile(GetParentObject(), file);
       } else {
         nsCOMPtr<FileImpl> fileImpl = do_QueryInterface(supports);
         if (!fileImpl) {
           continue;
         }
-
-        MOZ_ASSERT(fileImpl->IsFile());
-
-        domFile = File::Create(GetParentObject(), fileImpl);
-        MOZ_ASSERT(domFile);
+        domFile = new File(GetParentObject(), static_cast<FileImpl*>(fileImpl.get()));
       }
 
       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 Blob& aBlob, nsIInputStream** aStream,
+ExtractFromBlob(const File& aFile, nsIInputStream** aStream,
                 nsCString& aContentType)
 {
-  nsRefPtr<FileImpl> impl = aBlob.Impl();
+  nsRefPtr<FileImpl> impl = aFile.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<Blob> file =
+      nsRefPtr<File> 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 Blob& blob = aBodyInit.GetAsBlob();
+    const File& 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 Blob& blob = aBodyInit.GetAsBlob();
+    const File& 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,20 +1502,19 @@ 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<dom::Blob> blob =
-        Blob::CreateMemoryBlob(DerivedClass()->GetParentObject(),
-                               reinterpret_cast<void *>(aResult), aResultLength,
-                               NS_ConvertUTF8toUTF16(mMimeType));
+      nsRefPtr<File> blob =
+        File::CreateMemoryFile(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 Blob& aValue, uint64_t* aInputLength,
+FileHandleBase::GetInputStream(const File& aValue, uint64_t* aInputLength,
                                ErrorResult& aRv)
 {
-  Blob& file = const_cast<Blob&>(aValue);
+  File& file = const_cast<File&>(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 Blob;
+class File;
 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 Blob& aValue, uint64_t* aInputLength,
+  GetInputStream(const File& 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,
-                               Blob* aBlobData,
+                               File* 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,17 +122,19 @@ CreateFileTask::GetRequestParams(const n
   }
   return param;
 }
 
 FileSystemResponseValue
 CreateFileTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
-  BlobParent* actor = GetBlobParent(mTargetFileImpl);
+  nsRefPtr<File> file = new File(mFileSystem->GetWindow(),
+                                       mTargetFileImpl);
+  BlobParent* actor = GetBlobParent(file);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
 
@@ -296,18 +298,18 @@ CreateFileTask::HandlerCallback()
     nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
       mErrorValue);
     mPromise->MaybeRejectBrokenly(domError);
     mPromise = nullptr;
     mBlobData = nullptr;
     return;
   }
 
-  nsRefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetFileImpl);
-  mPromise->MaybeResolve(blob);
+  nsCOMPtr<nsIDOMFile> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
+  mPromise->MaybeResolve(file);
   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 Blob;
+class File;
 class FileImpl;
 class Promise;
 
 class CreateFileTask final
   : public FileSystemTaskBase
 {
 public:
   CreateFileTask(FileSystemBase* aFileSystem,
                  const nsAString& aPath,
-                 Blob* aBlobData,
+                 File* 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<Blob> mBlobData;
+  nsRefPtr<File> 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<Blob> blobData;
+  nsRefPtr<File> 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,43 +149,33 @@ bool
 FileSystemTaskBase::Recv__delete__(const FileSystemResponseValue& aValue)
 {
   SetRequestResult(aValue);
   HandlerCallback();
   return true;
 }
 
 BlobParent*
-FileSystemTaskBase::GetBlobParent(FileImpl* aFile) const
+FileSystemTaskBase::GetBlobParent(nsIDOMFile* 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);
-
-  // 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();
-  }
+  uint64_t fileSize;
+  aFile->GetSize(&fileSize);
+  int64_t lastModifiedDate;
+  aFile->GetMozLastModifiedDate(&lastModifiedDate);
 
   ContentParent* cp = static_cast<ContentParent*>(mRequestParent->Manager());
-  return cp->GetOrCreateActorForFileImpl(aFile);
+  return cp->GetOrCreateActorForBlob(static_cast<File*>(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,21 +6,22 @@
 
 #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
@@ -199,17 +200,17 @@ protected:
   bool
   HasError() const { return mErrorValue != NS_OK; }
 
   // Overrides PFileSystemRequestChild
   virtual bool
   Recv__delete__(const FileSystemResponseValue& value) override;
 
   BlobParent*
-  GetBlobParent(FileImpl* aFile) const;
+  GetBlobParent(nsIDOMFile* 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,17 +77,18 @@ GetFileOrDirectoryTask::GetRequestParams
 FileSystemResponseValue
 GetFileOrDirectoryTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mIsDirectory) {
     return FileSystemDirectoryResponse(mTargetRealPath);
   }
 
-  BlobParent* actor = GetBlobParent(mTargetFileImpl);
+  nsRefPtr<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
+  BlobParent* actor = GetBlobParent(file);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
 
@@ -208,18 +209,18 @@ GetFileOrDirectoryTask::HandlerCallback(
 
   if (mIsDirectory) {
     nsRefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
     mPromise->MaybeResolve(dir);
     mPromise = nullptr;
     return;
   }
 
-  nsRefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetFileImpl);
-  mPromise->MaybeResolve(blob);
+  nsRefPtr<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
+  mPromise->MaybeResolve(file);
   mPromise = nullptr;
 }
 
 void
 GetFileOrDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
 {
   aAccess.AssignLiteral("read");
 }
--- a/dom/filesystem/RemoveTask.cpp
+++ b/dom/filesystem/RemoveTask.cpp
@@ -87,20 +87,19 @@ 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<Blob> blob = Blob::Create(mFileSystem->GetWindow(),
-                                       mTargetFileImpl);
+    nsRefPtr<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
     BlobChild* actor
-      = ContentChild::GetSingleton()->GetOrCreateActorForBlob(blob);
+      = ContentChild::GetSingleton()->GetOrCreateActorForBlob(file);
     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<Blob> aBlob)
+    nsresult ReceiveBlob(already_AddRefed<File> aBlob)
     {
-      nsRefPtr<Blob> blob = aBlob;
+      nsRefPtr<File> 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<Blob> newBlob = Blob::Create(mGlobal, blob->Impl());
+      nsRefPtr<File> newBlob = new File(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,18 +556,17 @@ 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] = File::Create(global, mFileList[i]->Impl());
-      MOZ_ASSERT(mFileList[i]);
+      mFileList[i] = new File(global, mFileList[i]->Impl());
     }
 
     // The text control frame (if there is one) isn't going to send a change
     // event because it will think this is done by a script.
     // So, we can safely send one by ourself.
     mInput->SetFiles(mFileList, true);
     nsresult rv =
       nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
@@ -2343,20 +2342,17 @@ 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) {
-    nsRefPtr<File> file = File::Create(global, aFiles[i].get()->Impl());
-    MOZ_ASSERT(file);
-
-    files.AppendElement(file);
+    files.AppendElement(new File(global, aFiles[i].get()->Impl()));
   }
   SetFiles(files, true);
 }
 
 void
 HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv)
 {
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
@@ -6017,19 +6013,17 @@ 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 = File::Create(global, fileImpls[i]);
-            MOZ_ASSERT(file);
-
+            nsRefPtr<File> file = new File(global, fileImpls[i]);
             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,22 +72,21 @@ public:
     : nsEncodingFormSubmission(aCharset, aOriginatingElement),
       mMethod(aMethod),
       mDocument(aDocument),
       mWarnedFileControl(false)
   {
   }
 
   virtual nsresult AddNameValuePair(const nsAString& aName,
-                                    const nsAString& aValue) override;
+                                    const nsAString& aValue);
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   File* aFile) override;
+                                   File* aBlob);
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
-                                        nsIInputStream** aPostDataStream)
-                                                                       override;
+                                        nsIInputStream** aPostDataStream);
 
   virtual bool SupportsIsindexSubmission()
   {
     return true;
   }
 
   virtual nsresult AddIsindex(const nsAString& aValue);
 
@@ -161,26 +160,26 @@ nsFSURLEncoded::AddIsindex(const nsAStri
     mQueryString += NS_LITERAL_CSTRING("&isindex=") + convValue;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsFSURLEncoded::AddNameFilePair(const nsAString& aName,
-                                File* aFile)
+                                File* aBlob)
 {
   if (!mWarnedFileControl) {
     SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nullptr, 0);
     mWarnedFileControl = true;
   }
 
   nsAutoString filename;
-  if (aFile) {
-    aFile->GetName(filename);
+  if (aBlob && aBlob->IsFile()) {
+    aBlob->GetName(filename);
   }
 
   return AddNameValuePair(aName, filename);
 }
 
 static void
 HandleMailtoSubject(nsCString& aPath) {
 
@@ -435,59 +434,62 @@ nsFSMultipartFormData::AddNameValuePair(
                  + nameStr + NS_LITERAL_CSTRING("\"" CRLF CRLF)
                  + valueStr + NS_LITERAL_CSTRING(CRLF);
 
   return NS_OK;
 }
 
 nsresult
 nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
-                                       File* aFile)
+                                       File* aBlob)
 {
   // Encode the control name
   nsAutoCString nameStr;
   nsresult rv = EncodeVal(aName, nameStr, true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCString filename, contentType;
   nsCOMPtr<nsIInputStream> fileStream;
-  if (aFile) {
+  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());
     nsAutoString filename16;
-    rv = aFile->GetName(filename16);
+    rv = aBlob->GetName(filename16);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsAutoString filepath16;
-    rv = aFile->GetPath(filepath16);
+    rv = aBlob->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 = aFile->GetType(contentType16);
+    rv = aBlob->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 = aFile->GetInternalStream(getter_AddRefs(fileStream));
+    rv = aBlob->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);
 
@@ -512,17 +514,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(aFile->GetSize(&size))) {
+  if (fileStream && NS_SUCCEEDED(aBlob->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;
   }
 
@@ -580,22 +582,21 @@ class nsFSTextPlain : public nsEncodingF
 {
 public:
   nsFSTextPlain(const nsACString& aCharset, nsIContent* aOriginatingElement)
     : nsEncodingFormSubmission(aCharset, aOriginatingElement)
   {
   }
 
   virtual nsresult AddNameValuePair(const nsAString& aName,
-                                    const nsAString& aValue) override;
+                                    const nsAString& aValue);
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   File* aFile) override;
+                                   File* aBlob);
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
-                                        nsIInputStream** aPostDataStream)
-                                                                       override;
+                                        nsIInputStream** aPostDataStream);
 
 private:
   nsString mBody;
 };
 
 nsresult
 nsFSTextPlain::AddNameValuePair(const nsAString& aName,
                                 const nsAString& aValue)
@@ -606,21 +607,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* aFile)
+                               File* aBlob)
 {
   nsAutoString filename;
-  if (aFile) {
-    aFile->GetName(filename);
+  if (aBlob && aBlob->IsFile()) {
+    aBlob->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 aFile the file to submit. The file's name will be used
+   * @param aBlob the file to submit. The file's name will be used
    */
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   mozilla::dom::File* aFile) = 0;
+                                   mozilla::dom::File* aBlob) = 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* aFile) override;
+                                   mozilla::dom::File* aBlob) 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<Blob> blob = Blob::Create(aDatabase->GetOwner(), blobImpl);
+      nsRefPtr<File> blob = new File(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->mBlob.swap(blob);
+      file->mFile.swap(blob);
       file->mFileInfo.swap(fileInfo);
     }
   }
 }
 
 void
 DispatchErrorEvent(IDBRequest* aRequest,
                    nsresult aErrorCode,
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -7713,17 +7713,16 @@ 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(Blob* aBlob)
+IDBDatabase::GetOrCreateFileActorForBlob(File* 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(Blob* aBlob)
+IDBDatabase::NoteReceivedBlob(File* 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 Blob;
+class File;
 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(Blob* aBlob);
+  GetOrCreateFileActorForBlob(File* aBlob);
 
   void
   NoteFinishedFileActor(PBackgroundIDBDatabaseFileChild* aFileActor);
 
   void
-  NoteReceivedBlob(Blob* aBlob);
+  NoteReceivedBlob(File* 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,20 +335,18 @@ IDBMutableFile::CreateFileObject(IDBFile
   nsRefPtr<FileImpl> impl =
     new FileImplSnapshot(mName,
                          mType,
                          aMetadataParams,
                          mFile,
                          aFileHandle,
                          mFileInfo);
 
-  nsRefPtr<File> file = File::Create(GetOwner(), impl);
-  MOZ_ASSERT(file);
-
-  return file.forget();
+  nsCOMPtr<nsIDOMFile> fileSnapshot = new File(GetOwner(), impl);
+  return fileSnapshot.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<Blob> mBlob;
+    nsRefPtr<File> 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;
   }
 
   {
-    Blob* blob = nullptr;
+    File* 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,26 +327,25 @@ 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;
       }
 
-      nsRefPtr<File> file = blob->ToFile();
-      if (file) {
+      if (blob->IsFile()) {
         int64_t lastModifiedDate;
         MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
-          file->GetMozLastModifiedDate(&lastModifiedDate)));
+          blob->GetMozLastModifiedDate(&lastModifiedDate)));
 
         lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate);
 
         nsString name;
-        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(file->GetName(name)));
+        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetName(name)));
 
         NS_ConvertUTF16toUTF8 convName(name);
         uint32_t convNameLength =
           NativeEndian::swapToLittleEndian(convName.Length());
 
         if (!JS_WriteBytes(aWriter, &lastModifiedDate, sizeof(lastModifiedDate)) || 
             !JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
             !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
@@ -398,21 +397,21 @@ GetAddInfoCallback(JSContext* aCx, void*
                                                 &data->mCloneWriteInfo)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   return NS_OK;
 }
 
 BlobChild*
-ActorFromRemoteFileImpl(FileImpl* aImpl)
+ActorFromRemoteBlob(File* aBlob)
 {
-  MOZ_ASSERT(aImpl);
+  MOZ_ASSERT(aBlob);
 
-  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aImpl);
+  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob->Impl());
   if (remoteBlob) {
     BlobChild* actor = remoteBlob->GetBlobChild();
     MOZ_ASSERT(actor);
 
     if (actor->GetContentManager()) {
       return nullptr;
     }
 
@@ -424,36 +423,36 @@ ActorFromRemoteFileImpl(FileImpl* aImpl)
 
     return actor;
   }
 
   return nullptr;
 }
 
 bool
-ResolveMysteryFile(FileImpl* aImpl,
+ResolveMysteryFile(File* aBlob,
                    const nsString& aName,
                    const nsString& aContentType,
                    uint64_t aSize,
                    uint64_t aLastModifiedDate)
 {
-  BlobChild* actor = ActorFromRemoteFileImpl(aImpl);
+  BlobChild* actor = ActorFromRemoteBlob(aBlob);
   if (actor) {
     return actor->SetMysteryBlobInfo(aName, aContentType,
                                      aSize, aLastModifiedDate);
   }
   return true;
 }
 
 bool
-ResolveMysteryBlob(FileImpl* aImpl,
+ResolveMysteryBlob(File* aBlob,
                    const nsString& aContentType,
                    uint64_t aSize)
 {
-  BlobChild* actor = ActorFromRemoteFileImpl(aImpl);
+  BlobChild* actor = ActorFromRemoteBlob(aBlob);
   if (actor) {
     return actor->SetMysteryBlobInfo(aContentType, aSize);
   }
   return true;
 }
 
 bool
 StructuredCloneReadString(JSStructuredCloneReader* aReader,
@@ -601,17 +600,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.mBlob);
+    MOZ_ASSERT(aFile.mFile);
 
     // 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 {
@@ -623,49 +622,46 @@ 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.mBlob->Impl(),
+      if (NS_WARN_IF(!ResolveMysteryBlob(aFile.mFile,
                                          aData.type,
                                          aData.size))) {
         return false;
       }
 
-      MOZ_ASSERT(!aFile.mBlob->IsFile());
-
       JS::Rooted<JS::Value> wrappedBlob(aCx);
-      if (!ToJSValue(aCx, aFile.mBlob, &wrappedBlob)) {
+      if (!GetOrCreateDOMReflector(aCx, aFile.mFile, &wrappedBlob)) {
         return false;
       }
 
       aResult.set(&wrappedBlob.toObject());
       return true;
     }
 
-    if (NS_WARN_IF(!ResolveMysteryFile(aFile.mBlob->Impl(),
+    MOZ_ASSERT(aFile.mFile->IsFile());
+
+    if (NS_WARN_IF(!ResolveMysteryFile(aFile.mFile,
                                        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 (!ToJSValue(aCx, file, &wrappedFile)) {
+    if (!GetOrCreateDOMReflector(aCx, aFile.mFile, &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 Blob;
+class File;
 
 namespace indexedDB {
 
 class FileInfo;
 class IDBDatabase;
 class SerializedStructuredCloneReadInfo;
 
 struct StructuredCloneFile
 {
-  nsRefPtr<Blob> mBlob;
+  nsRefPtr<File> mFile;
   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->mBlob == aOther.mBlob &&
+  return this->mFile == aOther.mFile &&
          this->mFileInfo == aOther.mFileInfo;
 }
 
 inline
 StructuredCloneReadInfo::StructuredCloneReadInfo()
   : mDatabase(nullptr)
 {
   MOZ_COUNT_CTOR(StructuredCloneReadInfo);
--- a/dom/ipc/FilePickerParent.cpp
+++ b/dom/ipc/FilePickerParent.cpp
@@ -112,19 +112,20 @@ 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++) {
-    BlobParent* blobParent = parent->GetOrCreateActorForFileImpl(aFiles[i]);
-    if (blobParent) {
-      files.AppendElement(blobParent);
+    nsRefPtr<File> file = new File(nullptr, aFiles[i]);
+    BlobParent* blob = parent->GetOrCreateActorForBlob(file);
+    if (blob) {
+      files.AppendElement(blob);
     }
   }
 
   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<Blob> blob = closure->mBlobs[aData];
+      nsRefPtr<File> blob = closure->mBlobs[aData];
 
 #ifdef DEBUG
       {
-        // Blob should not be mutable.
+        // File 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<Blob> newBlob = Blob::Create(global, blob->Impl());
-      if (!ToJSValue(aCx, newBlob, &val)) {
+      nsRefPtr<File> newBlob = new File(global, blob->Impl());
+      if (!GetOrCreateDOMReflector(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.
   {
-    Blob* blob = nullptr;
+    File* 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<Blob>> mBlobs;
+  nsTArray<nsRefPtr<File>> 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,34 +88,25 @@ nsIContentChild::AllocPBlobChild(const B
 bool
 nsIContentChild::DeallocPBlobChild(PBlobChild* aActor)
 {
   BlobChild::Destroy(aActor);
   return true;
 }
 
 BlobChild*
-nsIContentChild::GetOrCreateActorForBlob(Blob* aBlob)
+nsIContentChild::GetOrCreateActorForBlob(File* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
 
   nsRefPtr<FileImpl> blobImpl = aBlob->Impl();
   MOZ_ASSERT(blobImpl);
 
-  return GetOrCreateActorForFileImpl(blobImpl);
-}
-
-BlobChild*
-nsIContentChild::GetOrCreateActorForFileImpl(FileImpl* aImpl)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aImpl);
-
-  BlobChild* actor = BlobChild::GetOrCreate(this, aImpl);
+  BlobChild* actor = BlobChild::GetOrCreate(this, blobImpl);
   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,33 +27,31 @@ namespace mozilla {
 
 namespace jsipc {
 class PJavaScriptChild;
 class CpowEntry;
 } // jsipc
 
 namespace dom {
 
-class Blob;
 class BlobChild;
 class BlobConstructorParams;
 class ClonedMessageData;
-class FileImpl;
+class File;
 class IPCTabContext;
 class PBlobChild;
 class PBrowserChild;
 
 class nsIContentChild : public nsISupports
                       , public CPOWManagerGetter
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTCHILD_IID)
 
-  BlobChild* GetOrCreateActorForBlob(Blob* aBlob);
-  BlobChild* GetOrCreateActorForFileImpl(FileImpl* aImpl);
+  BlobChild* GetOrCreateActorForBlob(File* aBlob);
 
   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,34 +154,25 @@ nsIContentParent::AllocPBlobParent(const
 bool
 nsIContentParent::DeallocPBlobParent(PBlobParent* aActor)
 {
   BlobParent::Destroy(aActor);
   return true;
 }
 
 BlobParent*
-nsIContentParent::GetOrCreateActorForBlob(Blob* aBlob)
+nsIContentParent::GetOrCreateActorForBlob(File* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
 
   nsRefPtr<FileImpl> blobImpl = aBlob->Impl();
   MOZ_ASSERT(blobImpl);
 
-  return GetOrCreateActorForFileImpl(blobImpl);
-}
-
-BlobParent*
-nsIContentParent::GetOrCreateActorForFileImpl(FileImpl* aImpl)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aImpl);
-
-  BlobParent* actor = BlobParent::GetOrCreate(this, aImpl);
+  BlobParent* actor = BlobParent::GetOrCreate(this, blobImpl);
   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,36 +28,34 @@ namespace mozilla {
 
 namespace jsipc {
 class PJavaScriptParent;
 class CpowEntry;
 } // namespace jsipc
 
 namespace dom {
 
-class Blob;
 class BlobConstructorParams;
 class BlobParent;
 class ContentParent;
-class FileImpl;
+class File;
 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(Blob* aBlob);
-  BlobParent* GetOrCreateActorForFileImpl(FileImpl* aImpl);
+  BlobParent* GetOrCreateActorForBlob(File* aBlob);
 
   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::Blob>
+already_AddRefed<dom::File>
 EncodedBufferCache::ExtractBlob(nsISupports* aParent,
                                 const nsAString &aContentType)
 {
   MutexAutoLock lock(mMutex);
-  nsRefPtr<dom::Blob> blob;
+  nsRefPtr<dom::File> blob;
   if (mTempFileEnabled) {
     // generate new temporary file to write
-    blob = dom::Blob::CreateTemporaryBlob(aParent, mFD, 0, mDataSize,
-                                          aContentType);
+    blob = dom::File::CreateTemporaryFileBlob(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::Blob::CreateMemoryBlob(aParent, blobData, mDataSize,
+      blob = dom::File::CreateMemoryFile(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 Blob;
+class File;
 }
 
 /**
  * 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::Blob> ExtractBlob(nsISupports* aParent, const nsAString &aContentType);
+  already_AddRefed<dom::File> 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<Blob*>(blob.get());
+  init.mData = static_cast<File*>(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::Blob> aBlob, nsresult aRv)
+CaptureTask::TaskComplete(already_AddRefed<dom::File> aBlob, nsresult aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   DetachStream();
 
   nsresult rv;
-  nsRefPtr<dom::Blob> blob(aBlob);
+  nsRefPtr<dom::File> blob(aBlob);
 
   // We have to set the parent because the blob has been generated with a valid one.
   if (blob) {
-    blob = dom::Blob::Create(mImageCapture->GetParentObject(), blob->Impl());
+    blob = new dom::File(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::Blob> aBlob) override
+    nsresult ReceiveBlob(already_AddRefed<dom::File> aBlob) override
     {
-      nsRefPtr<dom::Blob> blob(aBlob);
+      nsRefPtr<dom::File> 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 Blob;
+class File;
 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::Blob> aBlob, nsresult aRv);
+  nsresult TaskComplete(already_AddRefed<dom::File> 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(Blob* aBlob)
+ImageCapture::PostBlobEvent(File* 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 Blob;
+class File;
 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(Blob* aBlob);
+  nsresult PostBlobEvent(File* 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 = Blob::Create(nullptr, impl);
+      att.mContent = new File(nullptr, impl);
     } else if (element.contentChild()) {
       nsRefPtr<FileImpl> impl = static_cast<BlobChild*>(element.contentChild())->GetBlobImpl();
-      att.mContent = Blob::Create(nullptr, impl);
+      att.mContent = new File(nullptr, impl);
     } else {
       NS_WARNING("MmsMessage: Unable to get attachment content.");
     }
     mAttachments.AppendElement(att);
   }
 
   len = aData.deliveryInfo().Length();
   mDeliveryInfo.SetCapacity(len);
@@ -385,23 +385,20 @@ 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.
-    nsRefPtr<FileImpl> impl = element.content->Impl();
-    if (impl && impl->IsDateUnknown()) {
-      ErrorResult rv;
-      impl->GetLastModified(rv);
-      if (rv.Failed()) {
+    if (element.content->IsDateUnknown()) {
+      int64_t date;
+      if (NS_FAILED(element.content->GetMozLastModifiedDate(&date))) {
         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);
@@ -575,20 +572,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<Blob> newBlob = Blob::Create(global, attachment.content->Impl());
+    nsRefPtr<File> newBlob = new File(global, attachment.content->Impl());
 
     JS::Rooted<JS::Value> val(aCx);
-    if (!ToJSValue(aCx, newBlob, &val)) {
+    if (!GetOrCreateDOMReflector(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 Blob;
+class File;
 
 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<Blob> content;
+    nsRefPtr<File> 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<Blob> blob = Blob::Create(global, blobImpl);
-    if (!ToJSValue(aContext, blob, &content)) {
+    nsRefPtr<File> blob = new File(global, blobImpl);
+    if (!GetOrCreateDOMReflector(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()) {
-    Blob& blob = aData.GetAsBlob();
+    File& 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,
-                                  Blob& aBlob,
+                                  File& 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(Blob& aBlob,
+FileReaderSync::ReadAsBinaryString(File& 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(Blob&
     if (aResult.Length() - oldLength != numRead) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return;
     }
   } while (numRead > 0);
 }
 
 void
-FileReaderSync::ReadAsText(Blob& aBlob,
+FileReaderSync::ReadAsText(File& 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(Blob& aBlob,
   rv = ConvertStream(stream, encoding.get(), aResult);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 }
 
 void
-FileReaderSync::ReadAsDataURL(Blob& aBlob, nsAString& aResult,
+FileReaderSync::ReadAsDataURL(File& 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 Blob;
+class File;
 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,
-                         Blob& aBlob, JS::MutableHandle<JSObject*> aRetval,
+                         File& aBlob, JS::MutableHandle<JSObject*> aRetval,
                          ErrorResult& aRv);
-  void ReadAsBinaryString(Blob& aBlob, nsAString& aResult, ErrorResult& aRv);
-  void ReadAsText(Blob& aBlob, const Optional<nsAString>& aEncoding,
+  void ReadAsBinaryString(File& aBlob, nsAString& aResult, ErrorResult& aRv);
+  void ReadAsText(File& aBlob, const Optional<nsAString>& aEncoding,
                   nsAString& aResult, ErrorResult& aRv);
-  void ReadAsDataURL(Blob& aBlob, nsAString& aResult, ErrorResult& aRv);
+  void ReadAsDataURL(File& 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::Blob*
+mozilla::dom::File*
 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,19 +20,18 @@
 #endif
 
 #include "nsProxyRelease.h"
 
 class nsIInterceptedChannel;
 
 namespace mozilla {
 namespace dom {
-class Blob;
-class Request;
-class ResponseOrPromise;
+  class Request;
+  class ResponseOrPromise;
 } // namespace dom
 } // namespace mozilla
 
 BEGIN_WORKERS_NAMESPACE
 
 class ServiceWorkerClient;
 
 class FetchEvent final : public Event
@@ -172,17 +171,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::Blob* Blob();
+  mozilla::dom::File* 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, Blob& aBlob,
+URL::CreateObjectURL(const GlobalObject& aGlobal, File& 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 Blob;
+class File;
 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,
-                  Blob& aArg, const objectURLOptions& aOptions,
+                  File& 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<Blob>
+already_AddRefed<File>
 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<Blob> blob = Blob::Create(parent, blobImpl);
+  nsRefPtr<File> blob = new File(parent, blobImpl);
   return blob.forget();
 }
 
 void
 ReadBlobOrFile(JSContext* aCx,
                JSStructuredCloneReader* aReader,
                bool aIsMainThread,
                JS::MutableHandle<JSObject*> aBlobOrFile)
 {
-  nsRefPtr<Blob> blob = ReadBlobOrFileNoWrap(aCx, aReader, aIsMainThread);
+  nsRefPtr<File> 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<Blob> blob = ReadBlobOrFileNoWrap(aCx, aReader, aIsMainThread);
+      nsRefPtr<File> 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<Blob> blob;
+      nsRefPtr<File> 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<Blob> blob;
+      nsRefPtr<File> 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(Blob& aBody, ErrorResult& aRv)
+XMLHttpRequest::Send(File& 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 Blob;
+class File;
 }
 }
 
 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(Blob& aBody, ErrorResult& aRv);
+  Send(File& 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<Blob*>(aBlob)->Impl();
+  nsRefPtr<FileImpl> blobImpl = static_cast<File*>(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<Blob> blob = Blob::Create(global, cloneData->mBlobImpls[idx]);
-            if (!ToJSValue(cx, blob, &val)) {
+            nsRefPtr<File> blob = new File(global, cloneData->mBlobImpls[idx]);
+            if (!GetOrCreateDOMReflector(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);
 
     {
-        Blob* blob = nullptr;
+        File* 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,22 +153,19 @@ 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);
 
-      if (!blobImpl->IsFile()) {
-        return true;
-      }
-
-      nsRefPtr<File> file = File::Create(mParent, blobImpl);
-      MOZ_ASSERT(file);
+      nsCOMPtr<nsIDOMBlob> blob = new File(mParent, blobImpl);
+      nsCOMPtr<nsIDOMFile> file(do_QueryInterface(blob));
+      NS_ENSURE_TRUE(file, true);
 
       mDomfiles.AppendObject(file);
     }
   }
 
   if (mCallback) {
     mCallback->Done(aResult);
     mCallback = nullptr;