Merge inbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 12 May 2015 16:24:41 -0700
changeset 274326 d476776d920d65eb6b53a94d01054945a5d7e437
parent 274270 de1fd9d0682a7c0b7301d02b92a88276f6e50faa (current diff)
parent 274325 5fcc4f1b36605b672b49f4b72cfa5b2f0c9fa43d (diff)
child 274352 62d9b117c688edcf38349b197adde657aec75f47
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c a=merge
dom/base/MultipartFileImpl.cpp
dom/base/MultipartFileImpl.h
js/src/tests/ecma/Date/15.9.5.2-2-n.js
js/src/tests/ecma/extensions/15.9.5.js
js/src/tests/ecma_2/Exceptions/date-001.js
js/src/tests/js1_4/Regress/date-001-n.js
toolkit/devtools/server/actors/script.js
--- a/accessible/atk/nsMaiHyperlink.cpp
+++ b/accessible/atk/nsMaiHyperlink.cpp
@@ -216,17 +216,17 @@ getEndIndexCB(AtkHyperlink *aLink)
   uint32_t endIdx = maiLink->Proxy()->EndOffset(&valid);
   return valid ? static_cast<gint>(endIdx) : -1;
 }
 
 gint
 getStartIndexCB(AtkHyperlink *aLink)
 {
   MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
-  if (maiLink)
+  if (!maiLink)
     return -1;
 
   if (Accessible* hyperlink = maiLink->GetAccHyperlink())
     return static_cast<gint>(hyperlink->StartOffset());
 
   bool valid = false;
   uint32_t startIdx = maiLink->Proxy()->StartOffset(&valid);
   return valid ? static_cast<gint>(startIdx) : -1;
--- a/b2g/chrome/content/content.css
+++ b/b2g/chrome/content/content.css
@@ -25,29 +25,24 @@ html xul|scrollbar[root="true"] {
 html xul|scrollbar {
   -moz-appearance: none !important;
   background-color: transparent !important;
   background-image: none !important;
   border: 0px solid transparent !important;
   pointer-events: none;
 }
 
+/* Scrollbar code will reset the margin to the correct side depending on
+   where layout actually puts the scrollbar */
 xul|scrollbar[orient="vertical"] {
-  -moz-margin-start: -8px;
+  margin-left: -8px;
   min-width: 8px;
   max-width: 8px;
 }
 
-/* workaround for bug 1119057: as -moz-margin-start may not work as expected,
- * force a right margin value in RTL mode.  */
-[dir="rtl"] xul|scrollbar[root="true"][orient="vertical"] {
-  -moz-margin-start: unset;
-  margin-right: -8px;
-}
-
 xul|scrollbar[orient="vertical"] xul|thumb {
   max-width: 6px !important;
   min-width: 6px !important;
 }
 
 xul|scrollbar[orient="horizontal"] {
   margin-top: -8px;
   min-height: 8px;
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -335,17 +335,16 @@ skip-if = buildapp == 'mulet'
 
 [browser_parsable_css.js]
 skip-if = e10s
 [browser_parsable_script.js]
 skip-if = asan # Disabled because it takes a long time (see test for more information)
 
 [browser_pinnedTabs.js]
 [browser_plainTextLinks.js]
-skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and gets in a mess when in e10s mode
 [browser_popupUI.js]
 skip-if = buildapp == 'mulet'
 [browser_popup_blocker.js]
 skip-if = e10s && debug # Frequent bug 1125520 failures
 [browser_printpreview.js]
 skip-if = buildapp == 'mulet' || e10s # Bug 1101973 - breaks the next test in e10s, and may be responsible for later timeout after logging "Error: Channel closing: too late to send/recv, messages will be lost"
 [browser_private_browsing_window.js]
 skip-if = buildapp == 'mulet'
--- a/browser/base/content/test/general/browser_plainTextLinks.js
+++ b/browser/base/content/test/general/browser_plainTextLinks.js
@@ -1,115 +1,146 @@
-let doc, range, selection;
-function setSelection(el1, el2, index1, index2) {
-  while (el1.nodeType != Node.TEXT_NODE)
-    el1 = el1.firstChild;
-  while (el2.nodeType != Node.TEXT_NODE)
-    el2 = el2.firstChild;
-
-  selection.removeAllRanges();
-  range.setStart(el1, index1);
-  range.setEnd(el2, index2);
-  selection.addRange(range);
+function testExpected(expected, msg) {
+  is(document.getElementById("context-openlinkincurrent").hidden, expected, msg);
 }
 
-function initContextMenu(aNode) {
-  document.popupNode = aNode;
-  let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
-  let contextMenu = new nsContextMenu(contentAreaContextMenu);
-  return contextMenu;
-}
-
-function testExpected(expected, msg, aNode) {
-  let popupNode = aNode || doc.getElementsByTagName("DIV")[0];
-  initContextMenu(popupNode);
-  let linkMenuItem = document.getElementById("context-openlinkincurrent");
-  is(linkMenuItem.hidden, expected, msg);
-}
-
-function testLinkExpected(expected, msg, aNode) {
-  let popupNode = aNode || doc.getElementsByTagName("DIV")[0];
-  let contextMenu = initContextMenu(popupNode);
-  is(contextMenu.linkURL, expected, msg);
+function testLinkExpected(expected, msg) {
+  is(gContextMenu.linkURL, expected, msg);
 }
 
-function runSelectionTests() {
-  let mainDiv = doc.createElement("div");
-  let div = doc.createElement("div");
-  let div2 = doc.createElement("div");
-  let span1 = doc.createElement("span");
-  let span2 = doc.createElement("span");
-  let span3 = doc.createElement("span");
-  let span4 = doc.createElement("span");
-  let p1 = doc.createElement("p");
-  let p2 = doc.createElement("p");
-  span1.textContent = "http://index.";
-  span2.textContent = "example.com example.com";
-  span3.textContent = " - Test";
-  span4.innerHTML = "<a href='http://www.example.com'>http://www.example.com/example</a>";
-  p1.textContent = "mailto:test.com ftp.example.com";
-  p2.textContent = "example.com   -";
-  div.appendChild(span1);
-  div.appendChild(span2);
-  div.appendChild(span3);
-  div.appendChild(span4);
-  div.appendChild(p1);
-  div.appendChild(p2);
-  let p3 = doc.createElement("p");
-  p3.textContent = "main.example.com";
-  div2.appendChild(p3);
-  mainDiv.appendChild(div);
-  mainDiv.appendChild(div2);
-  doc.body.appendChild(mainDiv);
-  setSelection(span1.firstChild, span2.firstChild, 0, 11);
-  testExpected(false, "The link context menu should show for http://www.example.com");
-  setSelection(span1.firstChild, span2.firstChild, 7, 11);
-  testExpected(false, "The link context menu should show for www.example.com");
-  setSelection(span1.firstChild, span2.firstChild, 8, 11);
-  testExpected(true, "The link context menu should not show for ww.example.com");
-  setSelection(span2.firstChild, span2.firstChild, 0, 11);
-  testExpected(false, "The link context menu should show for example.com");
-  testLinkExpected("http://example.com/", "url for example.com selection should not prepend www");
-  setSelection(span2.firstChild, span2.firstChild, 11, 23);
-  testExpected(false, "The link context menu should show for example.com");
-  setSelection(span2.firstChild, span2.firstChild, 0, 10);
-  testExpected(true, "Link options should not show for selection that's not at a word boundary");
-  setSelection(span2.firstChild, span3.firstChild, 12, 7);
-  testExpected(true, "Link options should not show for selection that has whitespace");
-  setSelection(span2.firstChild, span2.firstChild, 12, 19);
-  testExpected(true, "Link options should not show unless a url is selected");
-  setSelection(p1.firstChild, p1.firstChild, 0, 15);
-  testExpected(true, "Link options should not show for mailto: links");
-  setSelection(p1.firstChild, p1.firstChild, 16, 31);
-  testExpected(false, "Link options should show for ftp.example.com");
-  testLinkExpected("ftp://ftp.example.com/", "ftp.example.com should be preceeded with ftp://");
-  setSelection(p2.firstChild, p2.firstChild, 0, 14);
-  testExpected(false, "Link options should show for www.example.com  ");
-  selection.selectAllChildren(div2);
-  testExpected(false, "Link options should show for triple-click selections");
-  selection.selectAllChildren(span4);
-  testLinkExpected("http://www.example.com/", "Linkified text should open the correct link", span4.firstChild);
+add_task(function *() {
+  const url = "data:text/html;charset=UTF-8,Test For Non-Hyperlinked url selection";
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
+
+  yield SimpleTest.promiseFocus(gBrowser.selectedBrowser.contentWindowAsCPOW);
+
+  // Initial setup of the content area.
+  yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* (arg) {
+    let doc = content.document;
+    let range = doc.createRange();
+    let selection = content.getSelection();
+
+    let mainDiv = doc.createElement("div");
+    let div = doc.createElement("div");
+    let div2 = doc.createElement("div");
+    let span1 = doc.createElement("span");
+    let span2 = doc.createElement("span");
+    let span3 = doc.createElement("span");
+    let span4 = doc.createElement("span");
+    let p1 = doc.createElement("p");
+    let p2 = doc.createElement("p");
+    span1.textContent = "http://index.";
+    span2.textContent = "example.com example.com";
+    span3.textContent = " - Test";
+    span4.innerHTML = "<a href='http://www.example.com'>http://www.example.com/example</a>";
+    p1.textContent = "mailto:test.com ftp.example.com";
+    p2.textContent = "example.com   -";
+    div.appendChild(span1);
+    div.appendChild(span2);
+    div.appendChild(span3);
+    div.appendChild(span4);
+    div.appendChild(p1);
+    div.appendChild(p2);
+    let p3 = doc.createElement("p");
+    p3.textContent = "main.example.com";
+    div2.appendChild(p3);
+    mainDiv.appendChild(div);
+    mainDiv.appendChild(div2);
+    doc.body.appendChild(mainDiv);
+
+    function setSelection(el1, el2, index1, index2) {
+      while (el1.nodeType != el1.TEXT_NODE)
+        el1 = el1.firstChild;
+      while (el2.nodeType != el1.TEXT_NODE)
+        el2 = el2.firstChild;
+
+      selection.removeAllRanges();
+      range.setStart(el1, index1);
+      range.setEnd(el2, index2);
+      selection.addRange(range);
+
+      return range;
+    }
 
-  mainDiv.innerHTML = "(open-suse.ru)";
-  setSelection(mainDiv, mainDiv, 1, 13);
-  testExpected(false, "Link options should show for open-suse.ru");
-  testLinkExpected("http://open-suse.ru/", "Linkified text should open the correct link");
-  setSelection(mainDiv, mainDiv, 1, 14);
-  testExpected(true, "Link options should not show for 'open-suse.ru)'");
+    // Each of these tests creates a selection and returns a range within it.
+    content.tests = [
+      () => setSelection(span1.firstChild, span2.firstChild, 0, 11),
+      () => setSelection(span1.firstChild, span2.firstChild, 7, 11),
+      () => setSelection(span1.firstChild, span2.firstChild, 8, 11),
+      () => setSelection(span2.firstChild, span2.firstChild, 0, 11),
+      () => setSelection(span2.firstChild, span2.firstChild, 11, 23),
+      () => setSelection(span2.firstChild, span2.firstChild, 0, 10),
+      () => setSelection(span2.firstChild, span3.firstChild, 12, 7),
+      () => setSelection(span2.firstChild, span2.firstChild, 12, 19),
+      () => setSelection(p1.firstChild, p1.firstChild, 0, 15),
+      () => setSelection(p1.firstChild, p1.firstChild, 16, 31),
+      () => setSelection(p2.firstChild, p2.firstChild, 0, 14),
+      () => {
+        selection.selectAllChildren(div2);
+        return selection.getRangeAt(0);
+      },
+      () => {
+        selection.selectAllChildren(span4);
+        return selection.getRangeAt(0);
+      },
+      () => {
+        mainDiv.innerHTML = "(open-suse.ru)";
+        return setSelection(mainDiv, mainDiv, 1, 13);
+      },
+      () => setSelection(mainDiv, mainDiv, 1, 14)
+    ];
+  });
+
+  let checks = [
+    () => testExpected(false, "The link context menu should show for http://www.example.com"),
+    () => testExpected(false, "The link context menu should show for www.example.com"),
+    () => testExpected(true, "The link context menu should not show for ww.example.com"),
+    () => {
+      testExpected(false, "The link context menu should show for example.com");
+      testLinkExpected("http://example.com/", "url for example.com selection should not prepend www");
+    },
+    () => testExpected(false, "The link context menu should show for example.com"),
+    () => testExpected(true, "Link options should not show for selection that's not at a word boundary"),
+    () => testExpected(true, "Link options should not show for selection that has whitespace"),
+    () => testExpected(true, "Link options should not show unless a url is selected"),
+    () => testExpected(true, "Link options should not show for mailto: links"),
+    () => {
+      testExpected(false, "Link options should show for ftp.example.com");
+      testLinkExpected("ftp://ftp.example.com/", "ftp.example.com should be preceeded with ftp://");
+    },
+    () => testExpected(false, "Link options should show for www.example.com  "),
+    () => testExpected(false, "Link options should show for triple-click selections"),
+    () => testLinkExpected("http://www.example.com/", "Linkified text should open the correct link"),
+    () => {
+      testExpected(false, "Link options should show for open-suse.ru");
+      testLinkExpected("http://open-suse.ru/", "Linkified text should open the correct link");
+    },
+    () => testExpected(true, "Link options should not show for 'open-suse.ru)'")
+  ];
+
+  let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
+
+  for (let testid = 0; testid < checks.length; testid++) {
+    let menuPosition = yield ContentTask.spawn(gBrowser.selectedBrowser, { testid: testid }, function* (arg) {
+      let range = content.tests[arg.testid]();
+
+      // Get the range of the selection and determine its coordinates. These
+      // coordinates will be returned to the parent process and the context menu
+      // will be opened at that location.
+      let rangeRect = range.getBoundingClientRect();
+      return [rangeRect.x + 3, rangeRect.y + 3];
+    });
+
+    let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
+    yield BrowserTestUtils.synthesizeMouseAtPoint(menuPosition[0], menuPosition[1],
+          { type: "contextmenu", button: 2 }, gBrowser.selectedBrowser);
+    yield popupShownPromise;
+
+    checks[testid]();
+
+    let popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");
+    contentAreaContextMenu.hidePopup();
+    yield popupHiddenPromise;  
+  }
 
   gBrowser.removeCurrentTab();
-  finish();
-}
+});
 
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    doc = content.document;
-    range = doc.createRange();
-    selection = content.getSelection();
-    waitForFocus(runSelectionTests, content);
-  }, true);
-
-  content.location =
-    "data:text/html;charset=UTF-8,Test For Non-Hyperlinked url selection";
-}
--- a/browser/themes/linux/devtools/floating-scrollbars.css
+++ b/browser/themes/linux/devtools/floating-scrollbars.css
@@ -4,18 +4,20 @@ scrollbar {
   -moz-appearance: none !important;
   position: relative;
   background-color: transparent;
   background-image: none;
   z-index: 2147483647;
   padding: 2px;
 }
 
+/* Scrollbar code will reset the margin to the correct side depending on
+   where layout actually puts the scrollbar */
 scrollbar[orient="vertical"] {
-  -moz-margin-start: -10px;
+  margin-left: -10px;
   min-width: 10px;
   max-width: 10px;
 }
 
 scrollbar[orient="horizontal"] {
   margin-top: -10px;
   min-height: 10px;
   max-height: 10px;
--- a/browser/themes/osx/devtools/floating-scrollbars.css
+++ b/browser/themes/osx/devtools/floating-scrollbars.css
@@ -5,18 +5,20 @@ scrollbar {
   position: relative;
   background-color: transparent;
   background-image: none;
   border: 0px solid transparent;
   z-index: 2147483647;
   padding: 2px;
 }
 
+/* Scrollbar code will reset the margin to the correct side depending on
+   where layout actually puts the scrollbar */
 scrollbar[orient="vertical"] {
-  -moz-margin-start: -8px;
+  margin-left: -8px;
   min-width: 8px;
   max-width: 8px;
 }
 
 scrollbar[orient="horizontal"] {
   margin-top: -8px;
   min-height: 8px;
   max-height: 8px;
--- a/browser/themes/windows/devtools/floating-scrollbars.css
+++ b/browser/themes/windows/devtools/floating-scrollbars.css
@@ -4,18 +4,20 @@ scrollbar {
   -moz-appearance: none !important;
   position: relative;
   background-color: transparent;
   background-image: none;
   z-index: 2147483647;
   padding: 2px;
 }
 
+/* Scrollbar code will reset the margin to the correct side depending on
+   where layout actually puts the scrollbar */
 scrollbar[orient="vertical"] {
-  -moz-margin-start: -10px;
+  margin-left: -10px;
   min-width: 10px;
   max-width: 10px;
 }
 
 scrollbar[orient="horizontal"] {
   margin-top: -10px;
   min-height: 10px;
   max-height: 10px;
--- a/dom/archivereader/ArchiveEvent.cpp
+++ b/dom/archivereader/ArchiveEvent.cpp
@@ -100,17 +100,17 @@ ArchiveReaderEvent::RunShare(nsresult aS
   NS_DispatchToMainThread(event);
 
   return NS_OK;
 }
 
 void
 ArchiveReaderEvent::ShareMainThread()
 {
-  nsTArray<nsCOMPtr<nsIDOMFile> > fileList;
+  nsTArray<nsRefPtr<File>> fileList;
 
   if (!NS_FAILED(mStatus)) {
     // This extra step must run in the main thread:
     for (uint32_t index = 0; index < mFileList.Length(); ++index) {
       nsRefPtr<ArchiveItem> item = mFileList[index];
 
       nsString tmp;
       nsresult rv = item->GetFilename(tmp);
@@ -126,17 +126,17 @@ ArchiveReaderEvent::ShareMainThread()
         // Just to be sure, if something goes wrong, the mimetype is an empty string:
         nsCString type;
         if (NS_SUCCEEDED(GetType(filename, type))) {
           item->SetType(type);
         }
       }
 
       // This is a File:
-      nsRefPtr<nsIDOMFile> file = item->File(mArchiveReader);
+      nsRefPtr<File> file = item->GetFile(mArchiveReader);
       if (file) {
         fileList.AppendElement(file);
       }
     }
   }
 
   mArchiveReader->Ready(fileList, mStatus);
 }
--- a/dom/archivereader/ArchiveEvent.h
+++ b/dom/archivereader/ArchiveEvent.h
@@ -31,17 +31,17 @@ public:
   // Getter/Setter for the type
   nsCString GetType();
   void SetType(const nsCString& aType);
 
   // Getter for the filename
   virtual nsresult GetFilename(nsString& aFilename) = 0;
 
   // Generate a File
-  virtual nsIDOMFile* File(ArchiveReader* aArchiveReader) = 0;
+  virtual already_AddRefed<File> GetFile(ArchiveReader* aArchiveReader) = 0;
 
 protected:
   virtual ~ArchiveItem();
 
   nsCString mType;
 };
 
 /**
--- a/dom/archivereader/ArchiveReader.cpp
+++ b/dom/archivereader/ArchiveReader.cpp
@@ -19,17 +19,17 @@
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 USING_ARCHIVEREADER_NAMESPACE
 
 /* static */ already_AddRefed<ArchiveReader>
 ArchiveReader::Constructor(const GlobalObject& aGlobal,
-                           File& aBlob,
+                           Blob& aBlob,
                            const ArchiveReaderOptions& aOptions,
                            ErrorResult& aError)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aError.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
@@ -41,19 +41,19 @@ ArchiveReader::Constructor(const GlobalO
     return nullptr;
   }
 
   nsRefPtr<ArchiveReader> reader =
     new ArchiveReader(aBlob, window, encoding);
   return reader.forget();
 }
 
-ArchiveReader::ArchiveReader(File& aBlob, nsPIDOMWindow* aWindow,
+ArchiveReader::ArchiveReader(Blob& aBlob, nsPIDOMWindow* aWindow,
                              const nsACString& aEncoding)
-  : mFileImpl(aBlob.Impl())
+  : mBlobImpl(aBlob.Impl())
   , mWindow(aWindow)
   , mStatus(NOT_STARTED)
   , mEncoding(aEncoding)
 {
   MOZ_ASSERT(aWindow);
 }
 
 ArchiveReader::~ArchiveReader()
@@ -90,26 +90,26 @@ ArchiveReader::RegisterRequest(ArchiveRe
   return NS_OK;
 }
 
 // This returns the input stream
 nsresult
 ArchiveReader::GetInputStream(nsIInputStream** aInputStream)
 {
   // Getting the input stream
-  mFileImpl->GetInternalStream(aInputStream);
+  mBlobImpl->GetInternalStream(aInputStream);
   NS_ENSURE_TRUE(*aInputStream, NS_ERROR_UNEXPECTED);
   return NS_OK;
 }
 
 nsresult
 ArchiveReader::GetSize(uint64_t* aSize)
 {
   ErrorResult rv;
-  *aSize = mFileImpl->GetSize(rv);
+  *aSize = mBlobImpl->GetSize(rv);
   return rv.StealNSResult();
 }
 
 // Here we open the archive:
 nsresult
 ArchiveReader::OpenArchive()
 {
   mStatus = WORKING;
@@ -131,17 +131,17 @@ ArchiveReader::OpenArchive()
   // we increase the refcount here:
   AddRef();
 
   return NS_OK;
 }
 
 // Data received from the dispatched event:
 void
-ArchiveReader::Ready(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
+ArchiveReader::Ready(nsTArray<nsRefPtr<File>>& aFileList,
                      nsresult aStatus)
 {
   mStatus = READY;
  
   // Let's store the values:
   mData.fileList = aFileList;
   mData.status = aStatus;
 
@@ -194,17 +194,17 @@ ArchiveReader::GetFiles()
 already_AddRefed<ArchiveRequest>
 ArchiveReader::GenerateArchiveRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   return ArchiveRequest::Create(mWindow, this);
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ArchiveReader,
-                                      mFileImpl,
+                                      mBlobImpl,
                                       mWindow,
                                       mData.fileList,
                                       mRequests)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ArchiveReader)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
--- a/dom/archivereader/ArchiveReader.h
+++ b/dom/archivereader/ArchiveReader.h
@@ -8,24 +8,24 @@
 #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 BlobImpl;
 class File;
-class FileImpl;
 class GlobalObject;
 } // namespace dom
 } // namespace mozilla
 
 BEGIN_ARCHIVEREADER_NAMESPACE
 
 class ArchiveRequest;
 
@@ -35,20 +35,20 @@ class ArchiveRequest;
 class ArchiveReader final : public nsISupports,
                             public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ArchiveReader)
 
   static already_AddRefed<ArchiveReader>
-  Constructor(const GlobalObject& aGlobal, File& aBlob,
+  Constructor(const GlobalObject& aGlobal, Blob& aBlob,
               const ArchiveReaderOptions& aOptions, ErrorResult& aError);
 
-  ArchiveReader(File& aBlob, nsPIDOMWindow* aWindow,
+  ArchiveReader(Blob& aBlob, nsPIDOMWindow* aWindow,
                 const nsACString& aEncoding);
 
   nsIDOMWindow* GetParentObject() const
   {
     return mWindow;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -59,36 +59,35 @@ public:
 
   nsresult GetInputStream(nsIInputStream** aInputStream);
   nsresult GetSize(uint64_t* aSize);
 
 public: // for the ArchiveRequest:
   nsresult RegisterRequest(ArchiveRequest* aRequest);
 
 public: // For events:
-  FileImpl* GetFileImpl() const
+  BlobImpl* GetBlobImpl() const
   {
-    return mFileImpl;
+    return mBlobImpl;
   }
 
-  void Ready(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
-             nsresult aStatus);
+  void Ready(nsTArray<nsRefPtr<File>>& aFileList, nsresult aStatus);
 
 private:
   ~ArchiveReader();
 
   already_AddRefed<ArchiveRequest> GenerateArchiveRequest();
 
   nsresult OpenArchive();
 
   void RequestReady(ArchiveRequest* aRequest);
 
 protected:
   // The archive blob/file
-  nsRefPtr<FileImpl> mFileImpl;
+  nsRefPtr<BlobImpl> mBlobImpl;
 
   // The window is needed by the requests
   nsCOMPtr<nsPIDOMWindow> mWindow;
 
   // Are we ready to return data?
   enum {
     NOT_STARTED = 0,
     WORKING,
@@ -103,17 +102,17 @@ protected:
     Search  // ... if the data length is unknown (== 0) we wait until we read a new header 
   } mReadStatus;
 
   // List of requests to be processed
   nsTArray<nsRefPtr<ArchiveRequest> > mRequests;
 
   // Everything related to the blobs and the status:
   struct {
-    nsTArray<nsCOMPtr<nsIDOMFile> > fileList;
+    nsTArray<nsRefPtr<File>> fileList;
     nsresult status;
   } mData;
 
   nsCString mEncoding;
 };
 
 END_ARCHIVEREADER_NAMESPACE
 
--- a/dom/archivereader/ArchiveRequest.cpp
+++ b/dom/archivereader/ArchiveRequest.cpp
@@ -117,17 +117,17 @@ ArchiveRequest::OpGetFile(const nsAStrin
 
 void
 ArchiveRequest::OpGetFiles()
 {
   mOperation = GetFiles;
 }
 
 nsresult
-ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
+ArchiveRequest::ReaderReady(nsTArray<nsRefPtr<File>>& aFileList,
                             nsresult aStatus)
 {
   if (NS_FAILED(aStatus)) {
     FireError(aStatus);
     return NS_OK;
   }
 
   nsresult rv;
@@ -169,28 +169,28 @@ ArchiveRequest::ReaderReady(nsTArray<nsC
   }
 
   return NS_OK;
 }
 
 nsresult
 ArchiveRequest::GetFilenamesResult(JSContext* aCx,
                                    JS::Value* aValue,
-                                   nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
+                                   nsTArray<nsRefPtr<File>>& aFileList)
 {
   JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aFileList.Length()));
   nsresult rv;
 
   if (!array) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   JS::Rooted<JSString*> str(aCx);
   for (uint32_t i = 0; i < aFileList.Length(); ++i) {
-    nsCOMPtr<nsIDOMFile> file = aFileList[i];
+    nsRefPtr<File> file = aFileList[i];
 
     nsString filename;
     rv = file->GetName(filename);
     NS_ENSURE_SUCCESS(rv, rv);
 
     str = JS_NewUCStringCopyZ(aCx, filename.get());
     NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
 
@@ -206,52 +206,56 @@ ArchiveRequest::GetFilenamesResult(JSCon
 
   *aValue = OBJECT_TO_JSVAL(array);
   return NS_OK;
 }
 
 nsresult
 ArchiveRequest::GetFileResult(JSContext* aCx,
                               JS::MutableHandle<JS::Value> aValue,
-                              nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
+                              nsTArray<nsRefPtr<File>>& aFileList)
 {
   for (uint32_t i = 0; i < aFileList.Length(); ++i) {
-    nsCOMPtr<nsIDOMFile> file = aFileList[i];
+    nsRefPtr<File> file = aFileList[i];
 
     nsString filename;
     nsresult rv = file->GetName(filename);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (filename == mFilename) {
-      return nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile),
-                                        aValue);
+      if (!ToJSValue(aCx, file, aValue)) {
+        return NS_ERROR_FAILURE;
+      }
+
+      return NS_OK;
     }
   }
 
   return NS_ERROR_FAILURE;
 }
 
 nsresult
 ArchiveRequest::GetFilesResult(JSContext* aCx,
                                JS::MutableHandle<JS::Value> aValue,
-                               nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
+                               nsTArray<nsRefPtr<File>>& aFileList)
 {
   JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aFileList.Length()));
   if (!array) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   for (uint32_t i = 0; i < aFileList.Length(); ++i) {
-    nsCOMPtr<nsIDOMFile> file = aFileList[i];
+    nsRefPtr<File> file = aFileList[i];
 
     JS::Rooted<JS::Value> value(aCx);
-    nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile),
-                                             &value);
-    if (NS_FAILED(rv) ||
-        !JS_DefineElement(aCx, array, i, value, JSPROP_ENUMERATE)) {
+    if (!ToJSValue(aCx, file, &value)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    if (!JS_DefineElement(aCx, array, i, value, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   aValue.setObject(*array);
   return NS_OK;
 }
 
--- a/dom/archivereader/ArchiveRequest.h
+++ b/dom/archivereader/ArchiveRequest.h
@@ -44,35 +44,34 @@ public:
   // This is called by the DOMArchiveRequestEvent
   void Run();
 
   // Set the types for this request
   void OpGetFilenames();
   void OpGetFile(const nsAString& aFilename);
   void OpGetFiles();
 
-  nsresult ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
-                       nsresult aStatus);
+  nsresult ReaderReady(nsTArray<nsRefPtr<File>>& aFileList, nsresult aStatus);
 
 public: // static
   static already_AddRefed<ArchiveRequest> Create(nsPIDOMWindow* aOwner,
                                                  ArchiveReader* aReader);
 
 private:
   ~ArchiveRequest();
 
   nsresult GetFilenamesResult(JSContext* aCx,
                               JS::Value* aValue,
-                              nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
+                              nsTArray<nsRefPtr<File>>& aFileList);
   nsresult GetFileResult(JSContext* aCx,
                          JS::MutableHandle<JS::Value> aValue,
-                         nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
+                         nsTArray<nsRefPtr<File>>& aFileList);
   nsresult GetFilesResult(JSContext* aCx,
                           JS::MutableHandle<JS::Value> aValue,
-                          nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
+                          nsTArray<nsRefPtr<File>>& aFileList);
 
 protected:
   // The reader:
   nsRefPtr<ArchiveReader> mArchiveReader;
 
   // The operation:
   enum {
     GetFilenames,
--- a/dom/archivereader/ArchiveZipEvent.cpp
+++ b/dom/archivereader/ArchiveZipEvent.cpp
@@ -70,30 +70,32 @@ ArchiveZipItem::GetFilename(nsString& aF
     }
   }
 
   aFilename = mFilenameU;
   return NS_OK;
 }
 
 // From zipItem to File:
-nsIDOMFile*
-ArchiveZipItem::File(ArchiveReader* aArchiveReader)
+already_AddRefed<File>
+ArchiveZipItem::GetFile(ArchiveReader* aArchiveReader)
 {
   nsString filename;
 
   if (NS_FAILED(GetFilename(filename))) {
     return nullptr;
   }
 
-  return new dom::File(aArchiveReader,
-    new ArchiveZipFileImpl(filename,
+  nsRefPtr<dom::File> file = dom::File::Create(aArchiveReader,
+    new ArchiveZipBlobImpl(filename,
                            NS_ConvertUTF8toUTF16(GetType()),
                            StrToInt32(mCentralStruct.orglen),
-                           mCentralStruct, aArchiveReader->GetFileImpl()));
+                           mCentralStruct, aArchiveReader->GetBlobImpl()));
+  MOZ_ASSERT(file);
+  return file.forget();
 }
 
 uint32_t
 ArchiveZipItem::StrToInt32(const uint8_t* aStr)
 {
   return (uint32_t)( (aStr [0] <<  0) |
                      (aStr [1] <<  8) |
                      (aStr [2] << 16) |
--- a/dom/archivereader/ArchiveZipEvent.h
+++ b/dom/archivereader/ArchiveZipEvent.h
@@ -26,17 +26,18 @@ public:
                  const nsACString& aEncoding);
 protected:
   virtual ~ArchiveZipItem();
 
 public:
   nsresult GetFilename(nsString& aFilename) override;
 
   // From zipItem to File:
-  virtual nsIDOMFile* File(ArchiveReader* aArchiveReader) override;
+  virtual already_AddRefed<File>
+  GetFile(ArchiveReader* aArchiveReader) override;
 
 public: // for the event
   static uint32_t StrToInt32(const uint8_t* aStr);
   static uint16_t StrToInt16(const uint8_t* aStr);
 
 private:
   nsresult ConvertFilename();
 
--- a/dom/archivereader/ArchiveZipFile.cpp
+++ b/dom/archivereader/ArchiveZipFile.cpp
@@ -348,53 +348,53 @@ ArchiveInputStream::Tell(int64_t *aResul
 }
 
 NS_IMETHODIMP
 ArchiveInputStream::SetEOF()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-// ArchiveZipFileImpl
+// ArchiveZipBlobImpl
 
 nsresult
-ArchiveZipFileImpl::GetInternalStream(nsIInputStream** aStream)
+ArchiveZipBlobImpl::GetInternalStream(nsIInputStream** aStream)
 {
   if (mLength > INT32_MAX) {
     return NS_ERROR_FAILURE;
   }
 
   ErrorResult rv;
-  uint64_t size = mFileImpl->GetSize(rv);
+  uint64_t size = mBlobImpl->GetSize(rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
   nsCOMPtr<nsIInputStream> inputStream;
-  rv = mFileImpl->GetInternalStream(getter_AddRefs(inputStream));
+  rv = mBlobImpl->GetInternalStream(getter_AddRefs(inputStream));
   if (NS_WARN_IF(rv.Failed()) || !inputStream) {
     return NS_ERROR_UNEXPECTED;
   }
 
   nsRefPtr<ArchiveInputStream> stream = new ArchiveInputStream(size,
                                                                inputStream,
                                                                mFilename,
                                                                mStart,
                                                                mLength,
                                                                mCentral);
 
   stream.forget(aStream);
   return NS_OK;
 }
 
-already_AddRefed<mozilla::dom::FileImpl>
-ArchiveZipFileImpl::CreateSlice(uint64_t aStart,
+already_AddRefed<mozilla::dom::BlobImpl>
+ArchiveZipBlobImpl::CreateSlice(uint64_t aStart,
                                 uint64_t aLength,
                                 const nsAString& aContentType,
                                 mozilla::ErrorResult& aRv)
 {
-  nsRefPtr<FileImpl> impl =
-    new ArchiveZipFileImpl(mFilename, mContentType, aStart, mLength, mCentral,
-                           mFileImpl);
+  nsRefPtr<BlobImpl> impl =
+    new ArchiveZipBlobImpl(mFilename, mContentType, aStart, mLength, mCentral,
+                           mBlobImpl);
   return impl.forget();
 }
 
-NS_IMPL_ISUPPORTS_INHERITED0(ArchiveZipFileImpl, FileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(ArchiveZipBlobImpl, BlobImpl)
--- a/dom/archivereader/ArchiveZipFile.h
+++ b/dom/archivereader/ArchiveZipFile.h
@@ -14,66 +14,66 @@
 #include "ArchiveReader.h"
 
 #include "ArchiveReaderCommon.h"
 #include "zipstruct.h"
 
 BEGIN_ARCHIVEREADER_NAMESPACE
 
 /**
- * ArchiveZipFileImpl to FileImpl
+ * ArchiveZipBlobImpl to BlobImpl
  */
-class ArchiveZipFileImpl : public FileImplBase
+class ArchiveZipBlobImpl : public BlobImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
-  ArchiveZipFileImpl(const nsAString& aName,
+  ArchiveZipBlobImpl(const nsAString& aName,
                      const nsAString& aContentType,
                      uint64_t aLength,
                      ZipCentral& aCentral,
-                     FileImpl* aFileImpl)
-  : FileImplBase(aName, aContentType, aLength),
+                     BlobImpl* aBlobImpl)
+  : BlobImplBase(aName, aContentType, aLength),
     mCentral(aCentral),
-    mFileImpl(aFileImpl),
+    mBlobImpl(aBlobImpl),
     mFilename(aName)
   {
-    MOZ_ASSERT(mFileImpl);
-    MOZ_COUNT_CTOR(ArchiveZipFileImpl);
+    MOZ_ASSERT(mBlobImpl);
+    MOZ_COUNT_CTOR(ArchiveZipBlobImpl);
   }
 
-  ArchiveZipFileImpl(const nsAString& aName,
+  ArchiveZipBlobImpl(const nsAString& aName,
                      const nsAString& aContentType,
                      uint64_t aStart,
                      uint64_t aLength,
                      ZipCentral& aCentral,
-                     FileImpl* aFileImpl)
-  : FileImplBase(aContentType, aStart, aLength),
+                     BlobImpl* aBlobImpl)
+  : BlobImplBase(aContentType, aStart, aLength),
     mCentral(aCentral),
-    mFileImpl(aFileImpl),
+    mBlobImpl(aBlobImpl),
     mFilename(aName)
   {
-    MOZ_ASSERT(mFileImpl);
-    MOZ_COUNT_CTOR(ArchiveZipFileImpl);
+    MOZ_ASSERT(mBlobImpl);
+    MOZ_COUNT_CTOR(ArchiveZipBlobImpl);
   }
 
   // Overrides:
   virtual nsresult GetInternalStream(nsIInputStream**) override;
 protected:
-  virtual ~ArchiveZipFileImpl()
+  virtual ~ArchiveZipBlobImpl()
   {
-    MOZ_COUNT_DTOR(ArchiveZipFileImpl);
+    MOZ_COUNT_DTOR(ArchiveZipBlobImpl);
   }
 
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
               mozilla::ErrorResult& aRv) override;
 
 private: // Data
   ZipCentral mCentral;
-  nsRefPtr<FileImpl> mFileImpl;
+  nsRefPtr<BlobImpl> mBlobImpl;
 
   nsString mFilename;
 };
 
 END_ARCHIVEREADER_NAMESPACE
 
 #endif // mozilla_dom_archivereader_domarchivefile_h__
--- a/dom/base/BlobSet.h
+++ b/dom/base/BlobSet.h
@@ -21,22 +21,22 @@ public:
 
   ~BlobSet()
   {
     free(mData);
   }
 
   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);
+  nsresult AppendBlobImpl(BlobImpl* aBlobImpl);
+  nsresult AppendBlobImpls(const nsTArray<nsRefPtr<BlobImpl>>& aBlobImpls);
 
-  nsTArray<nsRefPtr<FileImpl>>& GetBlobImpls() { Flush(); return mBlobImpls; }
+  nsTArray<nsRefPtr<BlobImpl>>& GetBlobImpls() { Flush(); return mBlobImpls; }
 
-  already_AddRefed<File> GetBlobInternal(nsISupports* aParent,
+  already_AddRefed<Blob> GetBlobInternal(nsISupports* aParent,
                                          const nsACString& aContentType);
 
 protected:
   bool ExpandBufferSize(uint64_t aSize)
   {
     using mozilla::CheckedUint32;
 
     if (mDataBufferLen >= mDataLen + aSize) {
@@ -63,26 +63,26 @@ protected:
     return true;
   }
 
   void Flush() {
     if (mData) {
       // If we have some data, create a blob for it
       // and put it on the stack
 
-      nsRefPtr<FileImpl> blobImpl =
-        new FileImplMemory(mData, mDataLen, EmptyString());
+      nsRefPtr<BlobImpl> blobImpl =
+        new BlobImplMemory(mData, mDataLen, EmptyString());
       mBlobImpls.AppendElement(blobImpl);
       mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer
       mDataLen = 0;
       mDataBufferLen = 0;
     }
   }
 
-  nsTArray<nsRefPtr<FileImpl>> mBlobImpls;
+  nsTArray<nsRefPtr<BlobImpl>> mBlobImpls;
   void* mData;
   uint64_t mDataLen;
   uint64_t mDataBufferLen;
 };
 
 } // dom namespace
 } // mozilla namespace
 
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -55,17 +55,17 @@ using namespace mozilla::dom::workers;
 
 namespace mozilla {
 namespace dom {
 
 struct
 ConsoleStructuredCloneData
 {
   nsCOMPtr<nsISupports> mParent;
-  nsTArray<nsRefPtr<FileImpl>> mFiles;
+  nsTArray<nsRefPtr<BlobImpl>> mBlobs;
 };
 
 /**
  * Console API in workers uses the Structured Clone Algorithm to move any value
  * from the worker thread to the main-thread. Some object cannot be moved and,
  * in these cases, we convert them to strings.
  * It's not the best, but at least we are able to show something.
  */
@@ -79,23 +79,23 @@ ConsoleStructuredCloneCallbacksRead(JSCo
                                     void* aClosure)
 {
   AssertIsOnMainThread();
   ConsoleStructuredCloneData* data =
     static_cast<ConsoleStructuredCloneData*>(aClosure);
   MOZ_ASSERT(data);
 
   if (aTag == CONSOLE_TAG_BLOB) {
-    MOZ_ASSERT(data->mFiles.Length() > aIndex);
+    MOZ_ASSERT(data->mBlobs.Length() > aIndex);
 
     JS::Rooted<JS::Value> val(aCx);
     {
-      nsRefPtr<File> file =
-        new File(data->mParent, data->mFiles.ElementAt(aIndex));
-      if (!GetOrCreateDOMReflector(aCx, file, &val)) {
+      nsRefPtr<Blob> blob =
+        Blob::Create(data->mParent, data->mBlobs.ElementAt(aIndex));
+      if (!ToJSValue(aCx, blob, &val)) {
         return nullptr;
       }
     }
 
     return &val.toObject();
   }
 
   MOZ_CRASH("No other tags are supported.");
@@ -109,24 +109,24 @@ ConsoleStructuredCloneCallbacksWrite(JSC
                                      JSStructuredCloneWriter* aWriter,
                                      JS::Handle<JSObject*> aObj,
                                      void* aClosure)
 {
   ConsoleStructuredCloneData* data =
     static_cast<ConsoleStructuredCloneData*>(aClosure);
   MOZ_ASSERT(data);
 
-  nsRefPtr<File> file;
-  if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, file)) &&
-      file->Impl()->MayBeClonedToOtherThreads()) {
-    if (!JS_WriteUint32Pair(aWriter, CONSOLE_TAG_BLOB, data->mFiles.Length())) {
+  nsRefPtr<Blob> blob;
+  if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
+      blob->Impl()->MayBeClonedToOtherThreads()) {
+    if (!JS_WriteUint32Pair(aWriter, CONSOLE_TAG_BLOB, data->mBlobs.Length())) {
       return false;
     }
 
-    data->mFiles.AppendElement(file->Impl());
+    data->mBlobs.AppendElement(blob->Impl());
     return true;
   }
 
   JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aObj));
   JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
   if (!jsString) {
     return false;
   }
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/File.h"
 
-#include "MultipartFileImpl.h"
+#include "MultipartBlobImpl.h"
 #include "nsCExternalHandlerService.h"
 #include "nsContentCID.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsICharsetDetector.h"
 #include "nsIConverterInputStream.h"
 #include "nsIDocument.h"
 #include "nsIFileStreams.h"
@@ -50,17 +50,17 @@ namespace dom {
 // can outlive the actual File object.  Thus, we must
 // ensure that the buffer underlying the stream we get
 // from NS_NewByteInputStream is held alive as long as the
 // stream is.  We do that by passing back this class instead.
 class DataOwnerAdapter final : public nsIInputStream,
                                public nsISeekableStream,
                                public nsIIPCSerializableInputStream
 {
-  typedef FileImplMemory::DataOwner DataOwner;
+  typedef BlobImplMemory::DataOwner DataOwner;
 public:
   static nsresult Create(DataOwner* aDataOwner,
                          uint32_t aStart,
                          uint32_t aLength,
                          nsIInputStream** _retval);
 
   NS_DECL_THREADSAFE_ISUPPORTS
 
@@ -119,232 +119,475 @@ nsresult DataOwnerAdapter::Create(DataOw
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ADDREF(*_retval = new DataOwnerAdapter(aDataOwner, stream));
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// mozilla::dom::File implementation
+// mozilla::dom::Blob implementation
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(File)
+NS_IMPL_CYCLE_COLLECTION_CLASS(Blob)
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(File)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Blob)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(File)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Blob)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(File)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Blob)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(File)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Blob)
   // This class should not receive any nsIRemoteBlob QI!
   MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsIRemoteBlob)));
 
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMBlob)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, IsFile())
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY(nsIMutable)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(File)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(File)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(Blob)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(Blob)
 
-/* static */ already_AddRefed<File>
-File::Create(nsISupports* aParent, const nsAString& aName,
-             const nsAString& aContentType, uint64_t aLength,
-             int64_t aLastModifiedDate)
+/* static */ Blob*
+Blob::Create(nsISupports* aParent, BlobImpl* aImpl)
 {
-  nsRefPtr<File> file = new File(aParent,
-    new FileImplBase(aName, aContentType, aLength, aLastModifiedDate));
-  return file.forget();
+  MOZ_ASSERT(aImpl);
+
+  return aImpl->IsFile() ? new File(aParent, aImpl)
+                         : new Blob(aParent, aImpl);
 }
 
-/* static */ already_AddRefed<File>
-File::Create(nsISupports* aParent, const nsAString& aName,
-             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,
+/* static */ already_AddRefed<Blob>
+Blob::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();
+  nsRefPtr<Blob> blob = Blob::Create(aParent,
+    new BlobImplBase(aContentType, aLength));
+  MOZ_ASSERT(!blob->mImpl->IsFile());
+  return blob.forget();
 }
 
-/* static */ already_AddRefed<File>
-File::CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer,
-                       uint64_t aLength, const nsAString& aName,
-                       const nsAString& aContentType,
-                       int64_t aLastModifiedDate)
+/* static */ already_AddRefed<Blob>
+Blob::Create(nsISupports* aParent, const nsAString& aContentType,
+             uint64_t aStart, uint64_t aLength)
 {
-  nsRefPtr<File> file = new File(aParent,
-    new FileImplMemory(aMemoryBuffer, aLength, aName,
-                       aContentType, aLastModifiedDate));
-  return file.forget();
+  nsRefPtr<Blob> blob = Blob::Create(aParent,
+    new BlobImplBase(aContentType, aStart, aLength));
+  MOZ_ASSERT(!blob->mImpl->IsFile());
+  return blob.forget();
 }
 
-/* static */ already_AddRefed<File>
-File::CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer,
+/* static */ already_AddRefed<Blob>
+Blob::CreateMemoryBlob(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();
+  nsRefPtr<Blob> blob = Blob::Create(aParent,
+    new BlobImplMemory(aMemoryBuffer, aLength, aContentType));
+  MOZ_ASSERT(!blob->mImpl->IsFile());
+  return blob.forget();
 }
 
-/* static */ already_AddRefed<File>
-File::CreateFromFile(nsISupports* aParent, const nsAString& aContentType,
-                     uint64_t aLength, nsIFile* aFile,
-                     indexedDB::FileInfo* aFileInfo)
+/* static */ already_AddRefed<Blob>
+Blob::CreateTemporaryBlob(nsISupports* aParent, PRFileDesc* aFD,
+                          uint64_t aStartPos, uint64_t aLength,
+                          const nsAString& aContentType)
 {
-  nsRefPtr<File> file = new File(aParent,
-    new FileImplFile(aContentType, aLength, aFile, aFileInfo));
-  return file.forget();
+  nsRefPtr<Blob> blob = Blob::Create(aParent,
+    new BlobImplTemporaryBlob(aFD, aStartPos, aLength, aContentType));
+  MOZ_ASSERT(!blob->mImpl->IsFile());
+  return blob.forget();
 }
 
-/* static */ already_AddRefed<File>
-File::CreateFromFile(nsISupports* aParent, const nsAString& aName,
-                     const nsAString& aContentType,
-                     uint64_t aLength, nsIFile* aFile,
-                     indexedDB::FileInfo* aFileInfo)
-{
-  nsRefPtr<File> file = new File(aParent,
-    new FileImplFile(aName, aContentType, aLength, aFile, aFileInfo));
-  return file.forget();
-}
-
-/* static */ already_AddRefed<File>
-File::CreateFromFile(nsISupports* aParent, nsIFile* aFile,
-                     indexedDB::FileInfo* aFileInfo)
-{
-  nsRefPtr<File> file = new File(aParent,
-    new FileImplFile(aFile, aFileInfo));
-  return file.forget();
-}
-
-/* static */ already_AddRefed<File>
-File::CreateFromFile(nsISupports* aParent, nsIFile* aFile,
-                     const nsAString& aName, const nsAString& aContentType)
-{
-  nsRefPtr<File> file = new File(aParent,
-    new FileImplFile(aFile, aName, aContentType));
-  return file.forget();
-}
-
-File::File(nsISupports* aParent, FileImpl* aImpl)
+Blob::Blob(nsISupports* aParent, BlobImpl* 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
+bool
+Blob::IsFile() const
+{
+  return mImpl->IsFile();
+}
+
+const nsTArray<nsRefPtr<BlobImpl>>*
+Blob::GetSubBlobImpls() const
 {
   return mImpl->GetSubBlobImpls();
 }
 
-bool
-File::IsSizeUnknown() const
+already_AddRefed<File>
+Blob::ToFile()
 {
-  return mImpl->IsSizeUnknown();
-}
+  if (!mImpl->IsFile()) {
+    return nullptr;
+  }
 
-bool
-File::IsDateUnknown() const
-{
-  return mImpl->IsDateUnknown();
-}
+  nsRefPtr<File> file;
+  if (HasFileInterface()) {
+    file = static_cast<File*>(this);
+  } else {
+    file = new File(mParent, mImpl);
+  }
 
-bool
-File::IsFile() const
-{
-  return mImpl->IsFile();
+  return file.forget();
 }
 
 already_AddRefed<File>
-File::CreateSlice(uint64_t aStart, uint64_t aLength,
+Blob::ToFile(const nsAString& aName) const
+{
+  nsAutoTArray<nsRefPtr<BlobImpl>, 1> blobImpls;
+  blobImpls.AppendElement(mImpl);
+
+  nsAutoString contentType;
+  mImpl->GetType(contentType);
+
+  nsRefPtr<MultipartBlobImpl> impl =
+    new MultipartBlobImpl(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,
+  nsRefPtr<BlobImpl> impl = mImpl->CreateSlice(aStart, aLength,
                                                aContentType, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  nsRefPtr<File> file = new File(mParent, impl);
+  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<BlobImpl> 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<MultipartBlobImpl> impl = new MultipartBlobImpl();
+
+  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<MultipartBlobImpl> impl = new MultipartBlobImpl();
+
+  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, BlobImpl* aImpl)
+  : Blob(aParent, aImpl)
+{
+  MOZ_ASSERT(aImpl->IsFile());
+}
+
+/* static */ File*
+File::Create(nsISupports* aParent, BlobImpl* aImpl)
+{
+  MOZ_ASSERT(aImpl);
+  MOZ_ASSERT(aImpl->IsFile());
+
+  return new File(aParent, aImpl);
+}
+
+/* static */ already_AddRefed<File>
+File::Create(nsISupports* aParent, const nsAString& aName,
+             const nsAString& aContentType, uint64_t aLength,
+             int64_t aLastModifiedDate)
+{
+  nsRefPtr<File> file = new File(aParent,
+    new BlobImplBase(aName, aContentType, aLength, aLastModifiedDate));
   return file.forget();
 }
 
+/* static */ already_AddRefed<File>
+File::Create(nsISupports* aParent, const nsAString& aName,
+             const nsAString& aContentType, uint64_t aLength)
+{
+  nsRefPtr<File> file = new File(aParent,
+    new BlobImplBase(aName, aContentType, 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 BlobImplMemory(aMemoryBuffer, aLength, aName,
+                       aContentType, aLastModifiedDate));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<File>
+File::CreateFromFile(nsISupports* aParent, nsIFile* aFile, bool aTemporary)
+{
+  nsRefPtr<File> file = new File(aParent, new BlobImplFile(aFile, aTemporary));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<File>
+File::CreateFromFile(nsISupports* aParent, const nsAString& aContentType,
+                     uint64_t aLength, nsIFile* aFile,
+                     indexedDB::FileInfo* aFileInfo)
+{
+  nsRefPtr<File> file = new File(aParent,
+    new BlobImplFile(aContentType, aLength, aFile, aFileInfo));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<File>
+File::CreateFromFile(nsISupports* aParent, const nsAString& aName,
+                     const nsAString& aContentType,
+                     uint64_t aLength, nsIFile* aFile,
+                     indexedDB::FileInfo* aFileInfo)
+{
+  nsRefPtr<File> file = new File(aParent,
+    new BlobImplFile(aName, aContentType, aLength, aFile, aFileInfo));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<File>
+File::CreateFromFile(nsISupports* aParent, nsIFile* aFile,
+                     indexedDB::FileInfo* aFileInfo)
+{
+  nsRefPtr<File> file = new File(aParent,
+    new BlobImplFile(aFile, aFileInfo));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<File>
+File::CreateFromFile(nsISupports* aParent, nsIFile* aFile,
+                     const nsAString& aName, const nsAString& aContentType)
+{
+  nsRefPtr<File> file = new File(aParent,
+    new BlobImplFile(aFile, aName, aContentType));
+  return file.forget();
+}
+
+JSObject*
+File::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return FileBinding::Wrap(aCx, this, aGivenProto);
+}
+
 NS_IMETHODIMP
 File::GetName(nsAString& aFileName)
 {
   mImpl->GetName(aFileName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 File::GetPath(nsAString& aPath)
 {
   return mImpl->GetPath(aPath);
 }
 
+Date
+File::GetLastModifiedDate(ErrorResult& aRv)
+{
+  int64_t value = GetLastModified(aRv);
+  if (aRv.Failed()) {
+    return Date();
+  }
+
+  return Date(value);
+}
+
+int64_t
+File::GetLastModified(ErrorResult& aRv)
+{
+  return mImpl->GetLastModified(aRv);
+}
+
 NS_IMETHODIMP
 File::GetLastModifiedDate(JSContext* aCx,
                           JS::MutableHandle<JS::Value> aDate)
 {
   ErrorResult rv;
   Date value = GetLastModifiedDate(rv);
   if (rv.Failed()) {
     return rv.StealNSResult();
@@ -352,33 +595,16 @@ File::GetLastModifiedDate(JSContext* aCx
 
   if (!value.ToDateObject(aCx, aDate)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
-Date
-File::GetLastModifiedDate(ErrorResult& aRv)
-{
-  int64_t value = GetLastModified(aRv);
-  if (aRv.Failed()) {
-    return Date();
-  }
-
-  return Date(value);
-}
-
-int64_t
-File::GetLastModified(ErrorResult& aRv)
-{
-  return mImpl->GetLastModified(aRv);
-}
-
 NS_IMETHODIMP
 File::GetMozFullPath(nsAString& aFileName)
 {
   ErrorResult rv;
   GetMozFullPath(aFileName, rv);
   return rv.StealNSResult();
 }
 
@@ -392,39 +618,16 @@ NS_IMETHODIMP
 File::GetMozFullPathInternal(nsAString& aFileName)
 {
   ErrorResult rv;
   mImpl->GetMozFullPathInternal(aFileName, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-File::GetSize(uint64_t* aSize)
-{
-  MOZ_ASSERT(aSize);
-
-  ErrorResult rv;
-  *aSize = GetSize(rv);
-  return rv.StealNSResult();
-}
-
-uint64_t
-File::GetSize(ErrorResult& aRv)
-{
-  return mImpl->GetSize(aRv);
-}
-
-NS_IMETHODIMP
-File::GetType(nsAString &aType)
-{
-  mImpl->GetType(aType);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 File::GetMozLastModifiedDate(int64_t* aDate)
 {
   MOZ_ASSERT(aDate);
 
   ErrorResult rv;
   *aDate = GetLastModified(rv);
   return rv.StealNSResult();
 }
@@ -461,156 +664,25 @@ 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)
 {
-  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl(aName);
+  nsRefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(aName);
 
   impl->InitializeBlob(aGlobal.Context(), aData, aBag.mType, false, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
   MOZ_ASSERT(impl->IsFile());
 
   if (aBag.mLastModified.WasPassed()) {
@@ -618,26 +690,26 @@ File::Constructor(
   }
 
   nsRefPtr<File> file = new File(aGlobal.GetAsSupports(), impl);
   return file.forget();
 }
 
 /* static */ already_AddRefed<File>
 File::Constructor(const GlobalObject& aGlobal,
-                  File& aData,
+                  Blob& aData,
                   const ChromeFilePropertyBag& aBag,
                   ErrorResult& aRv)
 {
   if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl(EmptyString());
+  nsRefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(EmptyString());
   impl->InitializeChromeFile(aData, aBag, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
   MOZ_ASSERT(impl->IsFile());
 
   if (aBag.mLastModified.WasPassed()) {
     impl->SetLastModified(aBag.mLastModified.Value());
@@ -656,17 +728,17 @@ File::Constructor(const GlobalObject& aG
   MOZ_ASSERT(NS_IsMainThread());
   if (!nsContentUtils::IsCallerChrome()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
 
-  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl(EmptyString());
+  nsRefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(EmptyString());
   impl->InitializeChromeFile(window, aData, aBag, true, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
   MOZ_ASSERT(impl->IsFile());
 
   if (aBag.mLastModified.WasPassed()) {
     impl->SetLastModified(aBag.mLastModified.Value());
@@ -684,36 +756,36 @@ File::Constructor(const GlobalObject& aG
 {
   if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
 
-  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl(EmptyString());
+  nsRefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(EmptyString());
   impl->InitializeChromeFile(window, aData, aBag, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
   MOZ_ASSERT(impl->IsFile());
 
   if (aBag.mLastModified.WasPassed()) {
     impl->SetLastModified(aBag.mLastModified.Value());
   }
 
   nsRefPtr<File> domFile = new File(aGlobal.GetAsSupports(), impl);
   return domFile.forget();
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// mozilla::dom::FileImpl implementation
+// mozilla::dom::BlobImpl implementation
 
-already_AddRefed<FileImpl>
-FileImpl::Slice(const Optional<int64_t>& aStart,
+already_AddRefed<BlobImpl>
+BlobImpl::Slice(const Optional<int64_t>& aStart,
                 const Optional<int64_t>& aEnd,
                 const nsAString& aContentType,
                 ErrorResult& aRv)
 {
   // Truncate aStart and aEnd so that we stay within this file.
   uint64_t thisLength = GetSize(aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
@@ -724,42 +796,42 @@ FileImpl::Slice(const Optional<int64_t>&
 
   ParseSize((int64_t)thisLength, start, end);
 
   return CreateSlice((uint64_t)start, (uint64_t)(end - start),
                      aContentType, aRv);
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// FileImpl implementation
+// BlobImpl implementation
 
-NS_IMPL_ISUPPORTS(FileImpl, FileImpl)
+NS_IMPL_ISUPPORTS(BlobImpl, BlobImpl)
 
 ////////////////////////////////////////////////////////////////////////////
-// FileImplFile implementation
+// BlobImplFile implementation
 
-NS_IMPL_ISUPPORTS_INHERITED0(FileImplFile, FileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(BlobImplFile, BlobImpl)
 
 void
-FileImplBase::GetName(nsAString& aName)
+BlobImplBase::GetName(nsAString& aName)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   aName = mName;
 }
 
 nsresult
-FileImplBase::GetPath(nsAString& aPath)
+BlobImplBase::GetPath(nsAString& aPath)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   aPath = mPath;
   return NS_OK;
 }
 
 void
-FileImplBase::GetMozFullPath(nsAString& aFileName, ErrorResult& aRv)
+BlobImplBase::GetMozFullPath(nsAString& aFileName, ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
 
   aFileName.Truncate();
 
   if (NS_IsMainThread()) {
     if (nsContentUtils::IsCallerChrome()) {
       GetMozFullPathInternal(aFileName, aRv);
@@ -773,51 +845,51 @@ FileImplBase::GetMozFullPath(nsAString& 
   MOZ_ASSERT(workerPrivate);
 
   if (workerPrivate->UsesSystemPrincipal()) {
     GetMozFullPathInternal(aFileName, aRv);
   }
 }
 
 void
-FileImplBase::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv)
+BlobImplBase::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv)
 {
   if (!mIsFile) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   aFileName.Truncate();
 }
 
 void
-FileImplBase::GetType(nsAString& aType)
+BlobImplBase::GetType(nsAString& aType)
 {
   aType = mContentType;
 }
 
 int64_t
-FileImplBase::GetLastModified(ErrorResult& aRv)
+BlobImplBase::GetLastModified(ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   if (IsDateUnknown()) {
     mLastModificationDate = PR_Now();
   }
 
   return mLastModificationDate / PR_USEC_PER_MSEC;
 }
 
 void
-FileImplBase::SetLastModified(int64_t aLastModified)
+BlobImplBase::SetLastModified(int64_t aLastModified)
 {
   mLastModificationDate = aLastModified * PR_USEC_PER_MSEC;
 }
 
 int64_t
-FileImplBase::GetFileId()
+BlobImplBase::GetFileId()
 {
   int64_t id = -1;
 
   if (IsStoredFile() && IsWholeFile() && !IsSnapshot()) {
     if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
       indexedDB::IndexedDatabaseManager::FileMutex().Lock();
     }
 
@@ -833,17 +905,17 @@ FileImplBase::GetFileId()
       indexedDB::IndexedDatabaseManager::FileMutex().Unlock();
     }
   }
 
   return id;
 }
 
 void
-FileImplBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
+BlobImplBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
 {
   if (indexedDB::IndexedDatabaseManager::IsClosed()) {
     NS_ERROR("Shouldn't be called after shutdown!");
     return;
   }
 
   nsRefPtr<indexedDB::FileInfo> fileInfo = aFileInfo;
 
@@ -852,17 +924,17 @@ FileImplBase::AddFileInfo(indexedDB::Fil
   NS_ASSERTION(!mFileInfos.Contains(aFileInfo),
                "Adding the same file info agan?!");
 
   nsRefPtr<indexedDB::FileInfo>* element = mFileInfos.AppendElement();
   element->swap(fileInfo);
 }
 
 indexedDB::FileInfo*
-FileImplBase::GetFileInfo(indexedDB::FileManager* aFileManager)
+BlobImplBase::GetFileInfo(indexedDB::FileManager* aFileManager)
 {
   if (indexedDB::IndexedDatabaseManager::IsClosed()) {
     NS_ERROR("Shouldn't be called after shutdown!");
     return nullptr;
   }
 
   // A slice created from a stored file must keep the file info alive.
   // However, we don't support sharing of slices yet, so the slice must be
@@ -884,17 +956,17 @@ FileImplBase::GetFileInfo(indexedDB::Fil
       return fileInfo;
     }
   }
 
   return nullptr;
 }
 
 nsresult
-FileImplBase::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
+BlobImplBase::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
                           nsACString& aContentType, nsACString& aCharset)
 {
   MOZ_ASSERT(aContentLength);
 
   nsresult rv;
 
   nsCOMPtr<nsIInputStream> stream;
   rv = GetInternalStream(getter_AddRefs(stream));
@@ -913,24 +985,24 @@ FileImplBase::GetSendInfo(nsIInputStream
 
   aCharset.Truncate();
 
   stream.forget(aBody);
   return NS_OK;
 }
 
 nsresult
-FileImplBase::GetMutable(bool* aMutable) const
+BlobImplBase::GetMutable(bool* aMutable) const
 {
   *aMutable = !mImmutable;
   return NS_OK;
 }
 
 nsresult
-FileImplBase::SetMutable(bool aMutable)
+BlobImplBase::SetMutable(bool aMutable)
 {
   nsresult rv = NS_OK;
 
   NS_ENSURE_ARG(!mImmutable || !aMutable);
 
   if (!mImmutable && !aMutable) {
     // Force the content type and size to be cached
     nsAutoString dummyString;
@@ -943,37 +1015,37 @@ FileImplBase::SetMutable(bool aMutable)
     }
   }
 
   mImmutable = !aMutable;
   return rv;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// FileImplFile implementation
+// BlobImplFile implementation
 
-already_AddRefed<FileImpl>
-FileImplFile::CreateSlice(uint64_t aStart, uint64_t aLength,
+already_AddRefed<BlobImpl>
+BlobImplFile::CreateSlice(uint64_t aStart, uint64_t aLength,
                           const nsAString& aContentType,
                           ErrorResult& aRv)
 {
-  nsRefPtr<FileImpl> impl =
-    new FileImplFile(this, aStart, aLength, aContentType);
+  nsRefPtr<BlobImpl> impl =
+    new BlobImplFile(this, aStart, aLength, aContentType);
   return impl.forget();
 }
 
 void
-FileImplFile::GetMozFullPathInternal(nsAString& aFilename, ErrorResult& aRv)
+BlobImplFile::GetMozFullPathInternal(nsAString& aFilename, ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   aRv = mFile->GetPath(aFilename);
 }
 
 uint64_t
-FileImplFile::GetSize(ErrorResult& aRv)
+BlobImplFile::GetSize(ErrorResult& aRv)
 {
   if (IsSizeUnknown()) {
     NS_ASSERTION(mWholeFile,
                  "Should only use lazy size when using the whole file");
     int64_t fileSize;
     aRv = mFile->GetFileSize(&fileSize);
     if (NS_WARN_IF(aRv.Failed())) {
       return 0;
@@ -986,17 +1058,17 @@ FileImplFile::GetSize(ErrorResult& aRv)
 
     mLength = fileSize;
   }
 
   return mLength;
 }
 
 void
-FileImplFile::GetType(nsAString& aType)
+BlobImplFile::GetType(nsAString& aType)
 {
   if (mContentType.IsVoid()) {
     NS_ASSERTION(mWholeFile,
                  "Should only use lazy ContentType when using the whole file");
     nsresult rv;
     nsCOMPtr<nsIMIMEService> mimeService =
       do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
     if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -1013,109 +1085,109 @@ FileImplFile::GetType(nsAString& aType)
     AppendUTF8toUTF16(mimeType, mContentType);
     mContentType.SetIsVoid(false);
   }
 
   aType = mContentType;
 }
 
 int64_t
-FileImplFile::GetLastModified(ErrorResult& aRv)
+BlobImplFile::GetLastModified(ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   if (IsDateUnknown()) {
     PRTime msecs;
     aRv = mFile->GetLastModifiedTime(&msecs);
     if (NS_WARN_IF(aRv.Failed())) {
       return 0;
     }
 
     mLastModificationDate = msecs;
   }
 
   return mLastModificationDate;
 }
 
 void
-FileImplFile::SetLastModified(int64_t aLastModified)
+BlobImplFile::SetLastModified(int64_t aLastModified)
 {
   MOZ_CRASH("SetLastModified of a real file is not allowed!");
 }
 
 const uint32_t sFileStreamFlags =
   nsIFileInputStream::CLOSE_ON_EOF |
   nsIFileInputStream::REOPEN_ON_REWIND |
   nsIFileInputStream::DEFER_OPEN |
   nsIFileInputStream::SHARE_DELETE;
 
 nsresult
-FileImplFile::GetInternalStream(nsIInputStream** aStream)
+BlobImplFile::GetInternalStream(nsIInputStream** aStream)
 {
   return mWholeFile ?
     NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags) :
     NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
                                       -1, -1, sFileStreamFlags);
 }
 
 void
-FileImplFile::SetPath(const nsAString& aPath)
+BlobImplFile::SetPath(const nsAString& aPath)
 {
   MOZ_ASSERT(aPath.IsEmpty() ||
              aPath[aPath.Length() - 1] == char16_t('/'),
              "Path must end with a path separator");
   mPath = aPath;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// FileImplMemory implementation
+// BlobImplMemory implementation
 
-NS_IMPL_ISUPPORTS_INHERITED0(FileImplMemory, FileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(BlobImplMemory, BlobImpl)
 
-already_AddRefed<FileImpl>
-FileImplMemory::CreateSlice(uint64_t aStart, uint64_t aLength,
+already_AddRefed<BlobImpl>
+BlobImplMemory::CreateSlice(uint64_t aStart, uint64_t aLength,
                             const nsAString& aContentType,
                             ErrorResult& aRv)
 {
-  nsRefPtr<FileImpl> impl =
-    new FileImplMemory(this, aStart, aLength, aContentType);
+  nsRefPtr<BlobImpl> impl =
+    new BlobImplMemory(this, aStart, aLength, aContentType);
   return impl.forget();
 }
 
 nsresult
-FileImplMemory::GetInternalStream(nsIInputStream** aStream)
+BlobImplMemory::GetInternalStream(nsIInputStream** aStream)
 {
   if (mLength > INT32_MAX)
     return NS_ERROR_FAILURE;
 
   return DataOwnerAdapter::Create(mDataOwner, mStart, mLength, aStream);
 }
 
 /* static */ StaticMutex
-FileImplMemory::DataOwner::sDataOwnerMutex;
+BlobImplMemory::DataOwner::sDataOwnerMutex;
 
-/* static */ StaticAutoPtr<LinkedList<FileImplMemory::DataOwner>>
-FileImplMemory::DataOwner::sDataOwners;
+/* static */ StaticAutoPtr<LinkedList<BlobImplMemory::DataOwner>>
+BlobImplMemory::DataOwner::sDataOwners;
 
 /* static */ bool
-FileImplMemory::DataOwner::sMemoryReporterRegistered = false;
+BlobImplMemory::DataOwner::sMemoryReporterRegistered = false;
 
 MOZ_DEFINE_MALLOC_SIZE_OF(MemoryFileDataOwnerMallocSizeOf)
 
-class FileImplMemoryDataOwnerMemoryReporter final
+class BlobImplMemoryDataOwnerMemoryReporter final
   : public nsIMemoryReporter
 {
-  ~FileImplMemoryDataOwnerMemoryReporter() {}
+  ~BlobImplMemoryDataOwnerMemoryReporter() {}
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCallback,
                             nsISupports *aClosure, bool aAnonymize) override
   {
-    typedef FileImplMemory::DataOwner DataOwner;
+    typedef BlobImplMemory::DataOwner DataOwner;
 
     StaticMutexAutoLock lock(DataOwner::sDataOwnerMutex);
 
     if (!DataOwner::sDataOwners) {
       return NS_OK;
     }
 
     const size_t LARGE_OBJECT_MIN_SIZE = 8 * 1024;
@@ -1170,54 +1242,54 @@ public:
         aClosure);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return NS_OK;
   }
 };
 
-NS_IMPL_ISUPPORTS(FileImplMemoryDataOwnerMemoryReporter, nsIMemoryReporter)
+NS_IMPL_ISUPPORTS(BlobImplMemoryDataOwnerMemoryReporter, nsIMemoryReporter)
 
 /* static */ void
-FileImplMemory::DataOwner::EnsureMemoryReporterRegistered()
+BlobImplMemory::DataOwner::EnsureMemoryReporterRegistered()
 {
   sDataOwnerMutex.AssertCurrentThreadOwns();
   if (sMemoryReporterRegistered) {
     return;
   }
 
-  RegisterStrongMemoryReporter(new FileImplMemoryDataOwnerMemoryReporter());
+  RegisterStrongMemoryReporter(new BlobImplMemoryDataOwnerMemoryReporter());
 
   sMemoryReporterRegistered = true;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// FileImplTemporaryFileBlob implementation
+// BlobImplTemporaryBlob implementation
 
-NS_IMPL_ISUPPORTS_INHERITED0(FileImplTemporaryFileBlob, FileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(BlobImplTemporaryBlob, BlobImpl)
 
-already_AddRefed<FileImpl>
-FileImplTemporaryFileBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
-                                       const nsAString& aContentType,
-                                       ErrorResult& aRv)
+already_AddRefed<BlobImpl>
+BlobImplTemporaryBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
+                                   const nsAString& aContentType,
+                                   ErrorResult& aRv)
 {
   if (aStart + aLength > mLength) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
-  nsRefPtr<FileImpl> impl =
-    new FileImplTemporaryFileBlob(this, aStart + mStartPos,
-                                  aLength, aContentType);
+  nsRefPtr<BlobImpl> impl =
+    new BlobImplTemporaryBlob(this, aStart + mStartPos,
+                              aLength, aContentType);
   return impl.forget();
 }
 
 nsresult
-FileImplTemporaryFileBlob::GetInternalStream(nsIInputStream** aStream)
+BlobImplTemporaryBlob::GetInternalStream(nsIInputStream** aStream)
 {
   nsCOMPtr<nsIInputStream> stream =
     new nsTemporaryFileInputStream(mFileDescOwner, mStartPos, mStartPos + mLength);
   stream.forget(aStream);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
@@ -1254,21 +1326,21 @@ FileList::Item(uint32_t aIndex, nsIDOMFi
   nsRefPtr<File> file = Item(aIndex);
   file.forget(aFile);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // BlobSet implementation
 
-already_AddRefed<File>
+already_AddRefed<Blob>
 BlobSet::GetBlobInternal(nsISupports* aParent, const nsACString& aContentType)
 {
-  nsRefPtr<File> blob = new File(aParent,
-    new MultipartFileImpl(GetBlobImpls(),
+  nsRefPtr<Blob> blob = Blob::Create(aParent,
+    new MultipartBlobImpl(GetBlobImpls(),
                           NS_ConvertASCIItoUTF16(aContentType)));
   return blob.forget();
 }
 
 nsresult
 BlobSet::AppendVoidPtr(const void* aData, uint32_t aLength)
 {
   NS_ENSURE_ARG_POINTER(aData);
@@ -1297,28 +1369,28 @@ BlobSet::AppendString(const nsAString& a
 #endif
   }
 
   return AppendVoidPtr((void*)utf8Str.Data(),
                        utf8Str.Length());
 }
 
 nsresult
-BlobSet::AppendBlobImpl(FileImpl* aBlobImpl)
+BlobSet::AppendBlobImpl(BlobImpl* aBlobImpl)
 {
   NS_ENSURE_ARG_POINTER(aBlobImpl);
 
   Flush();
   mBlobImpls.AppendElement(aBlobImpl);
 
   return NS_OK;
 }
 
 nsresult
-BlobSet::AppendBlobImpls(const nsTArray<nsRefPtr<FileImpl>>& aBlobImpls)
+BlobSet::AppendBlobImpls(const nsTArray<nsRefPtr<BlobImpl>>& aBlobImpls)
 {
   Flush();
   mBlobImpls.AppendElements(aBlobImpls);
 
   return NS_OK;
 }
 
 } // dom namespace
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -42,71 +42,159 @@ namespace dom {
 
 namespace indexedDB {
 class FileInfo;
 };
 
 struct BlobPropertyBag;
 struct ChromeFilePropertyBag;
 struct FilePropertyBag;
-class FileImpl;
+class BlobImpl;
+class File;
 class OwningArrayBufferOrArrayBufferViewOrBlobOrString;
 
-class File final : public nsIDOMFile
-                 , public nsIXHRSendable
-                 , public nsIMutable
-                 , public nsSupportsWeakReference
-                 , public nsWrapperCache
+class Blob : public nsIDOMBlob
+           , public nsIXHRSendable
+           , public nsIMutable
+           , public nsSupportsWeakReference
+           , public nsWrapperCache
 {
 public:
   NS_DECL_NSIDOMBLOB
-  NS_DECL_NSIDOMFILE
   NS_DECL_NSIXHRSENDABLE
   NS_DECL_NSIMUTABLE
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(File, nsIDOMFile)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Blob, nsIDOMBlob)
+
+  static Blob*
+  Create(nsISupports* aParent, BlobImpl* 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);
+
+  BlobImpl* Impl() const
+  {
+    return mImpl;
+  }
+
+  bool IsFile() const;
+
+  const nsTArray<nsRefPtr<BlobImpl>>* 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 BlobImpl.
+  already_AddRefed<File> ToFile();
+
+  // This method creates a new File object with the given name and the same
+  // BlobImpl.
+  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, BlobImpl* 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<BlobImpl> 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: BlobImpl must be a File in order to use this method.
+  // Check impl->IsFile().
+  static File*
+  Create(nsISupports* aParent, BlobImpl* aImpl);
 
   static already_AddRefed<File>
   Create(nsISupports* aParent, const nsAString& aName,
          const nsAString& aContentType, uint64_t aLength,
          int64_t aLastModifiedDate);
 
   static already_AddRefed<File>
   Create(nsISupports* aParent, const nsAString& aName,
          const nsAString& aContentType, uint64_t aLength);
 
-  static already_AddRefed<File>
-  Create(nsISupports* aParent, const nsAString& aContentType,
-         uint64_t aLength);
-
-  static already_AddRefed<File>
-  Create(nsISupports* aParent, const nsAString& aContentType, uint64_t aStart,
-         uint64_t aLength);
-
   // The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
   // freed by free so it must be allocated by malloc or something
   // compatible with it.
   static already_AddRefed<File>
   CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
                    const nsAString& aName, const nsAString& aContentType,
                    int64_t aLastModifiedDate);
 
-  // The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
-  // freed by free so it must be allocated by malloc or something
-  // compatible with it.
-  static already_AddRefed<File>
-  CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
-                   const nsAString& aContentType);
-
-  static already_AddRefed<File>
-  CreateTemporaryFileBlob(nsISupports* aParent, PRFileDesc* aFD,
-                          uint64_t aStartPos, uint64_t aLength,
-                          const nsAString& aContentType);
-
   static already_AddRefed<File>
   CreateFromFile(nsISupports* aParent, nsIFile* aFile, bool aTemporary = false);
 
   static already_AddRefed<File>
   CreateFromFile(nsISupports* aParent, const nsAString& aContentType,
                  uint64_t aLength, nsIFile* aFile,
                  indexedDB::FileInfo* aFileInfo);
 
@@ -118,64 +206,33 @@ public:
   static already_AddRefed<File>
   CreateFromFile(nsISupports* aParent, nsIFile* aFile,
                  indexedDB::FileInfo* aFileInfo);
 
   static already_AddRefed<File>
   CreateFromFile(nsISupports* aParent, nsIFile* aFile, const nsAString& aName,
                  const nsAString& aContentType);
 
-  File(nsISupports* aParent, FileImpl* aImpl);
-
-  FileImpl* Impl() const
-  {
-    return mImpl;
-  }
-
-  const nsTArray<nsRefPtr<FileImpl>>* GetSubBlobImpls() const;
-
-  bool IsSizeUnknown() const;
-
-  bool IsDateUnknown() const;
-
-  bool IsFile() const;
+  // WebIDL methods
 
-  already_AddRefed<File>
-  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
-              ErrorResult& aRv);
-
-  // WebIDL methods
-  nsISupports* GetParentObject() const
-  {
-    return mParent;
-  }
-
-  // Blob constructor
-  static already_AddRefed<File>
-  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
-
-  // Blob constructor
-  static already_AddRefed<File>
-  Constructor(const GlobalObject& aGlobal,
-              const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
-              const BlobPropertyBag& aBag,
-              ErrorResult& aRv);
+  virtual JSObject* WrapObject(JSContext *cx,
+                               JS::Handle<JSObject*> aGivenProto) override;
 
   // File constructor
   static already_AddRefed<File>
   Constructor(const GlobalObject& aGlobal,
               const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
               const nsAString& aName,
               const FilePropertyBag& aBag,
               ErrorResult& aRv);
 
   // File constructor - ChromeOnly
   static already_AddRefed<File>
   Constructor(const GlobalObject& aGlobal,
-              File& aData,
+              Blob& aData,
               const ChromeFilePropertyBag& aBag,
               ErrorResult& aRv);
 
   // File constructor - ChromeOnly
   static already_AddRefed<File>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aData,
               const ChromeFilePropertyBag& aBag,
@@ -183,56 +240,44 @@ public:
 
   // File constructor - ChromeOnly
   static already_AddRefed<File>
   Constructor(const GlobalObject& aGlobal,
               nsIFile* aData,
               const ChromeFilePropertyBag& aBag,
               ErrorResult& aRv);
 
-  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-
-  uint64_t GetSize(ErrorResult& aRv);
-
-  // XPCOM GetType is OK
-
   // XPCOM GetName is OK
 
   int64_t GetLastModified(ErrorResult& aRv);
 
   Date GetLastModifiedDate(ErrorResult& aRv);
 
+
   void GetMozFullPath(nsAString& aFilename, ErrorResult& aRv);
 
-  already_AddRefed<File> Slice(const Optional<int64_t>& aStart,
-                               const Optional<int64_t>& aEnd,
-                               const nsAString& aContentType,
-                               ErrorResult& aRv);
+protected:
+  virtual bool HasFileInterface() const override { return true; }
 
 private:
+  // File constructor should never be used directly. Use Blob::Create or
+  // File::Create.
+  File(nsISupports* aParent, BlobImpl* 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
+class BlobImpl : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(FILEIMPL_IID)
   NS_DECL_THREADSAFE_ISUPPORTS
 
-  FileImpl() {}
+  BlobImpl() {}
 
   virtual void GetName(nsAString& aName) = 0;
 
   virtual nsresult GetPath(nsAString& aName) = 0;
 
   virtual int64_t GetLastModified(ErrorResult& aRv) = 0;
 
   virtual void SetLastModified(int64_t aLastModified) = 0;
@@ -240,25 +285,25 @@ public:
   virtual void GetMozFullPath(nsAString& aName, ErrorResult& aRv) = 0;
 
   virtual void GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) = 0;
 
   virtual uint64_t GetSize(ErrorResult& aRv) = 0;
 
   virtual void GetType(nsAString& aType) = 0;
 
-  already_AddRefed<FileImpl>
+  already_AddRefed<BlobImpl>
   Slice(const Optional<int64_t>& aStart, const Optional<int64_t>& aEnd,
         const nsAString& aContentType, ErrorResult& aRv);
 
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType, ErrorResult& aRv) = 0;
 
-  virtual const nsTArray<nsRefPtr<FileImpl>>*
+  virtual const nsTArray<nsRefPtr<BlobImpl>>*
   GetSubBlobImpls() const = 0;
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) = 0;
 
   virtual int64_t GetFileId() = 0;
 
   virtual void AddFileInfo(indexedDB::FileInfo* aFileInfo) = 0;
 
@@ -289,65 +334,65 @@ public:
 
   // True if this implementation can be sent to other threads.
   virtual bool MayBeClonedToOtherThreads() const
   {
     return true;
   }
 
 protected:
-  virtual ~FileImpl() {}
+  virtual ~BlobImpl() {}
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(FileImpl, FILEIMPL_IID)
+NS_DEFINE_STATIC_IID_ACCESSOR(BlobImpl, FILEIMPL_IID)
 
-class FileImplBase : public FileImpl
+class BlobImplBase : public BlobImpl
 {
 public:
-  FileImplBase(const nsAString& aName, const nsAString& aContentType,
+  BlobImplBase(const nsAString& aName, const nsAString& aContentType,
                uint64_t aLength, int64_t aLastModifiedDate)
     : mIsFile(true)
     , mImmutable(false)
     , mContentType(aContentType)
     , mName(aName)
     , mStart(0)
     , mLength(aLength)
     , mLastModificationDate(aLastModifiedDate)
   {
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
   }
 
-  FileImplBase(const nsAString& aName, const nsAString& aContentType,
+  BlobImplBase(const nsAString& aName, const nsAString& aContentType,
                uint64_t aLength)
     : mIsFile(true)
     , mImmutable(false)
     , mContentType(aContentType)
     , mName(aName)
     , mStart(0)
     , mLength(aLength)
     , mLastModificationDate(INT64_MAX)
   {
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
   }
 
-  FileImplBase(const nsAString& aContentType, uint64_t aLength)
+  BlobImplBase(const nsAString& aContentType, uint64_t aLength)
     : mIsFile(false)
     , mImmutable(false)
     , mContentType(aContentType)
     , mStart(0)
     , mLength(aLength)
     , mLastModificationDate(INT64_MAX)
   {
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
   }
 
-  FileImplBase(const nsAString& aContentType, uint64_t aStart,
+  BlobImplBase(const nsAString& aContentType, uint64_t aStart,
                uint64_t aLength)
     : mIsFile(false)
     , mImmutable(false)
     , mContentType(aContentType)
     , mStart(aStart)
     , mLength(aLength)
     , mLastModificationDate(INT64_MAX)
   {
@@ -372,24 +417,24 @@ public:
 
   virtual uint64_t GetSize(ErrorResult& aRv) override
   {
     return mLength;
   }
 
   virtual void GetType(nsAString& aType) override;
 
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType, ErrorResult& aRv) override
   {
     return nullptr;
   }
 
-  virtual const nsTArray<nsRefPtr<FileImpl>>*
+  virtual const nsTArray<nsRefPtr<BlobImpl>>*
   GetSubBlobImpls() const override
   {
     return nullptr;
   }
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) override
   {
     return NS_ERROR_NOT_IMPLEMENTED;
@@ -456,17 +501,17 @@ public:
   }
 
   virtual bool IsSizeUnknown() const override
   {
     return mLength == UINT64_MAX;
   }
 
 protected:
-  virtual ~FileImplBase() {}
+  virtual ~BlobImplBase() {}
 
   indexedDB::FileInfo* GetFileInfo() const
   {
     NS_ASSERTION(IsStoredFile(), "Should only be called on stored files!");
     NS_ASSERTION(!mFileInfos.IsEmpty(), "Must have at least one file info!");
 
     return mFileInfos.ElementAt(0);
   }
@@ -486,40 +531,40 @@ protected:
   // Protected by IndexedDatabaseManager::FileMutex()
   nsTArray<nsRefPtr<indexedDB::FileInfo>> mFileInfos;
 };
 
 /**
  * This class may be used off the main thread, and in particular, its
  * constructor and destructor may not run on the same thread.  Be careful!
  */
-class FileImplMemory final : public FileImplBase
+class BlobImplMemory final : public BlobImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
-  FileImplMemory(void* aMemoryBuffer, uint64_t aLength, const nsAString& aName,
+  BlobImplMemory(void* aMemoryBuffer, uint64_t aLength, const nsAString& aName,
                  const nsAString& aContentType, int64_t aLastModifiedDate)
-    : FileImplBase(aName, aContentType, aLength, aLastModifiedDate)
+    : BlobImplBase(aName, aContentType, aLength, aLastModifiedDate)
     , mDataOwner(new DataOwner(aMemoryBuffer, aLength))
   {
     NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
   }
 
-  FileImplMemory(void* aMemoryBuffer, uint64_t aLength,
+  BlobImplMemory(void* aMemoryBuffer, uint64_t aLength,
                  const nsAString& aContentType)
-    : FileImplBase(aContentType, aLength)
+    : BlobImplBase(aContentType, aLength)
     , mDataOwner(new DataOwner(aMemoryBuffer, aLength))
   {
     NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
   }
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) override;
 
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType, ErrorResult& aRv) override;
 
   virtual bool IsMemoryFile() const override
   {
     return true;
   }
 
@@ -565,170 +610,170 @@ public:
     static bool sMemoryReporterRegistered;
 
     void* mData;
     uint64_t mLength;
   };
 
 private:
   // Create slice
-  FileImplMemory(const FileImplMemory* aOther, uint64_t aStart,
+  BlobImplMemory(const BlobImplMemory* aOther, uint64_t aStart,
                  uint64_t aLength, const nsAString& aContentType)
-    : FileImplBase(aContentType, aOther->mStart + aStart, aLength)
+    : BlobImplBase(aContentType, aOther->mStart + aStart, aLength)
     , mDataOwner(aOther->mDataOwner)
   {
     NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
     mImmutable = aOther->mImmutable;
   }
 
-  ~FileImplMemory() {}
+  ~BlobImplMemory() {}
 
   // Used when backed by a memory store
   nsRefPtr<DataOwner> mDataOwner;
 };
 
-class FileImplTemporaryFileBlob final : public FileImplBase
+class BlobImplTemporaryBlob final : public BlobImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
-  FileImplTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos,
-                            uint64_t aLength, const nsAString& aContentType)
-    : FileImplBase(aContentType, aLength)
+  BlobImplTemporaryBlob(PRFileDesc* aFD, uint64_t aStartPos,
+                        uint64_t aLength, const nsAString& aContentType)
+    : BlobImplBase(aContentType, aLength)
     , mStartPos(aStartPos)
   {
     mFileDescOwner = new nsTemporaryFileInputStream::FileDescOwner(aFD);
   }
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) override;
 
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType, ErrorResult& aRv) override;
 
 private:
-  FileImplTemporaryFileBlob(const FileImplTemporaryFileBlob* aOther,
-                            uint64_t aStart, uint64_t aLength,
-                            const nsAString& aContentType)
-    : FileImplBase(aContentType, aLength)
+  BlobImplTemporaryBlob(const BlobImplTemporaryBlob* aOther,
+                        uint64_t aStart, uint64_t aLength,
+                        const nsAString& aContentType)
+    : BlobImplBase(aContentType, aLength)
     , mStartPos(aStart)
     , mFileDescOwner(aOther->mFileDescOwner)
   {}
 
-  ~FileImplTemporaryFileBlob() {}
+  ~BlobImplTemporaryBlob() {}
 
   uint64_t mStartPos;
   nsRefPtr<nsTemporaryFileInputStream::FileDescOwner> mFileDescOwner;
 };
 
-class FileImplFile : public FileImplBase
+class BlobImplFile : public BlobImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // Create as a file
-  explicit FileImplFile(nsIFile* aFile, bool aTemporary = false)
-    : FileImplBase(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
+  explicit BlobImplFile(nsIFile* aFile, bool aTemporary = false)
+    : BlobImplBase(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(false)
     , mIsTemporary(aTemporary)
   {
     NS_ASSERTION(mFile, "must have file");
     // Lazily get the content type and size
     mContentType.SetIsVoid(true);
     mFile->GetLeafName(mName);
   }
 
-  FileImplFile(nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
-    : FileImplBase(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
+  BlobImplFile(nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
+    : BlobImplBase(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(true)
     , mIsTemporary(false)
   {
     NS_ASSERTION(mFile, "must have file");
     NS_ASSERTION(aFileInfo, "must have file info");
     // Lazily get the content type and size
     mContentType.SetIsVoid(true);
     mFile->GetLeafName(mName);
 
     mFileInfos.AppendElement(aFileInfo);
   }
 
   // Create as a file
-  FileImplFile(const nsAString& aName, const nsAString& aContentType,
+  BlobImplFile(const nsAString& aName, const nsAString& aContentType,
                uint64_t aLength, nsIFile* aFile)
-    : FileImplBase(aName, aContentType, aLength, UINT64_MAX)
+    : BlobImplBase(aName, aContentType, aLength, UINT64_MAX)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(false)
     , mIsTemporary(false)
   {
     NS_ASSERTION(mFile, "must have file");
   }
 
-  FileImplFile(const nsAString& aName, const nsAString& aContentType,
+  BlobImplFile(const nsAString& aName, const nsAString& aContentType,
                uint64_t aLength, nsIFile* aFile,
                int64_t aLastModificationDate)
-    : FileImplBase(aName, aContentType, aLength, aLastModificationDate)
+    : BlobImplBase(aName, aContentType, aLength, aLastModificationDate)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(false)
     , mIsTemporary(false)
   {
     NS_ASSERTION(mFile, "must have file");
   }
 
   // Create as a file with custom name
-  FileImplFile(nsIFile* aFile, const nsAString& aName,
+  BlobImplFile(nsIFile* aFile, const nsAString& aName,
                const nsAString& aContentType)
-    : FileImplBase(aName, aContentType, UINT64_MAX, INT64_MAX)
+    : BlobImplBase(aName, aContentType, UINT64_MAX, INT64_MAX)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(false)
     , mIsTemporary(false)
   {
     NS_ASSERTION(mFile, "must have file");
     if (aContentType.IsEmpty()) {
       // Lazily get the content type and size
       mContentType.SetIsVoid(true);
     }
   }
 
   // Create as a stored file
-  FileImplFile(const nsAString& aName, const nsAString& aContentType,
+  BlobImplFile(const nsAString& aName, const nsAString& aContentType,
                uint64_t aLength, nsIFile* aFile,
                indexedDB::FileInfo* aFileInfo)
-    : FileImplBase(aName, aContentType, aLength, UINT64_MAX)
+    : BlobImplBase(aName, aContentType, aLength, UINT64_MAX)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(true)
     , mIsTemporary(false)
   {
     NS_ASSERTION(mFile, "must have file");
     mFileInfos.AppendElement(aFileInfo);
   }
 
   // Create as a stored blob
-  FileImplFile(const nsAString& aContentType, uint64_t aLength,
+  BlobImplFile(const nsAString& aContentType, uint64_t aLength,
                nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
-    : FileImplBase(aContentType, aLength)
+    : BlobImplBase(aContentType, aLength)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(true)
     , mIsTemporary(false)
   {
     NS_ASSERTION(mFile, "must have file");
     mFileInfos.AppendElement(aFileInfo);
   }
 
   // Create as a file to be later initialized
-  FileImplFile()
-    : FileImplBase(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
+  BlobImplFile()
+    : BlobImplBase(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
     , mWholeFile(true)
     , mStoredFile(false)
     , mIsTemporary(false)
   {
     // Lazily get the content type and size
     mContentType.SetIsVoid(true);
     mName.SetIsVoid(true);
   }
@@ -740,34 +785,34 @@ public:
   virtual void SetLastModified(int64_t aLastModified) override;
   virtual void GetMozFullPathInternal(nsAString& aFullPath,
                                       ErrorResult& aRv) override;
   virtual nsresult GetInternalStream(nsIInputStream**) override;
 
   void SetPath(const nsAString& aFullPath);
 
 protected:
-  virtual ~FileImplFile() {
+  virtual ~BlobImplFile() {
     if (mFile && mIsTemporary) {
-      NS_WARNING("In temporary ~FileImplFile");
+      NS_WARNING("In temporary ~BlobImplFile");
       // Ignore errors if any, not much we can do. Clean-up will be done by
       // https://mxr.mozilla.org/mozilla-central/source/xpcom/io/nsAnonymousTemporaryFile.cpp?rev=6c1c7e45c902#127
 #ifdef DEBUG
       nsresult rv =
 #endif
       mFile->Remove(false);
       NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to remove temporary DOMFile.");
     }
   }
 
 private:
   // Create slice
-  FileImplFile(const FileImplFile* aOther, uint64_t aStart,
+  BlobImplFile(const BlobImplFile* aOther, uint64_t aStart,
                uint64_t aLength, const nsAString& aContentType)
-    : FileImplBase(aContentType, aOther->mStart + aStart, aLength)
+    : BlobImplBase(aContentType, aOther->mStart + aStart, aLength)
     , mFile(aOther->mFile)
     , mWholeFile(false)
     , mStoredFile(aOther->mStoredFile)
     , mIsTemporary(false)
   {
     NS_ASSERTION(mFile, "must have file");
     mImmutable = aOther->mImmutable;
 
@@ -783,17 +828,17 @@ private:
         mozilla::MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
         fileInfo = aOther->GetFileInfo();
       }
 
       mFileInfos.AppendElement(fileInfo);
     }
   }
 
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType, ErrorResult& aRv) override;
 
   virtual bool IsStoredFile() const override
   {
     return mStoredFile;
   }
 
@@ -818,17 +863,18 @@ public:
   {
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FileList)
 
   NS_DECL_NSIDOMFILELIST
 
-  virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
+  virtual JSObject* WrapObject(JSContext *cx,
+                               JS::Handle<JSObject*> aGivenProto) override;
 
   nsISupports* GetParentObject()
   {
     return mParent;
   }
 
   void Disconnect()
   {
--- a/dom/base/ImageEncoder.cpp
+++ b/dom/base/ImageEncoder.cpp
@@ -85,18 +85,18 @@ public:
 
   NS_IMETHOD Run() override
   {
     nsresult rv = NS_OK;
     MOZ_ASSERT(NS_IsMainThread());
 
     if (!mFailed) {
       // The correct parentObject has to be set by the mEncodeCompleteCallback.
-      nsRefPtr<File> blob =
-        File::CreateMemoryFile(nullptr, mImgData, mImgSize, mType);
+      nsRefPtr<Blob> blob =
+        Blob::CreateMemoryBlob(nullptr, mImgData, mImgSize, mType);
       MOZ_ASSERT(blob);
 
       rv = mEncodeCompleteCallback->ReceiveBlob(blob.forget());
     }
 
     mEncodeCompleteCallback = nullptr;
 
     mEncoderThread->Shutdown();
--- a/dom/base/ImageEncoder.h
+++ b/dom/base/ImageEncoder.h
@@ -111,17 +111,17 @@ private:
  *  The callback interface of ExtractDataAsync and ExtractDataFromLayersImageAsync.
  *  ReceiveBlob() is called on main thread when encoding is complete.
  */
 class EncodeCompleteCallback
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(EncodeCompleteCallback)
 
-  virtual nsresult ReceiveBlob(already_AddRefed<File> aBlob) = 0;
+  virtual nsresult ReceiveBlob(already_AddRefed<Blob> aBlob) = 0;
 
 protected:
   virtual ~EncodeCompleteCallback() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/base/MessagePort.cpp
+++ b/dom/base/MessagePort.cpp
@@ -106,32 +106,32 @@ PostMessageReadStructuredClone(JSContext
                                void* closure)
 {
   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
   NS_ASSERTION(scInfo, "Must have scInfo!");
 
   if (tag == SCTAG_DOM_BLOB) {
     NS_ASSERTION(!data, "Data should be empty");
 
-    // What we get back from the reader is a FileImpl.
+    // What we get back from the reader is a BlobImpl.
     // From that we create a new File.
-    FileImpl* blobImpl;
+    BlobImpl* blobImpl;
     if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) {
       MOZ_ASSERT(blobImpl);
 
       // nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
       // called because the static analysis thinks dereferencing XPCOM objects
       // can GC (because in some cases it can!), and a return statement with a
       // JSObject* type means that JSObject* is on the stack as a raw pointer
       // while destructors are running.
       JS::Rooted<JS::Value> val(cx);
       {
-        nsRefPtr<File> blob = new File(scInfo->mPort->GetParentObject(),
-                                             blobImpl);
-        if (!GetOrCreateDOMReflector(cx, blob, &val)) {
+        nsRefPtr<Blob> blob = Blob::Create(scInfo->mPort->GetParentObject(),
+                                           blobImpl);
+        if (!ToJSValue(cx, blob, &val)) {
           return nullptr;
         }
       }
 
       return &val.toObject();
     }
   }
 
@@ -163,19 +163,19 @@ PostMessageWriteStructuredClone(JSContex
                                 JS::Handle<JSObject*> obj,
                                 void *closure)
 {
   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
   NS_ASSERTION(scInfo, "Must have scInfo!");
 
   // See if this is a File/Blob object.
   {
-    File* blob = nullptr;
+    Blob* blob = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
-      FileImpl* blobImpl = blob->Impl();
+      BlobImpl* blobImpl = blob->Impl();
       if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
           JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
         scInfo->mEvent->StoreISupports(blobImpl);
         return true;
       }
     }
   }
 
rename from dom/base/MultipartFileImpl.cpp
rename to dom/base/MultipartBlobImpl.cpp
--- a/dom/base/MultipartFileImpl.cpp
+++ b/dom/base/MultipartBlobImpl.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "MultipartFileImpl.h"
+#include "MultipartBlobImpl.h"
 #include "jsfriendapi.h"
 #include "mozilla/dom/BlobSet.h"
 #include "mozilla/dom/FileBinding.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "nsAutoPtr.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsStringStream.h"
@@ -18,140 +18,140 @@
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsIXPConnect.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_ISUPPORTS_INHERITED0(MultipartFileImpl, FileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(MultipartBlobImpl, BlobImpl)
 
 nsresult
-MultipartFileImpl::GetInternalStream(nsIInputStream** aStream)
+MultipartBlobImpl::GetInternalStream(nsIInputStream** aStream)
 {
   nsresult rv;
   *aStream = nullptr;
 
   nsCOMPtr<nsIMultiplexInputStream> stream =
     do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
   NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);
 
   uint32_t i;
   for (i = 0; i < mBlobImpls.Length(); i++) {
     nsCOMPtr<nsIInputStream> scratchStream;
-    FileImpl* blobImpl = mBlobImpls.ElementAt(i).get();
+    BlobImpl* blobImpl = mBlobImpls.ElementAt(i).get();
 
     rv = blobImpl->GetInternalStream(getter_AddRefs(scratchStream));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = stream->AppendStream(scratchStream);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   stream.forget(aStream);
   return NS_OK;
 }
 
-already_AddRefed<FileImpl>
-MultipartFileImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
+already_AddRefed<BlobImpl>
+MultipartBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
                                const nsAString& aContentType,
                                ErrorResult& aRv)
 {
   // If we clamped to nothing we create an empty blob
-  nsTArray<nsRefPtr<FileImpl>> blobImpls;
+  nsTArray<nsRefPtr<BlobImpl>> blobImpls;
 
   uint64_t length = aLength;
   uint64_t skipStart = aStart;
 
   // Prune the list of blobs if we can
   uint32_t i;
   for (i = 0; length && skipStart && i < mBlobImpls.Length(); i++) {
-    FileImpl* blobImpl = mBlobImpls[i].get();
+    BlobImpl* blobImpl = mBlobImpls[i].get();
 
     uint64_t l = blobImpl->GetSize(aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
 
     if (skipStart < l) {
       uint64_t upperBound = std::min<uint64_t>(l - skipStart, length);
 
-      nsRefPtr<FileImpl> firstBlobImpl =
+      nsRefPtr<BlobImpl> firstBlobImpl =
         blobImpl->CreateSlice(skipStart, upperBound,
                               aContentType, aRv);
       if (NS_WARN_IF(aRv.Failed())) {
         return nullptr;
       }
 
-      // Avoid wrapping a single blob inside an MultipartFileImpl
+      // Avoid wrapping a single blob inside an MultipartBlobImpl
       if (length == upperBound) {
         return firstBlobImpl.forget();
       }
 
       blobImpls.AppendElement(firstBlobImpl);
       length -= upperBound;
       i++;
       break;
     }
     skipStart -= l;
   }
 
   // Now append enough blobs until we're done
   for (; length && i < mBlobImpls.Length(); i++) {
-    FileImpl* blobImpl = mBlobImpls[i].get();
+    BlobImpl* blobImpl = mBlobImpls[i].get();
 
     uint64_t l = blobImpl->GetSize(aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
 
     if (length < l) {
-      nsRefPtr<FileImpl> lastBlobImpl =
+      nsRefPtr<BlobImpl> lastBlobImpl =
         blobImpl->CreateSlice(0, length, aContentType, aRv);
       if (NS_WARN_IF(aRv.Failed())) {
         return nullptr;
       }
 
       blobImpls.AppendElement(lastBlobImpl);
     } else {
       blobImpls.AppendElement(blobImpl);
     }
     length -= std::min<uint64_t>(l, length);
   }
 
   // we can create our blob now
-  nsRefPtr<FileImpl> impl =
-    new MultipartFileImpl(blobImpls, aContentType);
+  nsRefPtr<BlobImpl> impl =
+    new MultipartBlobImpl(blobImpls, aContentType);
   return impl.forget();
 }
 
 void
-MultipartFileImpl::InitializeBlob()
+MultipartBlobImpl::InitializeBlob()
 {
   SetLengthAndModifiedDate();
 }
 
 void
-MultipartFileImpl::InitializeBlob(
+MultipartBlobImpl::InitializeBlob(
        JSContext* aCx,
        const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
        const nsAString& aContentType,
        bool aNativeEOL,
        ErrorResult& aRv)
 {
   mContentType = aContentType;
   BlobSet blobSet;
 
   for (uint32_t i = 0, len = aData.Length(); i < len; ++i) {
     const OwningArrayBufferOrArrayBufferViewOrBlobOrString& data = aData[i];
 
     if (data.IsBlob()) {
-      nsRefPtr<File> file = data.GetAsBlob().get();
-      blobSet.AppendBlobImpl(file->Impl());
+      nsRefPtr<Blob> blob = data.GetAsBlob().get();
+      blobSet.AppendBlobImpl(blob->Impl());
     }
 
     else if (data.IsString()) {
       aRv = blobSet.AppendString(data.GetAsString(), aNativeEOL, aCx);
       if (aRv.Failed()) {
         return;
       }
     }
@@ -180,27 +180,27 @@ MultipartFileImpl::InitializeBlob(
   }
 
 
   mBlobImpls = blobSet.GetBlobImpls();
   SetLengthAndModifiedDate();
 }
 
 void
-MultipartFileImpl::SetLengthAndModifiedDate()
+MultipartBlobImpl::SetLengthAndModifiedDate()
 {
   MOZ_ASSERT(mLength == UINT64_MAX);
   MOZ_ASSERT(mLastModificationDate == INT64_MAX);
 
   uint64_t totalLength = 0;
   int64_t lastModified = 0;
   bool lastModifiedSet = false;
 
   for (uint32_t index = 0, count = mBlobImpls.Length(); index < count; index++) {
-    nsRefPtr<FileImpl>& blob = mBlobImpls[index];
+    nsRefPtr<BlobImpl>& blob = mBlobImpls[index];
 
 #ifdef DEBUG
     MOZ_ASSERT(!blob->IsSizeUnknown());
     MOZ_ASSERT(!blob->IsDateUnknown());
 #endif
 
     ErrorResult error;
     uint64_t subBlobLength = blob->GetSize(error);
@@ -228,65 +228,65 @@ MultipartFileImpl::SetLengthAndModifiedD
     //   x.getTime() < f.dateModified.getTime()
     // could fail.
     mLastModificationDate =
       lastModifiedSet ? lastModified * PR_USEC_PER_MSEC : JS_Now();
   }
 }
 
 void
-MultipartFileImpl::GetMozFullPathInternal(nsAString& aFilename,
+MultipartBlobImpl::GetMozFullPathInternal(nsAString& aFilename,
                                           ErrorResult& aRv)
 {
   if (!mIsFromNsIFile || mBlobImpls.Length() == 0) {
-    FileImplBase::GetMozFullPathInternal(aFilename, aRv);
+    BlobImplBase::GetMozFullPathInternal(aFilename, aRv);
     return;
   }
 
-  FileImpl* blobImpl = mBlobImpls.ElementAt(0).get();
+  BlobImpl* blobImpl = mBlobImpls.ElementAt(0).get();
   if (!blobImpl) {
-    FileImplBase::GetMozFullPathInternal(aFilename, aRv);
+    BlobImplBase::GetMozFullPathInternal(aFilename, aRv);
     return;
   }
 
   blobImpl->GetMozFullPathInternal(aFilename, aRv);
 }
 
 nsresult
-MultipartFileImpl::SetMutable(bool aMutable)
+MultipartBlobImpl::SetMutable(bool aMutable)
 {
   nsresult rv;
 
-  // This looks a little sketchy since FileImpl objects are supposed to be
-  // threadsafe. However, we try to enforce that all FileImpl objects must be
+  // This looks a little sketchy since BlobImpl objects are supposed to be
+  // threadsafe. However, we try to enforce that all BlobImpl objects must be
   // set to immutable *before* being passed to another thread, so this should
   // be safe.
   if (!aMutable && !mImmutable && !mBlobImpls.IsEmpty()) {
     for (uint32_t index = 0, count = mBlobImpls.Length();
          index < count;
          index++) {
       rv = mBlobImpls[index]->SetMutable(aMutable);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
   }
 
-  rv = FileImplBase::SetMutable(aMutable);
+  rv = BlobImplBase::SetMutable(aMutable);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   MOZ_ASSERT_IF(!aMutable, mImmutable);
 
   return NS_OK;
 }
 
 void
-MultipartFileImpl::InitializeChromeFile(File& aBlob,
+MultipartBlobImpl::InitializeChromeFile(Blob& aBlob,
                                         const ChromeFilePropertyBag& aBag,
                                         ErrorResult& aRv)
 {
   NS_ASSERTION(!mImmutable, "Something went wrong ...");
 
   if (mImmutable) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
@@ -307,17 +307,17 @@ MultipartFileImpl::InitializeChromeFile(
   BlobSet blobSet;
   blobSet.AppendBlobImpl(aBlob.Impl());
   mBlobImpls = blobSet.GetBlobImpls();
 
   SetLengthAndModifiedDate();
 }
 
 void
-MultipartFileImpl::InitializeChromeFile(nsPIDOMWindow* aWindow,
+MultipartBlobImpl::InitializeChromeFile(nsPIDOMWindow* aWindow,
                                         nsIFile* aFile,
                                         const ChromeFilePropertyBag& aBag,
                                         bool aIsFromNsIFile,
                                         ErrorResult& aRv)
 {
   NS_ASSERTION(!mImmutable, "Something went wrong ...");
   if (mImmutable) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
@@ -380,32 +380,32 @@ MultipartFileImpl::InitializeChromeFile(
   BlobSet blobSet;
   blobSet.AppendBlobImpl(static_cast<File*>(blob.get())->Impl());
   mBlobImpls = blobSet.GetBlobImpls();
 
   SetLengthAndModifiedDate();
 }
 
 void
-MultipartFileImpl::InitializeChromeFile(nsPIDOMWindow* aWindow,
+MultipartBlobImpl::InitializeChromeFile(nsPIDOMWindow* aWindow,
                                         const nsAString& aData,
                                         const ChromeFilePropertyBag& aBag,
                                         ErrorResult& aRv)
 {
   nsCOMPtr<nsIFile> file;
   aRv = NS_NewLocalFile(aData, false, getter_AddRefs(file));
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   InitializeChromeFile(aWindow, file, aBag, false, aRv);
 }
 
 bool
-MultipartFileImpl::MayBeClonedToOtherThreads() const
+MultipartBlobImpl::MayBeClonedToOtherThreads() const
 {
   for (uint32_t i = 0; i < mBlobImpls.Length(); ++i) {
     if (!mBlobImpls[i]->MayBeClonedToOtherThreads()) {
       return false;
     }
   }
 
   return true;
rename from dom/base/MultipartFileImpl.h
rename to dom/base/MultipartBlobImpl.h
--- a/dom/base/MultipartFileImpl.h
+++ b/dom/base/MultipartBlobImpl.h
@@ -1,105 +1,105 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_dom_MultipartFileImpl_h
-#define mozilla_dom_MultipartFileImpl_h
+#ifndef mozilla_dom_MultipartBlobImpl_h
+#define mozilla_dom_MultipartBlobImpl_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/FileBinding.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-class MultipartFileImpl final : public FileImplBase
+class MultipartBlobImpl final : public BlobImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // Create as a file
-  MultipartFileImpl(const nsTArray<nsRefPtr<FileImpl>>& aBlobImpls,
+  MultipartBlobImpl(const nsTArray<nsRefPtr<BlobImpl>>& aBlobImpls,
                     const nsAString& aName,
                     const nsAString& aContentType)
-    : FileImplBase(aName, aContentType, UINT64_MAX),
+    : BlobImplBase(aName, aContentType, UINT64_MAX),
       mBlobImpls(aBlobImpls),
       mIsFromNsIFile(false)
   {
     SetLengthAndModifiedDate();
   }
 
   // Create as a blob
-  MultipartFileImpl(const nsTArray<nsRefPtr<FileImpl>>& aBlobImpls,
+  MultipartBlobImpl(const nsTArray<nsRefPtr<BlobImpl>>& aBlobImpls,
                     const nsAString& aContentType)
-    : FileImplBase(aContentType, UINT64_MAX),
+    : BlobImplBase(aContentType, UINT64_MAX),
       mBlobImpls(aBlobImpls),
       mIsFromNsIFile(false)
   {
     SetLengthAndModifiedDate();
   }
 
   // Create as a file to be later initialized
-  explicit MultipartFileImpl(const nsAString& aName)
-    : FileImplBase(aName, EmptyString(), UINT64_MAX),
+  explicit MultipartBlobImpl(const nsAString& aName)
+    : BlobImplBase(aName, EmptyString(), UINT64_MAX),
       mIsFromNsIFile(false)
   {
   }
 
   // Create as a blob to be later initialized
-  MultipartFileImpl()
-    : FileImplBase(EmptyString(), UINT64_MAX),
+  MultipartBlobImpl()
+    : BlobImplBase(EmptyString(), UINT64_MAX),
       mIsFromNsIFile(false)
   {
   }
 
   void InitializeBlob();
 
   void InitializeBlob(
        JSContext* aCx,
        const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
        const nsAString& aContentType,
        bool aNativeEOL,
        ErrorResult& aRv);
 
-  void InitializeChromeFile(File& aData,
+  void InitializeChromeFile(Blob& aData,
                             const ChromeFilePropertyBag& aBag,
                             ErrorResult& aRv);
 
   void InitializeChromeFile(nsPIDOMWindow* aWindow,
                             const nsAString& aData,
                             const ChromeFilePropertyBag& aBag,
                             ErrorResult& aRv);
 
   void InitializeChromeFile(nsPIDOMWindow* aWindow,
                             nsIFile* aData,
                             const ChromeFilePropertyBag& aBag,
                             bool aIsFromNsIFile,
                             ErrorResult& aRv);
 
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType,
               ErrorResult& aRv) override;
 
   virtual uint64_t GetSize(ErrorResult& aRv) override
   {
     return mLength;
   }
 
   virtual nsresult GetInternalStream(nsIInputStream** aInputStream) override;
 
-  virtual const nsTArray<nsRefPtr<FileImpl>>* GetSubBlobImpls() const override
+  virtual const nsTArray<nsRefPtr<BlobImpl>>* GetSubBlobImpls() const override
   {
     return &mBlobImpls;
   }
 
   virtual void GetMozFullPathInternal(nsAString& aFullPath,
                                       ErrorResult& aRv) override;
 
   virtual nsresult
@@ -113,17 +113,17 @@ public:
   void SetFromNsIFile(bool aValue)
   {
     mIsFromNsIFile = aValue;
   }
 
   virtual bool MayBeClonedToOtherThreads() const override;
 
 protected:
-  virtual ~MultipartFileImpl() {}
+  virtual ~MultipartBlobImpl() {}
 
   void SetLengthAndModifiedDate();
 
-  nsTArray<nsRefPtr<FileImpl>> mBlobImpls;
+  nsTArray<nsRefPtr<BlobImpl>> mBlobImpls;
   bool mIsFromNsIFile;
 };
 
-#endif // mozilla_dom_MultipartFileImpl_h
+#endif // mozilla_dom_MultipartBlobImpl_h
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1208,17 +1208,17 @@ Navigator::SendBeacon(const nsAString& a
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       mimeType.AssignLiteral("application/octet-stream");
       in = strStream;
 
     } else if (aData.Value().IsBlob()) {
-      File& blob = aData.Value().GetAsBlob();
+      Blob& blob = aData.Value().GetAsBlob();
       rv = blob.GetInternalStream(getter_AddRefs(in));
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       nsAutoString type;
       rv = blob.GetType(type);
       if (NS_FAILED(rv)) {
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -107,17 +107,17 @@ URL::Constructor(const nsAString& aUrl, 
   }
 
   nsRefPtr<URL> url = new URL(uri.forget());
   return url.forget();
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal,
-                     File& aBlob,
+                     Blob& aBlob,
                      const objectURLOptions& aOptions,
                      nsAString& aResult,
                      ErrorResult& aError)
 {
   CreateObjectURLInternal(aGlobal, aBlob.Impl(),
                           NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult,
                           aError);
 }
--- a/dom/base/URL.h
+++ b/dom/base/URL.h
@@ -17,17 +17,17 @@ class nsIURI;
 
 namespace mozilla {
 
 class ErrorResult;
 class DOMMediaStream;
 
 namespace dom {
 
-class File;
+class Blob;
 class MediaSource;
 class GlobalObject;
 struct objectURLOptions;
 
 namespace workers {
 class URLProxy;
 }
 
@@ -56,17 +56,17 @@ public:
   Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
               const nsAString& aBase, ErrorResult& aRv);
   static already_AddRefed<URL>
   Constructor(const nsAString& aUrl, const nsAString& aBase, ErrorResult& aRv);
   static already_AddRefed<URL>
   Constructor(const nsAString& aUrl, nsIURI* aBase, ErrorResult& aRv);
 
   static void CreateObjectURL(const GlobalObject& aGlobal,
-                              File& aBlob,
+                              Blob& aBlob,
                               const objectURLOptions& aOptions,
                               nsAString& aResult,
                               ErrorResult& aError);
   static void CreateObjectURL(const GlobalObject& aGlobal,
                               DOMMediaStream& aStream,
                               const objectURLOptions& aOptions,
                               nsAString& aResult,
                               ErrorResult& aError);
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -2205,17 +2205,17 @@ WebSocket::Send(const nsAString& aData,
 {
   AssertIsOnTargetThread();
 
   NS_ConvertUTF16toUTF8 msgString(aData);
   Send(nullptr, msgString, msgString.Length(), false, aRv);
 }
 
 void
-WebSocket::Send(File& aData, ErrorResult& aRv)
+WebSocket::Send(Blob& aData, ErrorResult& aRv)
 {
   AssertIsOnTargetThread();
 
   nsCOMPtr<nsIInputStream> msgStream;
   nsresult rv = aData.GetInternalStream(getter_AddRefs(msgStream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
--- a/dom/base/WebSocket.h
+++ b/dom/base/WebSocket.h
@@ -23,17 +23,17 @@
 #define DEFAULT_WS_SCHEME_PORT  80
 #define DEFAULT_WSS_SCHEME_PORT 443
 
 class nsIInputStream;
 
 namespace mozilla {
 namespace dom {
 
-class File;
+class Blob;
 
 class WebSocketImpl;
 
 class WebSocket final : public DOMEventTargetHelper
 {
   friend class WebSocketImpl;
 
 public:
@@ -116,17 +116,17 @@ public: // WebIDL interface:
 
   // webIDL: attribute DOMString binaryType;
   dom::BinaryType BinaryType() const;
   void SetBinaryType(dom::BinaryType aData);
 
   // webIDL: void send(DOMString|Blob|ArrayBufferView data);
   void Send(const nsAString& aData,
             ErrorResult& aRv);
-  void Send(File& aData,
+  void Send(Blob& aData,
             ErrorResult& aRv);
   void Send(const ArrayBuffer& aData,
             ErrorResult& aRv);
   void Send(const ArrayBufferView& aData,
             ErrorResult& aRv);
 
 private: // constructor && distructor
   explicit WebSocket(nsPIDOMWindow* aOwnerWindow);
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -232,17 +232,17 @@ UNIFIED_SOURCES += [
     'File.cpp',
     'FileIOObject.cpp',
     'FragmentOrElement.cpp',
     'ImageEncoder.cpp',
     'ImportManager.cpp',
     'Link.cpp',
     'MessageChannel.cpp',
     'MessagePortList.cpp',
-    'MultipartFileImpl.cpp',
+    'MultipartBlobImpl.cpp',
     'Navigator.cpp',
     'NodeInfo.cpp',
     'NodeIterator.cpp',
     'nsAtomListUtils.cpp',
     'nsAttrAndChildArray.cpp',
     'nsAttrValue.cpp',
     'nsAttrValueOrString.cpp',
     'nsCCUncollectableMarker.cpp',
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6085,26 +6085,26 @@ nsContentUtils::CreateArrayBuffer(JSCont
 nsresult
 nsContentUtils::CreateBlobBuffer(JSContext* aCx,
                                  nsISupports* aParent,
                                  const nsACString& aData,
                                  JS::MutableHandle<JS::Value> aBlob)
 {
   uint32_t blobLen = aData.Length();
   void* blobData = malloc(blobLen);
-  nsRefPtr<File> blob;
+  nsRefPtr<Blob> blob;
   if (blobData) {
     memcpy(blobData, aData.BeginReading(), blobLen);
-    blob = mozilla::dom::File::CreateMemoryFile(aParent, blobData, blobLen,
+    blob = mozilla::dom::Blob::CreateMemoryBlob(aParent, blobData, blobLen,
                                                 EmptyString());
   } else {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  if (!GetOrCreateDOMReflector(aCx, blob, aBlob)) {
+  if (!ToJSValue(aCx, blob, aBlob)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 void
 nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr)
@@ -7342,37 +7342,37 @@ nsContentUtils::TransferableToIPCTransfe
               imageDetails.stride() = stride;
               imageDetails.format() = static_cast<uint8_t>(dataSurface->GetFormat());
             }
 
             continue;
           }
 
           // Otherwise, handle this as a file.
-          nsCOMPtr<FileImpl> fileImpl;
+          nsCOMPtr<BlobImpl> blobImpl;
           nsCOMPtr<nsIFile> file = do_QueryInterface(data);
           if (file) {
-            fileImpl = new FileImplFile(file, false);
+            blobImpl = new BlobImplFile(file, false);
             ErrorResult rv;
-            fileImpl->GetSize(rv);
-            fileImpl->GetLastModified(rv);
+            blobImpl->GetSize(rv);
+            blobImpl->GetLastModified(rv);
           } else {
-            fileImpl = do_QueryInterface(data);
+            blobImpl = do_QueryInterface(data);
           }
-          if (fileImpl) {
+          if (blobImpl) {
             IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
             item->flavor() = nsCString(flavorStr);
             if (aChild) {
               item->data() =
                 mozilla::dom::BlobChild::GetOrCreate(aChild,
-                  static_cast<FileImpl*>(fileImpl.get()));
+                  static_cast<BlobImpl*>(blobImpl.get()));
             } else if (aParent) {
               item->data() =
                 mozilla::dom::BlobParent::GetOrCreate(aParent,
-                  static_cast<FileImpl*>(fileImpl.get()));
+                  static_cast<BlobImpl*>(blobImpl.get()));
             }
           } else {
             // This is a hack to support kFilePromiseMime.
             // On Windows there just needs to be an entry for it, 
             // and for OSX we need to create
             // nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
             if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
               IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
--- a/dom/base/nsDOMDataChannel.cpp
+++ b/dom/base/nsDOMDataChannel.cpp
@@ -262,17 +262,17 @@ nsDOMDataChannel::Close()
 void
 nsDOMDataChannel::Send(const nsAString& aData, ErrorResult& aRv)
 {
   NS_ConvertUTF16toUTF8 msgString(aData);
   Send(nullptr, msgString, msgString.Length(), false, aRv);
 }
 
 void
-nsDOMDataChannel::Send(File& aData, ErrorResult& aRv)
+nsDOMDataChannel::Send(Blob& aData, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
 
   nsCOMPtr<nsIInputStream> msgStream;
   nsresult rv = aData.GetInternalStream(getter_AddRefs(msgStream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
--- a/dom/base/nsDOMDataChannel.h
+++ b/dom/base/nsDOMDataChannel.h
@@ -13,17 +13,17 @@
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/net/DataChannelListener.h"
 #include "nsIDOMDataChannel.h"
 #include "nsIInputStream.h"
 
 
 namespace mozilla {
 namespace dom {
-class File;
+class Blob;
 }
 
 class DataChannel;
 };
 
 class nsDOMDataChannel final : public mozilla::DOMEventTargetHelper,
                                public nsIDOMDataChannel,
                                public mozilla::DataChannelListener
@@ -65,17 +65,17 @@ public:
       static_cast<int>(mBinaryType));
   }
   void SetBinaryType(mozilla::dom::RTCDataChannelType aType)
   {
     mBinaryType = static_cast<DataChannelBinaryType>(
       static_cast<int>(aType));
   }
   void Send(const nsAString& aData, mozilla::ErrorResult& aRv);
-  void Send(mozilla::dom::File& aData, mozilla::ErrorResult& aRv);
+  void Send(mozilla::dom::Blob& aData, mozilla::ErrorResult& aRv);
   void Send(const mozilla::dom::ArrayBuffer& aData, mozilla::ErrorResult& aRv);
   void Send(const mozilla::dom::ArrayBufferView& aData,
             mozilla::ErrorResult& aRv);
 
   // Uses XPIDL GetProtocol.
   bool Ordered() const;
   uint16_t Id() const;
   uint16_t Stream() const; // deprecated
--- a/dom/base/nsDOMFileReader.cpp
+++ b/dom/base/nsDOMFileReader.cpp
@@ -38,23 +38,23 @@ using namespace mozilla::dom;
 #define LOADEND_STR "loadend"
 
 static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileReader)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMFileReader,
                                                   FileIOObject)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFile)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBlob)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMFileReader,
                                                 FileIOObject)
   tmp->mResultArrayBuffer = nullptr;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFile)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBlob)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsDOMFileReader,
                                                DOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultArrayBuffer)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
@@ -178,53 +178,53 @@ nsDOMFileReader::GetResult(JSContext* aC
 NS_IMETHODIMP
 nsDOMFileReader::GetError(nsISupports** aError)
 {
   NS_IF_ADDREF(*aError = GetError());
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::ReadAsArrayBuffer(nsIDOMBlob* aFile, JSContext* aCx)
+nsDOMFileReader::ReadAsArrayBuffer(nsIDOMBlob* aBlob, JSContext* aCx)
 {
-  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<File> file = static_cast<File*>(aFile);
-  ReadAsArrayBuffer(aCx, *file, rv);
+  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
+  ReadAsArrayBuffer(aCx, *blob, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::ReadAsBinaryString(nsIDOMBlob* aFile)
+nsDOMFileReader::ReadAsBinaryString(nsIDOMBlob* aBlob)
 {
-  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<File> file = static_cast<File*>(aFile);
-  ReadAsBinaryString(*file, rv);
+  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
+  ReadAsBinaryString(*blob, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::ReadAsText(nsIDOMBlob* aFile,
+nsDOMFileReader::ReadAsText(nsIDOMBlob* aBlob,
                             const nsAString &aCharset)
 {
-  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<File> file = static_cast<File*>(aFile);
-  ReadAsText(*file, aCharset, rv);
+  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
+  ReadAsText(*blob, aCharset, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::ReadAsDataURL(nsIDOMBlob* aFile)
+nsDOMFileReader::ReadAsDataURL(nsIDOMBlob* aBlob)
 {
-  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aBlob, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  nsRefPtr<File> file = static_cast<File*>(aFile);
-  ReadAsDataURL(*file, rv);
+  nsRefPtr<Blob> blob = static_cast<Blob*>(aBlob);
+  ReadAsDataURL(*blob, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::Abort()
 {
   ErrorResult rv;
   FileIOObject::Abort(rv);
@@ -236,17 +236,17 @@ nsDOMFileReader::DoAbort(nsAString& aEve
 {
   // Revert status and result attributes
   SetDOMStringToNull(mResult);
   mResultArrayBuffer = nullptr;
 
   if (mAsyncStream) {
     mAsyncStream = nullptr;
   }
-  mFile = nullptr;
+  mBlob = nullptr;
 
   //Clean up memory buffer
   FreeFileData();
 
   // Tell the base class which event to dispatch
   aEvent = NS_LITERAL_STRING(LOADEND_STR);
 }
 
@@ -276,18 +276,18 @@ nsresult
 nsDOMFileReader::DoOnLoadEnd(nsresult aStatus,
                              nsAString& aSuccessEvent,
                              nsAString& aTerminationEvent)
 {
 
   // Make sure we drop all the objects that could hold files open now.
   nsCOMPtr<nsIAsyncInputStream> stream;
   mAsyncStream.swap(stream);
-  nsCOMPtr<nsIDOMBlob> file;
-  mFile.swap(file);
+  nsCOMPtr<nsIDOMBlob> blob;
+  mBlob.swap(blob);
 
   aSuccessEvent = NS_LITERAL_STRING(LOAD_STR);
   aTerminationEvent = NS_LITERAL_STRING(LOADEND_STR);
 
   // Clear out the data if necessary
   if (NS_FAILED(aStatus)) {
     FreeFileData();
     return NS_OK;
@@ -314,23 +314,23 @@ nsDOMFileReader::DoOnLoadEnd(nsresult aS
     case FILE_AS_BINARY:
       break; //Already accumulated mResult
     case FILE_AS_TEXT:
       if (!mFileData) {
         if (mDataLen) {
           rv = NS_ERROR_OUT_OF_MEMORY;
           break;
         }
-        rv = GetAsText(file, mCharset, "", mDataLen, mResult);
+        rv = GetAsText(blob, mCharset, "", mDataLen, mResult);
         break;
       }
-      rv = GetAsText(file, mCharset, mFileData, mDataLen, mResult);
+      rv = GetAsText(blob, mCharset, mFileData, mDataLen, mResult);
       break;
     case FILE_AS_DATAURL:
-      rv = GetAsDataURL(file, mFileData, mDataLen, mResult);
+      rv = GetAsDataURL(blob, mFileData, mDataLen, mResult);
       break;
   }
 
   mResult.SetIsVoid(false);
 
   FreeFileData();
 
   return rv;
@@ -375,45 +375,45 @@ nsDOMFileReader::DoReadData(nsIAsyncInpu
 
   mDataLen += aCount;
   return NS_OK;
 }
 
 // Helper methods
 
 void
-nsDOMFileReader::ReadFileContent(File& aFile,
+nsDOMFileReader::ReadFileContent(Blob& aBlob,
                                  const nsAString &aCharset,
                                  eDataFormat aDataFormat,
                                  ErrorResult& aRv)
 {
   //Implicit abort to clear any other activity going on
   Abort();
   mError = nullptr;
   SetDOMStringToNull(mResult);
   mTransferred = 0;
   mTotal = 0;
   mReadyState = nsIDOMFileReader::EMPTY;
   FreeFileData();
 
-  mFile = &aFile;
+  mBlob = &aBlob;
   mDataFormat = aDataFormat;
   CopyUTF16toUTF8(aCharset, mCharset);
 
   nsresult rv;
 
   nsCOMPtr<nsIStreamTransportService> sts =
     do_GetService(kStreamTransportServiceCID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return;
   }
 
   nsCOMPtr<nsIInputStream> stream;
-  rv = mFile->GetInternalStream(getter_AddRefs(stream));
+  rv = mBlob->GetInternalStream(getter_AddRefs(stream));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return;
   }
 
   nsCOMPtr<nsITransport> transport;
   rv = sts->CreateInputTransport(stream,
                                  /* aStartOffset */ 0,
@@ -435,17 +435,17 @@ nsDOMFileReader::ReadFileContent(File& a
     return;
   }
 
   MOZ_ASSERT(!mAsyncStream);
   mAsyncStream = do_QueryInterface(wrapper);
   MOZ_ASSERT(mAsyncStream);
 
   mTotal = mozilla::dom::kUnknownSize;
-  mFile->GetSize(&mTotal);
+  mBlob->GetSize(&mTotal);
 
   rv = DoAsyncWait(mAsyncStream);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return;
   }
 
   //FileReader should be in loading state here
@@ -457,17 +457,17 @@ nsDOMFileReader::ReadFileContent(File& a
     if (!mFileData) {
       NS_WARNING("Preallocation failed for ReadFileData");
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     }
   }
 }
 
 nsresult
-nsDOMFileReader::GetAsText(nsIDOMBlob *aFile,
+nsDOMFileReader::GetAsText(nsIDOMBlob *aBlob,
                            const nsACString &aCharset,
                            const char *aFileData,
                            uint32_t aDataLen,
                            nsAString& aResult)
 {
   // The BOM sniffing is baked into the "decode" part of the Encoding
   // Standard, which the File API references.
   nsAutoCString encoding;
@@ -475,17 +475,17 @@ nsDOMFileReader::GetAsText(nsIDOMBlob *a
         reinterpret_cast<const unsigned char *>(aFileData),
         aDataLen,
         encoding)) {
     // BOM sniffing failed. Try the API argument.
     if (!EncodingUtils::FindEncodingForLabel(aCharset,
                                              encoding)) {
       // API argument failed. Try the type property of the blob.
       nsAutoString type16;
-      aFile->GetType(type16);
+      aBlob->GetType(type16);
       NS_ConvertUTF16toUTF8 type(type16);
       nsAutoCString specifiedCharset;
       bool haveCharset;
       int32_t charsetStart, charsetEnd;
       NS_ExtractCharsetFromContentType(type,
                                        specifiedCharset,
                                        &haveCharset,
                                        &charsetStart,
@@ -497,26 +497,26 @@ nsDOMFileReader::GetAsText(nsIDOMBlob *a
     }
   }
 
   nsDependentCSubstring data(aFileData, aDataLen);
   return nsContentUtils::ConvertStringFromEncoding(encoding, data, aResult);
 }
 
 nsresult
-nsDOMFileReader::GetAsDataURL(nsIDOMBlob *aFile,
+nsDOMFileReader::GetAsDataURL(nsIDOMBlob *aBlob,
                               const char *aFileData,
                               uint32_t aDataLen,
                               nsAString& aResult)
 {
   aResult.AssignLiteral("data:");
 
   nsresult rv;
   nsString contentType;
-  rv = aFile->GetType(contentType);
+  rv = aBlob->GetType(contentType);
   if (NS_SUCCEEDED(rv) && !contentType.IsEmpty()) {
     aResult.Append(contentType);
   } else {
     aResult.AppendLiteral("application/octet-stream");
   }
   aResult.AppendLiteral(";base64,");
 
   nsCString encodedData;
--- a/dom/base/nsDOMFileReader.h
+++ b/dom/base/nsDOMFileReader.h
@@ -22,28 +22,29 @@
 #include "nsIDOMFileReader.h"
 #include "nsIDOMFileList.h"
 #include "nsCOMPtr.h"
 
 #include "FileIOObject.h"
 
 namespace mozilla {
 namespace dom {
-class File;
+class Blob;
 }
 }
 
 class nsDOMFileReader final : public mozilla::dom::FileIOObject,
                               public nsIDOMFileReader,
                               public nsIInterfaceRequestor,
                               public nsSupportsWeakReference
 {
   typedef mozilla::ErrorResult ErrorResult;
   typedef mozilla::dom::GlobalObject GlobalObject;
-  typedef mozilla::dom::File File;
+  typedef mozilla::dom::Blob Blob;
+
 public:
   nsDOMFileReader();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMFILEREADER
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(mozilla::DOMEventTargetHelper)
@@ -63,27 +64,27 @@ public:
   {
     return GetOwner();
   }
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   // WebIDL
   static already_AddRefed<nsDOMFileReader>
   Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
-  void ReadAsArrayBuffer(JSContext* aCx, File& aBlob, ErrorResult& aRv)
+  void ReadAsArrayBuffer(JSContext* aCx, Blob& aBlob, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
   }
 
-  void ReadAsText(File& aBlob, const nsAString& aLabel, ErrorResult& aRv)
+  void ReadAsText(Blob& aBlob, const nsAString& aLabel, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, aLabel, FILE_AS_TEXT, aRv);
   }
 
-  void ReadAsDataURL(File& aBlob, ErrorResult& aRv)
+  void ReadAsDataURL(Blob& aBlob, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
   }
 
   using FileIOObject::Abort;
 
   // Inherited ReadyState().
 
@@ -97,17 +98,17 @@ public:
   using FileIOObject::SetOnprogress;
   IMPL_EVENT_HANDLER(load)
   using FileIOObject::GetOnabort;
   using FileIOObject::SetOnabort;
   using FileIOObject::GetOnerror;
   using FileIOObject::SetOnerror;
   IMPL_EVENT_HANDLER(loadend)
 
-  void ReadAsBinaryString(File& aBlob, ErrorResult& aRv)
+  void ReadAsBinaryString(Blob& aBlob, ErrorResult& aRv)
   {
     ReadFileContent(aBlob, EmptyString(), FILE_AS_BINARY, aRv);
   }
 
 
   nsresult Init();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsDOMFileReader,
@@ -119,31 +120,33 @@ protected:
 
   enum eDataFormat {
     FILE_AS_ARRAYBUFFER,
     FILE_AS_BINARY,
     FILE_AS_TEXT,
     FILE_AS_DATAURL
   };
 
-  void ReadFileContent(File& aBlob,
+  void ReadFileContent(Blob& aBlob,
                        const nsAString &aCharset, eDataFormat aDataFormat,
                        ErrorResult& aRv);
-  nsresult GetAsText(nsIDOMBlob *aFile, const nsACString &aCharset,
-                     const char *aFileData, uint32_t aDataLen, nsAString &aResult);
-  nsresult GetAsDataURL(nsIDOMBlob *aFile, const char *aFileData, uint32_t aDataLen, nsAString &aResult);
+  nsresult GetAsText(nsIDOMBlob *aBlob, const nsACString &aCharset,
+                     const char *aFileData, uint32_t aDataLen,
+                     nsAString &aResult);
+  nsresult GetAsDataURL(nsIDOMBlob *aBlob, const char *aFileData,
+                        uint32_t aDataLen, nsAString &aResult);
 
   void FreeFileData() {
     free(mFileData);
     mFileData = nullptr;
     mDataLen = 0;
   }
 
   char *mFileData;
-  nsCOMPtr<nsIDOMBlob> mFile;
+  nsCOMPtr<nsIDOMBlob> mBlob;
   nsCString mCharset;
   uint32_t mDataLen;
 
   eDataFormat mDataFormat;
 
   nsString mResult;
 
   JS::Heap<JSObject*> mResultArrayBuffer;
--- a/dom/base/nsFormData.cpp
+++ b/dom/base/nsFormData.cpp
@@ -5,60 +5,56 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsFormData.h"
 #include "nsIVariant.h"
 #include "nsIInputStream.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/HTMLFormElement.h"
 
-#include "MultipartFileImpl.h"
+#include "MultipartBlobImpl.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsFormData::nsFormData(nsISupports* aOwner)
   : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr)
   , mOwner(aOwner)
 {
 }
 
 namespace {
+
 // Implements steps 3 and 4 of the "create an entry" algorithm of FormData.
-File*
-CreateNewFileInstance(File& aBlob, const Optional<nsAString>& aFilename)
+already_AddRefed<File>
+CreateNewFileInstance(Blob& aBlob, const Optional<nsAString>& aFilename)
 {
   // Step 3 "If value is a Blob object and not a File object, set value to
   // a new File object, representing the same bytes, whose name attribute value
   // is "blob"."
   // Step 4 "If value is a File object and filename is given, set value to
   // a new File object, representing the same bytes, whose name attribute
   // value is filename."
   nsAutoString filename;
   if (aFilename.WasPassed()) {
     filename = aFilename.Value();
-  } else if (aBlob.IsFile()) {
+  } else {
     // If value is already a File and filename is not passed, the spec says not
     // to create a new instance.
-    return &aBlob;
-  } else {
+    nsRefPtr<File> file = aBlob.ToFile();
+    if (file) {
+      return file.forget();
+    }
+
     filename = NS_LITERAL_STRING("blob");
   }
 
-  nsAutoTArray<nsRefPtr<FileImpl>, 1> blobImpls;
-  blobImpls.AppendElement(aBlob.Impl());
-
-  nsAutoString contentType;
-  aBlob.GetType(contentType);
+  return aBlob.ToFile(filename);
+}
 
-  nsRefPtr<MultipartFileImpl> impl =
-    new MultipartFileImpl(blobImpls, filename, contentType);
-
-  return new File(aBlob.GetParentObject(), impl);
-}
 } // anonymous namespace
 
 // -------------------------------------------------------------------------
 // nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsFormData)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormData)
@@ -106,17 +102,17 @@ nsFormData::GetEncodedSubmission(nsIURI*
 
 void
 nsFormData::Append(const nsAString& aName, const nsAString& aValue)
 {
   AddNameValuePair(aName, aValue);
 }
 
 void
-nsFormData::Append(const nsAString& aName, File& aBlob,
+nsFormData::Append(const nsAString& aName, Blob& aBlob,
                    const Optional<nsAString>& aFilename)
 {
   nsRefPtr<File> file = CreateNewFileInstance(aBlob, aFilename);
   AddNameFilePair(aName, file);
 }
 
 void
 nsFormData::Delete(const nsAString& aName)
@@ -174,16 +170,24 @@ nsFormData::Has(const nsAString& aName)
     if (aName.Equals(mFormData[i].name)) {
       return true;
     }
   }
 
   return false;
 }
 
+nsresult
+nsFormData::AddNameFilePair(const nsAString& aName, File* aFile)
+{
+  FormDataTuple* data = mFormData.AppendElement();
+  SetNameFilePair(data, aName, aFile);
+  return NS_OK;
+}
+
 nsFormData::FormDataTuple*
 nsFormData::RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName)
 {
   FormDataTuple* lastFoundTuple = nullptr;
   uint32_t lastFoundIndex = mFormData.Length();
   // We have to use this slightly awkward for loop since uint32_t >= 0 is an
   // error for being always true.
   for (uint32_t i = mFormData.Length(); i-- > 0; ) {
@@ -197,17 +201,17 @@ nsFormData::RemoveAllOthersAndGetFirstFo
       lastFoundIndex = i;
     }
   }
 
   return lastFoundTuple;
 }
 
 void
-nsFormData::Set(const nsAString& aName, File& aBlob,
+nsFormData::Set(const nsAString& aName, Blob& aBlob,
                 const Optional<nsAString>& aFilename)
 {
   FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
   if (tuple) {
     nsRefPtr<File> file = CreateNewFileInstance(aBlob, aFilename);
     SetNameFilePair(tuple, aName, file);
   } else {
     Append(aName, aBlob, aFilename);
@@ -240,17 +244,17 @@ nsFormData::Append(const nsAString& aNam
     nsCOMPtr<nsISupports> supports;
     nsID *iid;
     rv = aValue->GetAsInterface(&iid, getter_AddRefs(supports));
     NS_ENSURE_SUCCESS(rv, rv);
 
     free(iid);
 
     nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(supports);
-    nsRefPtr<File> blob = static_cast<File*>(domBlob.get());
+    nsRefPtr<Blob> blob = static_cast<Blob*>(domBlob.get());
     if (domBlob) {
       Optional<nsAString> temp;
       Append(aName, *blob, temp);
       return NS_OK;
     }
   }
 
   char16_t* stringData = nullptr;
--- a/dom/base/nsFormData.h
+++ b/dom/base/nsFormData.h
@@ -30,17 +30,19 @@ class GlobalObject;
 class nsFormData final : public nsIDOMFormData,
                          public nsIXHRSendable,
                          public nsFormSubmission,
                          public nsWrapperCache
 {
 private:
   ~nsFormData() {}
 
+  typedef mozilla::dom::Blob Blob;
   typedef mozilla::dom::File File;
+
   struct FormDataTuple
   {
     nsString name;
     nsString stringValue;
     nsRefPtr<File> fileValue;
     bool valueIsFile;
   };
 
@@ -56,21 +58,21 @@ private:
     MOZ_ASSERT(aData);
     aData->name = aName;
     aData->stringValue = aValue;
     aData->valueIsFile = false;
   }
 
   void SetNameFilePair(FormDataTuple* aData,
                        const nsAString& aName,
-                       File* aBlob)
+                       File* aFile)
   {
     MOZ_ASSERT(aData);
     aData->name = aName;
-    aData->fileValue = aBlob;
+    aData->fileValue = aFile;
     aData->valueIsFile = true;
   }
 
   void ExtractValue(const FormDataTuple& aTuple,
                     mozilla::dom::OwningFileOrUSVString* aOutValue);
 public:
   explicit nsFormData(nsISupports* aOwner = nullptr);
 
@@ -90,43 +92,38 @@ public:
   {
     return mOwner;
   }
   static already_AddRefed<nsFormData>
   Constructor(const mozilla::dom::GlobalObject& aGlobal,
               const mozilla::dom::Optional<mozilla::dom::NonNull<mozilla::dom::HTMLFormElement> >& aFormElement,
               mozilla::ErrorResult& aRv);
   void Append(const nsAString& aName, const nsAString& aValue);
-  void Append(const nsAString& aName, File& aBlob,
+  void Append(const nsAString& aName, Blob& aBlob,
               const mozilla::dom::Optional<nsAString>& aFilename);
   void Delete(const nsAString& aName);
   void Get(const nsAString& aName, mozilla::dom::Nullable<mozilla::dom::OwningFileOrUSVString>& aOutValue);
   void GetAll(const nsAString& aName, nsTArray<mozilla::dom::OwningFileOrUSVString>& aValues);
   bool Has(const nsAString& aName);
-  void Set(const nsAString& aName, File& aBlob,
+  void Set(const nsAString& aName, Blob& aBlob,
            const mozilla::dom::Optional<nsAString>& aFilename);
   void Set(const nsAString& aName, const nsAString& aValue);
 
   // nsFormSubmission
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream) override;
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) override
   {
     FormDataTuple* data = mFormData.AppendElement();
     SetNameValuePair(data, aName, aValue);
     return NS_OK;
   }
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   File* aBlob) override
-  {
-    FormDataTuple* data = mFormData.AppendElement();
-    SetNameFilePair(data, aName, aBlob);
-    return NS_OK;
-  }
+                                   File* aFile) override;
 
   typedef bool (*FormDataEntryCallback)(const nsString& aName, bool aIsFile,
                                         const nsString& aValue,
                                         File* aFile, void* aClosure);
 
   uint32_t
   Length() const
   {
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -272,17 +272,17 @@ template<ActorFlavorEnum Flavor>
 static bool
 BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType* aManager,
                        const StructuredCloneData& aData,
                        ClonedMessageData& aClonedData)
 {
   SerializedStructuredCloneBuffer& buffer = aClonedData.data();
   buffer.data = aData.mData;
   buffer.dataLength = aData.mDataLength;
-  const nsTArray<nsRefPtr<File>>& blobs = aData.mClosure.mBlobs;
+  const nsTArray<nsRefPtr<Blob>>& blobs = aData.mClosure.mBlobs;
   if (!blobs.IsEmpty()) {
     typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
     InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
     uint32_t length = blobs.Length();
     blobList.SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       typename BlobTraits<Flavor>::BlobType* protocolActor =
         aManager->GetOrCreateActorForBlob(blobs[i]);
@@ -324,22 +324,22 @@ UnpackClonedMessageData(const ClonedMess
   if (!blobs.IsEmpty()) {
     uint32_t length = blobs.Length();
     cloneData.mClosure.mBlobs.SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       auto* blob =
         static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
       MOZ_ASSERT(blob);
 
-      nsRefPtr<FileImpl> blobImpl = blob->GetBlobImpl();
+      nsRefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
       MOZ_ASSERT(blobImpl);
 
       // This object will be duplicated with a correct parent before being
       // exposed to JS.
-      nsRefPtr<File> domBlob = new File(nullptr, blobImpl);
+      nsRefPtr<Blob> domBlob = Blob::Create(nullptr, blobImpl);
       cloneData.mClosure.mBlobs.AppendElement(domBlob);
     }
   }
   return cloneData;
 }
 
 StructuredCloneData
 mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aData)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8045,31 +8045,31 @@ PostMessageReadStructuredClone(JSContext
                                void* closure)
 {
   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
   NS_ASSERTION(scInfo, "Must have scInfo!");
 
   if (tag == SCTAG_DOM_BLOB) {
     NS_ASSERTION(!data, "Data should be empty");
 
-    // What we get back from the reader is a FileImpl.
+    // What we get back from the reader is a BlobImpl.
     // From that we create a new File.
-    FileImpl* blobImpl;
+    BlobImpl* blobImpl;
     if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) {
       MOZ_ASSERT(blobImpl);
 
       // nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
       // called because the static analysis thinks dereferencing XPCOM objects
       // can GC (because in some cases it can!), and a return statement with a
       // JSObject* type means that JSObject* is on the stack as a raw pointer
       // while destructors are running.
       JS::Rooted<JS::Value> val(cx);
       {
-        nsRefPtr<File> blob = new File(scInfo->window, blobImpl);
-        if (!GetOrCreateDOMReflector(cx, blob, &val)) {
+        nsRefPtr<Blob> blob = Blob::Create(scInfo->window, blobImpl);
+        if (!ToJSValue(cx, blob, &val)) {
           return nullptr;
         }
       }
 
       return &val.toObject();
     }
   }
 
@@ -8101,19 +8101,19 @@ PostMessageWriteStructuredClone(JSContex
                                 JS::Handle<JSObject*> obj,
                                 void *closure)
 {
   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
   NS_ASSERTION(scInfo, "Must have scInfo!");
 
   // See if this is a File/Blob object.
   {
-    File* blob = nullptr;
+    Blob* blob = nullptr;
     if (scInfo->subsumes && NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
-      FileImpl* blobImpl = blob->Impl();
+      BlobImpl* 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/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -12,17 +12,17 @@
 #include "nsIPrincipal.h"
 #include "DOMMediaStream.h"
 #include "mozilla/dom/MediaSource.h"
 #include "nsIMemoryReporter.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/LoadInfo.h"
 
-using mozilla::dom::FileImpl;
+using mozilla::dom::BlobImpl;
 using mozilla::ErrorResult;
 using mozilla::LoadInfo;
 
 // -----------------------------------------------------------------------
 // Hash table
 struct DataInfo
 {
   // mObject is expected to be an nsIDOMBlob, DOMMediaStream, or MediaSource
@@ -525,17 +525,17 @@ nsHostObjectProtocolHandler::NewChannel2
   uri->GetSpec(spec);
 
   DataInfo* info = GetDataInfo(spec);
 
   if (!info) {
     return NS_ERROR_DOM_BAD_URI;
   }
 
-  nsCOMPtr<FileImpl> blob = do_QueryInterface(info->mObject);
+  nsCOMPtr<BlobImpl> blob = do_QueryInterface(info->mObject);
   if (!blob) {
     return NS_ERROR_DOM_BAD_URI;
   }
 
 #ifdef DEBUG
   {
     nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(uri);
     nsCOMPtr<nsIPrincipal> principal;
@@ -620,35 +620,35 @@ nsMediaSourceProtocolHandler::GetScheme(
 NS_IMETHODIMP
 nsFontTableProtocolHandler::GetScheme(nsACString &result)
 {
   result.AssignLiteral(FONTTABLEURI_SCHEME);
   return NS_OK;
 }
 
 nsresult
-NS_GetBlobForBlobURI(nsIURI* aURI, FileImpl** aBlob)
+NS_GetBlobForBlobURI(nsIURI* aURI, BlobImpl** aBlob)
 {
   NS_ASSERTION(IsBlobURI(aURI), "Only call this with blob URIs");
 
   *aBlob = nullptr;
 
-  nsCOMPtr<FileImpl> blob = do_QueryInterface(GetDataObject(aURI));
+  nsCOMPtr<BlobImpl> blob = do_QueryInterface(GetDataObject(aURI));
   if (!blob) {
     return NS_ERROR_DOM_BAD_URI;
   }
 
   blob.forget(aBlob);
   return NS_OK;
 }
 
 nsresult
 NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream)
 {
-  nsRefPtr<FileImpl> blobImpl;
+  nsRefPtr<BlobImpl> blobImpl;
   nsresult rv = NS_GetBlobForBlobURI(aURI, getter_AddRefs(blobImpl));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   return blobImpl->GetInternalStream(aStream);
 }
 
--- a/dom/base/nsHostObjectProtocolHandler.h
+++ b/dom/base/nsHostObjectProtocolHandler.h
@@ -19,17 +19,17 @@
 #define FONTTABLEURI_SCHEME "moz-fonttable"
 #define RTSPURI_SCHEME "rtsp"
 
 class nsIPrincipal;
 
 namespace mozilla {
 class DOMMediaStream;
 namespace dom {
-class FileImpl;
+class BlobImpl;
 class MediaSource;
 }
 }
 
 class nsHostObjectProtocolHandler : public nsIProtocolHandler
 {
 public:
   nsHostObjectProtocolHandler();
@@ -117,17 +117,17 @@ inline bool IsMediaSourceURI(nsIURI* aUr
 
 inline bool IsFontTableURI(nsIURI* aUri)
 {
   bool isFont;
   return NS_SUCCEEDED(aUri->SchemeIs(FONTTABLEURI_SCHEME, &isFont)) && isFont;
 }
 
 extern nsresult
-NS_GetBlobForBlobURI(nsIURI* aURI, mozilla::dom::FileImpl** aBlob);
+NS_GetBlobForBlobURI(nsIURI* aURI, mozilla::dom::BlobImpl** aBlob);
 
 extern nsresult
 NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream);
 
 extern nsresult
 NS_GetStreamForMediaStreamURI(nsIURI* aURI, mozilla::DOMMediaStream** aStream);
 
 extern nsresult
--- a/dom/base/nsIDOMFile.idl
+++ b/dom/base/nsIDOMFile.idl
@@ -49,18 +49,22 @@ 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();
 };
 
-[scriptable, builtinclass, uuid(74657f92-aa61-492b-8649-fd1cca62e255)]
-interface nsIDOMFile : nsIDOMBlob
+// 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
 {
   readonly attribute DOMString name;
 
   readonly attribute DOMString path;
 
   [implicit_jscontext]
   readonly attribute jsval lastModifiedDate;
 
--- a/dom/base/nsIGlobalObject.cpp
+++ b/dom/base/nsIGlobalObject.cpp
@@ -94,17 +94,17 @@ nsIGlobalObject::UnlinkHostObjectURIs()
 
 void
 nsIGlobalObject::TraverseHostObjectURIs(nsCycleCollectionTraversalCallback &aCb)
 {
   if (mHostObjectURIs.IsEmpty()) {
     return;
   }
 
-  // Currently we only store FileImpl objects off the the main-thread and they
+  // Currently we only store BlobImpl objects off the the main-thread and they
   // are not CCed.
   if (!NS_IsMainThread()) {
     return;
   }
 
   for (uint32_t index = 0; index < mHostObjectURIs.Length(); ++index) {
     nsHostObjectProtocolHandler::Traverse(mHostObjectURIs[index], aCb);
   }
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -423,17 +423,17 @@ nsXMLHttpRequest::InitParameters(bool aA
 
 void
 nsXMLHttpRequest::ResetResponse()
 {
   mResponseXML = nullptr;
   mResponseBody.Truncate();
   mResponseText.Truncate();
   mResponseBlob = nullptr;
-  mDOMFile = nullptr;
+  mDOMBlob = nullptr;
   mBlobSet = nullptr;
   mResultArrayBuffer = nullptr;
   mArrayBufferBuilder.reset();
   mResultJSON.setUndefined();
   mDataAvailable = 0;
   mLoadTransferred = 0;
   mResponseBodyDecodedPos = 0;
 }
@@ -474,17 +474,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseXML)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCORSPreflightChannel)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXMLParserStreamListener)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseBlob)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMFile)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMBlob)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationCallbacks)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannelEventSink)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProgressEventSink)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUpload)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
@@ -496,17 +496,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannel)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseXML)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCORSPreflightChannel)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mXMLParserStreamListener)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseBlob)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMFile)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMBlob)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNotificationCallbacks)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannelEventSink)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressEventSink)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mUpload)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
@@ -784,25 +784,25 @@ nsXMLHttpRequest::CreateResponseParsedJS
 
   mResultJSON = value;
   return NS_OK;
 }
 
 void
 nsXMLHttpRequest::CreatePartialBlob()
 {
-  if (mDOMFile) {
+  if (mDOMBlob) {
     // Use progress info to determine whether load is complete, but use
     // mDataAvailable to ensure a slice is created based on the uncompressed
     // data count.
     if (mLoadTotal == mLoadTransferred) {
-      mResponseBlob = mDOMFile;
+      mResponseBlob = mDOMBlob;
     } else {
       ErrorResult rv;
-      mResponseBlob = mDOMFile->CreateSlice(0, mDataAvailable,
+      mResponseBlob = mDOMBlob->CreateSlice(0, mDataAvailable,
                                             EmptyString(), rv);
     }
     return;
   }
 
   // mBlobSet can be null if the request has been canceled
   if (!mBlobSet) {
     return;
@@ -1824,17 +1824,17 @@ nsXMLHttpRequest::StreamReaderFunc(nsIIn
     NS_WARNING("XMLHttpRequest cannot read from stream: no closure or writeCount");
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv = NS_OK;
 
   if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
       xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
-    if (!xmlHttpRequest->mDOMFile) {
+    if (!xmlHttpRequest->mDOMBlob) {
       if (!xmlHttpRequest->mBlobSet) {
         xmlHttpRequest->mBlobSet = new BlobSet();
       }
       rv = xmlHttpRequest->mBlobSet->AppendVoidPtr(fromRawSegment, count);
     }
     // Clear the cache so that the blob size is updated.
     if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
       xmlHttpRequest->mResponseBlob = nullptr;
@@ -1894,31 +1894,31 @@ nsXMLHttpRequest::StreamReaderFunc(nsIIn
     *writeCount = count;
   } else {
     *writeCount = 0;
   }
 
   return rv;
 }
 
-bool nsXMLHttpRequest::CreateDOMFile(nsIRequest *request)
+bool nsXMLHttpRequest::CreateDOMBlob(nsIRequest *request)
 {
   nsCOMPtr<nsIFile> file;
   nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(request);
   if (fc) {
     fc->GetFile(getter_AddRefs(file));
   }
 
   if (!file)
     return false;
 
   nsAutoCString contentType;
   mChannel->GetContentType(contentType);
 
-  mDOMFile = File::CreateFromFile(GetOwner(), file, EmptyString(),
+  mDOMBlob = File::CreateFromFile(GetOwner(), file, EmptyString(),
                                   NS_ConvertASCIItoUTF16(contentType));
 
   mBlobSet = nullptr;
   NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
   return true;
 }
 
 NS_IMETHODIMP
@@ -1931,30 +1931,30 @@ nsXMLHttpRequest::OnDataAvailable(nsIReq
   NS_ENSURE_ARG_POINTER(inStr);
 
   MOZ_ASSERT(mContext.get() == ctxt,"start context different from OnDataAvailable context");
 
   mProgressSinceLastProgressEvent = true;
 
   bool cancelable = false;
   if ((mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
-       mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) && !mDOMFile) {
-    cancelable = CreateDOMFile(request);
+       mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) && !mDOMBlob) {
+    cancelable = CreateDOMBlob(request);
     // The nsIStreamListener contract mandates us
     // to read from the stream before returning.
   }
 
   uint32_t totalRead;
   nsresult rv = inStr->ReadSegments(nsXMLHttpRequest::StreamReaderFunc,
                                     (void*)this, count, &totalRead);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (cancelable) {
     // We don't have to read from the local file for the blob response
-    mDOMFile->GetSize(&mDataAvailable);
+    mDOMBlob->GetSize(&mDataAvailable);
     ChangeState(XML_HTTP_REQUEST_LOADING);
     return request->Cancel(NS_OK);
   }
 
   mDataAvailable += totalRead;
 
   ChangeState(XML_HTTP_REQUEST_LOADING);
   
@@ -2241,22 +2241,22 @@ nsXMLHttpRequest::OnStopRequest(nsIReque
   // until the parser is done.
   if (!mIsHtml) {
     MaybeDispatchProgressEvents(true);
   }
 
   if (NS_SUCCEEDED(status) &&
       (mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
        mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB)) {
-    if (!mDOMFile) {
-      CreateDOMFile(request);
+    if (!mDOMBlob) {
+      CreateDOMBlob(request);
     }
-    if (mDOMFile) {
-      mResponseBlob = mDOMFile;
-      mDOMFile = nullptr;
+    if (mDOMBlob) {
+      mResponseBlob = mDOMBlob;
+      mDOMBlob = nullptr;
     } else {
       // mBlobSet can be null if the channel is non-file non-cacheable
       // and if the response length is zero.
       if (!mBlobSet) {
         mBlobSet = new BlobSet();
       }
       // Smaller files may be written in cache map instead of separate files.
       // Also, no-store response cannot be written in persistent cache.
--- a/dom/base/nsXMLHttpRequest.h
+++ b/dom/base/nsXMLHttpRequest.h
@@ -46,18 +46,18 @@ class nsFormData;
 class nsIJARChannel;
 class nsILoadGroup;
 class nsIUnicodeDecoder;
 class nsIJSID;
 
 namespace mozilla {
 
 namespace dom {
+class Blob;
 class BlobSet;
-class File;
 }
 
 // A helper for building up an ArrayBuffer object's data
 // before creating the ArrayBuffer itself.  Will do doubling
 // based reallocation, up to an optional maximum growth given.
 //
 // When all the data has been appended, call getArrayBuffer,
 // passing in the JSContext* for which the ArrayBuffer object
@@ -347,17 +347,17 @@ private:
     explicit RequestBody(const mozilla::dom::ArrayBuffer* aArrayBuffer) : mType(ArrayBuffer)
     {
       mValue.mArrayBuffer = aArrayBuffer;
     }
     explicit RequestBody(const mozilla::dom::ArrayBufferView* aArrayBufferView) : mType(ArrayBufferView)
     {
       mValue.mArrayBufferView = aArrayBufferView;
     }
-    explicit RequestBody(mozilla::dom::File& aBlob) : mType(Blob)
+    explicit RequestBody(mozilla::dom::Blob& aBlob) : mType(Blob)
     {
       mValue.mBlob = &aBlob;
     }
     explicit RequestBody(nsIDocument* aDocument) : mType(Document)
     {
       mValue.mDocument = aDocument;
     }
     explicit RequestBody(const nsAString& aString) : mType(DOMString)
@@ -381,17 +381,17 @@ private:
       Document,
       DOMString,
       FormData,
       InputStream
     };
     union Value {
       const mozilla::dom::ArrayBuffer* mArrayBuffer;
       const mozilla::dom::ArrayBufferView* mArrayBufferView;
-      mozilla::dom::File* mBlob;
+      mozilla::dom::Blob* mBlob;
       nsIDocument* mDocument;
       const nsAString* mString;
       nsFormData* mFormData;
       nsIInputStream* mStream;
     };
 
     Type GetType() const
     {
@@ -445,17 +445,17 @@ public:
     aRv = Send(RequestBody(&aArrayBuffer));
   }
   void Send(JSContext* /*aCx*/,
             const mozilla::dom::ArrayBufferView& aArrayBufferView,
             ErrorResult& aRv)
   {
     aRv = Send(RequestBody(&aArrayBufferView));
   }
-  void Send(JSContext* /*aCx*/, mozilla::dom::File& aBlob, ErrorResult& aRv)
+  void Send(JSContext* /*aCx*/, mozilla::dom::Blob& aBlob, ErrorResult& aRv)
   {
     aRv = Send(RequestBody(aBlob));
   }
   void Send(JSContext* /*aCx*/, nsIDocument& aDoc, ErrorResult& aRv)
   {
     aRv = Send(RequestBody(&aDoc));
   }
   void Send(JSContext* aCx, const nsAString& aString, ErrorResult& aRv)
@@ -601,17 +601,17 @@ protected:
   static NS_METHOD StreamReaderFunc(nsIInputStream* in,
                 void* closure,
                 const char* fromRawSegment,
                 uint32_t toOffset,
                 uint32_t count,
                 uint32_t *writeCount);
   nsresult CreateResponseParsedJSON(JSContext* aCx);
   void CreatePartialBlob();
-  bool CreateDOMFile(nsIRequest *request);
+  bool CreateDOMBlob(nsIRequest *request);
   // Change the state of the object with this. The broadcast argument
   // determines if the onreadystatechange listener should be called.
   nsresult ChangeState(uint32_t aState, bool aBroadcast = true);
   already_AddRefed<nsILoadGroup> GetLoadGroup() const;
   nsIURI *GetBaseURI();
 
   already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel();
   already_AddRefed<nsIJARChannel> GetCurrentJARChannel();
@@ -703,22 +703,22 @@ protected:
   };
 
   void SetResponseType(nsXMLHttpRequest::ResponseTypeEnum aType, ErrorResult& aRv);
 
   ResponseTypeEnum mResponseType;
 
   // It is either a cached blob-response from the last call to GetResponse,
   // but is also explicitly set in OnStopRequest.
-  nsRefPtr<mozilla::dom::File> mResponseBlob;
+  nsRefPtr<mozilla::dom::Blob> mResponseBlob;
   // Non-null only when we are able to get a os-file representation of the
   // response, i.e. when loading from a file.
-  nsRefPtr<mozilla::dom::File> mDOMFile;
+  nsRefPtr<mozilla::dom::Blob> mDOMBlob;
   // We stream data to mBlobSet when response type is "blob" or "moz-blob"
-  // and mDOMFile is null.
+  // and mDOMBlob is null.
   nsAutoPtr<mozilla::dom::BlobSet> mBlobSet;
 
   nsString mOverrideMimeType;
 
   /**
    * The notification callbacks the channel had when Send() was
    * called.  We want to forward things here as needed.
    */
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -133,17 +133,16 @@ DOMInterfaces = {
     },
 },
 
 'BarProp': {
     'headerFile': 'mozilla/dom/BarProps.h',
 },
 
 'Blob': {
-    'nativeType': 'mozilla::dom::File',
     'headerFile': 'mozilla/dom/File.h',
 },
 
 'BatteryManager': {
     'nativeType': 'mozilla::dom::battery::BatteryManager',
     'headerFile': 'BatteryManager.h'
 },
 
--- a/dom/bluetooth/bluedroid/BluetoothOppManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothOppManager.cpp
@@ -407,18 +407,18 @@ BluetoothOppManager::StartSendingNextFil
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               BlobParent* aActor)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsRefPtr<FileImpl> impl = aActor->GetBlobImpl();
-  nsCOMPtr<nsIDOMBlob> blob = new File(nullptr, impl);
+  nsRefPtr<BlobImpl> impl = aActor->GetBlobImpl();
+  nsRefPtr<Blob> blob = Blob::Create(nullptr, impl);
 
   return SendFile(aDeviceAddress, blob.get());
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               nsIDOMBlob* aBlob)
 {
--- a/dom/bluetooth/bluetooth1/BluetoothAdapter.cpp
+++ b/dom/bluetooth/bluetooth1/BluetoothAdapter.cpp
@@ -761,17 +761,17 @@ BluetoothAdapter::IsConnected(const uint
   }
   bs->IsConnected(aServiceUuid, results);
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
-                           File& aBlob, ErrorResult& aRv)
+                           Blob& aBlob, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
--- a/dom/bluetooth/bluetooth1/BluetoothAdapter.h
+++ b/dom/bluetooth/bluetooth1/BluetoothAdapter.h
@@ -10,17 +10,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "BluetoothCommon.h"
 #include "BluetoothPropertyContainer.h"
 #include "nsCOMPtr.h"
 
 namespace mozilla {
 namespace dom {
-class File;
+class Blob;
 class DOMRequest;
 struct MediaMetaData;
 struct MediaPlayStatus;
 }
 }
 
 BEGIN_BLUETOOTH_NAMESPACE
 
@@ -129,17 +129,17 @@ public:
   already_AddRefed<DOMRequest>
     IsConnected(const uint16_t aServiceUuid,
                 ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
     GetConnectedDevices(uint16_t aServiceUuid, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
-    SendFile(const nsAString& aDeviceAddress, File& aBlob,
+    SendFile(const nsAString& aDeviceAddress, Blob& aBlob,
              ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     StopSendingFile(const nsAString& aDeviceAddress, ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     ConfirmReceivingFile(const nsAString& aDeviceAddress, bool aConfirmation,
                          ErrorResult& aRv);
 
   already_AddRefed<DOMRequest> ConnectSco(ErrorResult& aRv);
--- a/dom/bluetooth/bluetooth2/BluetoothAdapter.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothAdapter.cpp
@@ -1256,17 +1256,17 @@ BluetoothAdapter::Disconnect(BluetoothDe
   }
   bs->Disconnect(address, serviceUuid, results);
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
-                           File& aBlob, ErrorResult& aRv)
+                           Blob& aBlob, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
--- a/dom/bluetooth/bluetooth2/BluetoothAdapter.h
+++ b/dom/bluetooth/bluetooth2/BluetoothAdapter.h
@@ -12,18 +12,18 @@
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/BluetoothAdapter2Binding.h"
 #include "mozilla/dom/BluetoothDeviceEvent.h"
 #include "mozilla/dom/Promise.h"
 #include "nsCOMPtr.h"
 
 namespace mozilla {
 namespace dom {
+class Blob;
 class DOMRequest;
-class File;
 struct MediaMetaData;
 struct MediaPlayStatus;
 }
 }
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothDevice;
@@ -127,17 +127,17 @@ public:
     Disconnect(BluetoothDevice& aDevice,
                const Optional<short unsigned int>& aServiceUuid,
                ErrorResult& aRv);
   already_AddRefed<DOMRequest> GetConnectedDevices(uint16_t aServiceUuid,
                                                    ErrorResult& aRv);
 
   // OPP file transfer related methods
   already_AddRefed<DOMRequest> SendFile(const nsAString& aDeviceAddress,
-                                        File& aBlob,
+                                        Blob& aBlob,
                                         ErrorResult& aRv);
   already_AddRefed<DOMRequest> StopSendingFile(const nsAString& aDeviceAddress,
                                                ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     ConfirmReceivingFile(const nsAString& aDeviceAddress,
                          bool aConfirmation,
                          ErrorResult& aRv);
 
--- a/dom/bluetooth/bluez/BluetoothOppManager.cpp
+++ b/dom/bluetooth/bluez/BluetoothOppManager.cpp
@@ -379,18 +379,18 @@ BluetoothOppManager::StartSendingNextFil
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               BlobParent* aActor)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsRefPtr<FileImpl> impl = aActor->GetBlobImpl();
-  nsCOMPtr<nsIDOMBlob> blob = new File(nullptr, impl);
+  nsRefPtr<BlobImpl> impl = aActor->GetBlobImpl();
+  nsCOMPtr<nsIDOMBlob> blob = Blob::Create(nullptr, impl);
 
   return SendFile(aDeviceAddress, blob.get());
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               nsIDOMBlob* aBlob)
 {
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -207,17 +207,17 @@ public:
 
     SerializedStructuredCloneBuffer& buffer = message.data();
     buffer.data = mData->mBuffer.data();
     buffer.dataLength = mData->mBuffer.nbytes();
 
     PBackgroundChild* backgroundManager = mActor->Manager();
     MOZ_ASSERT(backgroundManager);
 
-    const nsTArray<nsRefPtr<File>>& blobs = mData->mClosure.mBlobs;
+    const nsTArray<nsRefPtr<Blob>>& blobs = mData->mClosure.mBlobs;
 
     if (!blobs.IsEmpty()) {
       message.blobsChild().SetCapacity(blobs.Length());
 
       for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
         PBlobChild* blobChild =
           BackgroundChild::GetOrCreateActorForBlob(backgroundManager, blobs[i]);
         MOZ_ASSERT(blobChild);
@@ -536,17 +536,17 @@ BroadcastChannel::PostMessageInternal(JS
 {
   nsRefPtr<BroadcastChannelMessage> data = new BroadcastChannelMessage();
 
   if (!WriteStructuredClone(aCx, aMessage, data->mBuffer, data->mClosure)) {
     aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
     return;
   }
 
-  const nsTArray<nsRefPtr<File>>& blobs = data->mClosure.mBlobs;
+  const nsTArray<nsRefPtr<Blob>>& blobs = data->mClosure.mBlobs;
   for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
     if (!blobs[i]->Impl()->MayBeClonedToOtherThreads()) {
       aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
       return;
     }
   }
 
   PostMessageData(data);
--- a/dom/broadcastchannel/BroadcastChannelChild.cpp
+++ b/dom/broadcastchannel/BroadcastChannelChild.cpp
@@ -37,26 +37,26 @@ BroadcastChannelChild::~BroadcastChannel
   MOZ_ASSERT(!mBC);
 }
 
 bool
 BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData)
 {
   // Make sure to retrieve all blobs from the message before returning to avoid
   // leaking their actors.
-  nsTArray<nsRefPtr<File>> files;
+  nsTArray<nsRefPtr<Blob>> blobs;
   if (!aData.blobsChild().IsEmpty()) {
-    files.SetCapacity(aData.blobsChild().Length());
+    blobs.SetCapacity(aData.blobsChild().Length());
 
     for (uint32_t i = 0, len = aData.blobsChild().Length(); i < len; ++i) {
-      nsRefPtr<FileImpl> impl =
+      nsRefPtr<BlobImpl> impl =
         static_cast<BlobChild*>(aData.blobsChild()[i])->GetBlobImpl();
 
-      nsRefPtr<File> file = new File(mBC ? mBC->GetOwner() : nullptr, impl);
-      files.AppendElement(file);
+      nsRefPtr<Blob> blob = Blob::Create(mBC ? mBC->GetOwner() : nullptr, impl);
+      blobs.AppendElement(blob);
     }
   }
 
   nsCOMPtr<DOMEventTargetHelper> helper = mBC;
   nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(helper);
 
   // This object has been already closed by content or is going to be deleted
   // soon. No notify is required.
@@ -87,17 +87,17 @@ BroadcastChannelChild::RecvNotify(const 
   }
 
   JSContext* cx = jsapi.cx();
 
   const SerializedStructuredCloneBuffer& buffer = aData.data();
   StructuredCloneData cloneData;
   cloneData.mData = buffer.data;
   cloneData.mDataLength = buffer.dataLength;
-  cloneData.mClosure.mBlobs.SwapElements(files);
+  cloneData.mClosure.mBlobs.SwapElements(blobs);
 
   JS::Rooted<JS::Value> value(cx, JS::NullValue());
   if (cloneData.mDataLength && !ReadStructuredClone(cx, cloneData, &value)) {
     JS_ClearPendingException(cx);
     return false;
   }
 
   RootedDictionary<MessageEventInit> init(cx);
--- a/dom/broadcastchannel/BroadcastChannelParent.cpp
+++ b/dom/broadcastchannel/BroadcastChannelParent.cpp
@@ -112,17 +112,17 @@ BroadcastChannelParent::CheckAndDeliver(
       return;
     }
 
     // Duplicate the data for this parent.
     ClonedMessageData newData(aData);
 
     // Ricreate the BlobParent for this new message.
     for (uint32_t i = 0, len = newData.blobsParent().Length(); i < len; ++i) {
-      nsRefPtr<FileImpl> impl =
+      nsRefPtr<BlobImpl> impl =
         static_cast<BlobParent*>(newData.blobsParent()[i])->GetBlobImpl();
 
       PBlobParent* blobParent =
         BackgroundParent::GetOrCreateActorForBlobImpl(Manager(), impl);
       if (!blobParent) {
         return;
       }
 
--- a/dom/broadcastchannel/BroadcastChannelService.cpp
+++ b/dom/broadcastchannel/BroadcastChannelService.cpp
@@ -97,35 +97,35 @@ struct MOZ_STACK_CLASS PostMessageData f
     , mPrivateBrowsing(aPrivateBrowsing)
   {
     MOZ_ASSERT(aParent);
     MOZ_COUNT_CTOR(PostMessageData);
 
     // We need to keep the array alive for the life-time of this
     // PostMessageData.
     if (!aData.blobsParent().IsEmpty()) {
-      mFiles.SetCapacity(aData.blobsParent().Length());
+      mBlobs.SetCapacity(aData.blobsParent().Length());
 
       for (uint32_t i = 0, len = aData.blobsParent().Length(); i < len; ++i) {
-        nsRefPtr<FileImpl> impl =
+        nsRefPtr<BlobImpl> impl =
           static_cast<BlobParent*>(aData.blobsParent()[i])->GetBlobImpl();
        MOZ_ASSERT(impl);
-       mFiles.AppendElement(impl);
+       mBlobs.AppendElement(impl);
       }
     }
   }
 
   ~PostMessageData()
   {
     MOZ_COUNT_DTOR(PostMessageData);
   }
 
   BroadcastChannelParent* mParent;
   const ClonedMessageData& mData;
-  nsTArray<nsRefPtr<FileImpl>> mFiles;
+  nsTArray<nsRefPtr<BlobImpl>> mBlobs;
   const nsString mOrigin;
   const nsString mChannel;
   uint64_t mAppId;
   bool mIsInBrowserElement;
   bool mPrivateBrowsing;
 };
 
 PLDHashOperator
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -1400,17 +1400,17 @@ nsDOMCameraControl::OnTakePictureComplet
   MOZ_ASSERT(aPicture);
 
   nsRefPtr<Promise> promise = mTakePicturePromise.forget();
   if (promise) {
     nsCOMPtr<nsIDOMBlob> picture = aPicture;
     promise->MaybeResolve(picture);
   }
 
-  nsRefPtr<File> blob = static_cast<File*>(aPicture);
+  nsRefPtr<Blob> blob = static_cast<Blob*>(aPicture);
   BlobEventInit eventInit;
   eventInit.mData = blob;
 
   nsRefPtr<BlobEvent> event = BlobEvent::Constructor(this,
                                                      NS_LITERAL_STRING("picture"),
                                                      eventInit);
 
   DispatchTrustedEvent(event);
--- a/dom/camera/DOMCameraControlListener.cpp
+++ b/dom/camera/DOMCameraControlListener.cpp
@@ -355,17 +355,17 @@ DOMCameraControlListener::OnTakePictureC
         mData = (uint8_t*) malloc(aLength);
         memcpy(mData, aData, aLength);
     }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) override
     {
       nsCOMPtr<nsIDOMBlob> picture =
-        File::CreateMemoryFile(mDOMCameraControl.get(),
+        Blob::CreateMemoryBlob(mDOMCameraControl.get(),
                                static_cast<void*>(mData),
                                static_cast<uint64_t>(mLength),
                                mMimeType);
       aDOMCameraControl->OnTakePictureComplete(picture);
       mData = NULL;
     }
 
   protected:
--- a/dom/camera/TestGonkCameraHardware.cpp
+++ b/dom/camera/TestGonkCameraHardware.cpp
@@ -101,29 +101,29 @@ TestGonkCameraHardwareListener::HandleEv
     }
   } else if (eventType.EqualsLiteral("shutter")) {
     DOM_CAMERA_LOGI("Inject shutter event");
     OnShutter(mTarget);
   } else if (eventType.EqualsLiteral("picture")) {
     BlobEvent* event = aEvent->InternalDOMEvent()->AsBlobEvent();
 
     if (!NS_WARN_IF(!event)) {
-      File* file = event->GetData();
+      Blob* blob = event->GetData();
 
-      if (file) {
+      if (blob) {
         static const uint64_t MAX_FILE_SIZE = 2147483647;
         uint64_t dataLength = 0;
-        nsresult rv = file->GetSize(&dataLength);
+        nsresult rv = blob->GetSize(&dataLength);
 
         if (NS_WARN_IF(NS_FAILED(rv) || dataLength > MAX_FILE_SIZE)) {
           return NS_OK;
         }
 
         nsCOMPtr<nsIInputStream> inputStream;
-        rv = file->GetInternalStream(getter_AddRefs(inputStream));
+        rv = blob->GetInternalStream(getter_AddRefs(inputStream));
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return NS_OK;
         }
 
         uint8_t* data = new uint8_t[dataLength];
         rv = NS_ReadInputStreamToBuffer(inputStream,
                                         reinterpret_cast<void**>(&data),
                                         static_cast<uint32_t>(dataLength));
--- a/dom/devicestorage/DeviceStorage.h
+++ b/dom/devicestorage/DeviceStorage.h
@@ -24,16 +24,17 @@
 #define DEVICESTORAGE_CRASHES    "crashes"
 
 class nsIInputStream;
 class nsIOutputStream;
 
 namespace mozilla {
 class EventListenerManager;
 namespace dom {
+class Blob;
 struct DeviceStorageEnumerationParameters;
 class DOMCursor;
 class DOMRequest;
 class Promise;
 class DeviceStorageFileSystem;
 } // namespace dom
 namespace ipc {
 class FileDescriptor;
@@ -217,25 +218,26 @@ public:
     return GetOwner();
   }
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   IMPL_EVENT_HANDLER(change)
 
   already_AddRefed<DOMRequest>
-  Add(nsIDOMBlob* aBlob, ErrorResult& aRv);
+  Add(mozilla::dom::Blob* aBlob, ErrorResult& aRv);
   already_AddRefed<DOMRequest>
-  AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath, ErrorResult& aRv);
+  AddNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
-  AppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath, ErrorResult& aRv);
+  AppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
+              ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
-  AddOrAppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
+  AddOrAppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
                    const int32_t aRequestType, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
   Get(const nsAString& aPath, ErrorResult& aRv)
   {
     return GetInternal(aPath, false, aRv);
   }
   already_AddRefed<DOMRequest>
--- a/dom/devicestorage/DeviceStorageRequestChild.cpp
+++ b/dom/devicestorage/DeviceStorageRequestChild.cpp
@@ -99,18 +99,19 @@ DeviceStorageRequestChild::
       mRequest->FireSuccess(result);
       break;
     }
 
     case DeviceStorageResponseValue::TBlobResponse:
     {
       BlobResponse r = aValue;
       BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
-      nsRefPtr<FileImpl> bloblImpl = actor->GetBlobImpl();
-      nsRefPtr<File> blob = new File(mRequest->GetParentObject(), bloblImpl);
+      nsRefPtr<BlobImpl> bloblImpl = actor->GetBlobImpl();
+      nsRefPtr<Blob> blob = Blob::Create(mRequest->GetParentObject(),
+                                         bloblImpl);
 
       AutoJSContext cx;
 
       JS::Rooted<JSObject*> obj(cx, blob->WrapObject(cx, JS::NullPtr()));
       MOZ_ASSERT(obj);
 
       JS::Rooted<JS::Value> result(cx, JS::ObjectValue(*obj));
       mRequest->FireSuccess(result);
--- a/dom/devicestorage/DeviceStorageRequestParent.cpp
+++ b/dom/devicestorage/DeviceStorageRequestParent.cpp
@@ -40,17 +40,17 @@ DeviceStorageRequestParent::Dispatch()
     case DeviceStorageParams::TDeviceStorageAddParams:
     {
       DeviceStorageAddParams p = mParams;
 
       nsRefPtr<DeviceStorageFile> dsf =
         new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
 
       BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
-      nsRefPtr<FileImpl> blobImpl = bp->GetBlobImpl();
+      nsRefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
 
       nsCOMPtr<nsIInputStream> stream;
       blobImpl->GetInternalStream(getter_AddRefs(stream));
 
       nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream,
                                                           DEVICE_STORAGE_REQUEST_CREATE);
 
       nsCOMPtr<nsIEventTarget> target
@@ -63,17 +63,17 @@ DeviceStorageRequestParent::Dispatch()
     case DeviceStorageParams::TDeviceStorageAppendParams:
     {
       DeviceStorageAppendParams p = mParams;
 
       nsRefPtr<DeviceStorageFile> dsf =
         new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
 
       BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
-      nsRefPtr<FileImpl> blobImpl = bp->GetBlobImpl();
+      nsRefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
 
       nsCOMPtr<nsIInputStream> stream;
       blobImpl->GetInternalStream(getter_AddRefs(stream));
 
       nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream,
                                                           DEVICE_STORAGE_REQUEST_APPEND);
 
       nsCOMPtr<nsIEventTarget> target
@@ -518,22 +518,22 @@ nsresult
 DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsString mime;
   CopyASCIItoUTF16(mMimeType, mime);
 
   nsString fullPath;
   mFile->GetFullPath(fullPath);
-  nsRefPtr<File> blob = new File(nullptr,
-    new FileImplFile(fullPath, mime, mLength, mFile->mFile,
-                     mLastModificationDate));
+  nsRefPtr<BlobImpl> blob =
+    new BlobImplFile(fullPath, mime, mLength, mFile->mFile,
+                     mLastModificationDate);
 
   ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
-  BlobParent* actor = cp->GetOrCreateActorForBlob(blob);
+  BlobParent* actor = cp->GetOrCreateActorForBlobImpl(blob);
   if (!actor) {
     ErrorResponse response(NS_LITERAL_STRING(POST_ERROR_EVENT_UNKNOWN));
     unused << mParent->Send__delete__(mParent, response);
     return NS_OK;
   }
 
   BlobResponse response;
   response.blobParent() = actor;
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -269,17 +269,17 @@ DeviceStorageTypeChecker::InitFromBundle
     getter_Copies(mMusicExtensions));
   aBundle->GetStringFromName(
     NS_ConvertASCIItoUTF16(DEVICESTORAGE_VIDEOS).get(),
     getter_Copies(mVideosExtensions));
 }
 
 
 bool
-DeviceStorageTypeChecker::Check(const nsAString& aType, nsIDOMBlob* aBlob)
+DeviceStorageTypeChecker::Check(const nsAString& aType, Blob* aBlob)
 {
   MOZ_ASSERT(aBlob);
 
   nsString mimeType;
   if (NS_FAILED(aBlob->GetType(mimeType))) {
     return false;
   }
 
@@ -1919,18 +1919,18 @@ nsIFileToJsval(nsPIDOMWindow* aWindow, D
   aFile->GetFullPath(fullPath);
 
   // This check is useful to know if somewhere the DeviceStorageFile
   // has not been properly set. Mimetype is not checked because it can be
   // empty.
   MOZ_ASSERT(aFile->mLength != UINT64_MAX);
   MOZ_ASSERT(aFile->mLastModifiedDate != UINT64_MAX);
 
-  nsCOMPtr<nsIDOMBlob> blob = new File(aWindow,
-    new FileImplFile(fullPath, aFile->mMimeType,
+  nsCOMPtr<nsIDOMBlob> blob = Blob::Create(aWindow,
+    new BlobImplFile(fullPath, aFile->mMimeType,
                      aFile->mLength, aFile->mFile,
                      aFile->mLastModifiedDate));
   return InterfaceToJsval(aWindow, blob, &NS_GET_IID(nsIDOMBlob));
 }
 
 bool
 StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString,
               JS::MutableHandle<JS::Value> result)
@@ -2605,17 +2605,17 @@ public:
 private:
   nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
   nsRefPtr<DOMRequest> mRequest;
 };
 
 class WriteFileEvent : public nsRunnable
 {
 public:
-  WriteFileEvent(FileImpl* aBlobImpl,
+  WriteFileEvent(BlobImpl* aBlobImpl,
                  DeviceStorageFile *aFile,
                  already_AddRefed<DOMRequest> aRequest,
                  int32_t aRequestType)
     : mBlobImpl(aBlobImpl)
     , mFile(aFile)
     , mRequest(aRequest)
     , mRequestType(aRequestType)
   {
@@ -2671,17 +2671,17 @@ public:
     nsString fullPath;
     mFile->GetFullPath(fullPath);
     nsCOMPtr<nsIRunnable> event =
       new PostResultEvent(mRequest.forget(), fullPath);
     return NS_DispatchToMainThread(event);
   }
 
 private:
-  nsRefPtr<FileImpl> mBlobImpl;
+  nsRefPtr<BlobImpl> mBlobImpl;
   nsRefPtr<DeviceStorageFile> mFile;
   nsRefPtr<DOMRequest> mRequest;
   int32_t mRequestType;
 };
 
 
 class ReadFileEvent : public nsRunnable
 {
@@ -2871,17 +2871,17 @@ public:
     MOZ_ASSERT(mDeviceStorage);
   }
 
   DeviceStorageRequest(const DeviceStorageRequestType aRequestType,
                        nsPIDOMWindow* aWindow,
                        nsIPrincipal* aPrincipal,
                        DeviceStorageFile* aFile,
                        DOMRequest* aRequest,
-                       nsIDOMBlob* aBlob = nullptr)
+                       Blob* aBlob = nullptr)
     : mRequestType(aRequestType)
     , mWindow(aWindow)
     , mPrincipal(aPrincipal)
     , mFile(aFile)
     , mRequest(aRequest)
     , mBlob(aBlob)
     , mRequester(new nsContentPermissionRequester(mWindow))
   {
@@ -3043,17 +3043,17 @@ public:
           r = new PostErrorEvent(mRequest.forget(),
                                  POST_ERROR_EVENT_ILLEGAL_TYPE);
           return NS_DispatchToCurrentThread(r);
         }
 
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
           BlobChild* actor
             = ContentChild::GetSingleton()->GetOrCreateActorForBlob(
-              static_cast<File*>(mBlob.get()));
+              static_cast<Blob*>(mBlob.get()));
           if (!actor) {
             return NS_ERROR_FAILURE;
           }
 
           DeviceStorageAddParams params;
           params.blobChild() = actor;
           params.type() = mFile->mStorageType;
           params.storageName() = mFile->mStorageName;
@@ -3089,17 +3089,17 @@ public:
           r = new PostErrorEvent(mRequest.forget(),
                                  POST_ERROR_EVENT_ILLEGAL_TYPE);
           return NS_DispatchToCurrentThread(r);
         }
 
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
           BlobChild* actor
             = ContentChild::GetSingleton()->GetOrCreateActorForBlob(
-              static_cast<File*>(mBlob.get()));
+              static_cast<Blob*>(mBlob.get()));
           if (!actor) {
             return NS_ERROR_FAILURE;
           }
 
           DeviceStorageAppendParams params;
           params.blobChild() = actor;
           params.type() = mFile->mStorageType;
           params.storageName() = mFile->mStorageName;
@@ -3326,17 +3326,17 @@ private:
   ~DeviceStorageRequest() {}
 
   int32_t mRequestType;
   nsCOMPtr<nsPIDOMWindow> mWindow;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsRefPtr<DeviceStorageFile> mFile;
 
   nsRefPtr<DOMRequest> mRequest;
-  nsCOMPtr<nsIDOMBlob> mBlob;
+  nsRefPtr<Blob> mBlob;
   nsRefPtr<nsDOMDeviceStorage> mDeviceStorage;
   nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
   nsCOMPtr<nsIContentPermissionRequester> mRequester;
 };
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageRequest)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
   NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
@@ -3736,23 +3736,23 @@ nsDOMDeviceStorage::IsAvailable()
   nsRefPtr<DeviceStorageFile> dsf(new DeviceStorageFile(mStorageType, mStorageName));
   return dsf->IsAvailable();
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::Add(nsIDOMBlob *aBlob, nsIDOMDOMRequest * *_retval)
 {
   ErrorResult rv;
-  nsRefPtr<DOMRequest> request = Add(aBlob, rv);
+  nsRefPtr<DOMRequest> request = Add(static_cast<Blob*>(aBlob), rv);
   request.forget(_retval);
   return rv.StealNSResult();
 }
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::Add(nsIDOMBlob* aBlob, ErrorResult& aRv)
+nsDOMDeviceStorage::Add(Blob* aBlob, ErrorResult& aRv)
 {
   if (!aBlob) {
     return nullptr;
   }
 
   nsCOMPtr<nsIMIMEService> mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID);
   if (!mimeSvc) {
     aRv.Throw(NS_ERROR_FAILURE);
@@ -3785,40 +3785,40 @@ nsDOMDeviceStorage::Add(nsIDOMBlob* aBlo
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::AddNamed(nsIDOMBlob *aBlob,
                              const nsAString & aPath,
                              nsIDOMDOMRequest * *_retval)
 {
   ErrorResult rv;
-  nsRefPtr<DOMRequest> request = AddNamed(aBlob, aPath, rv);
+  nsRefPtr<DOMRequest> request = AddNamed(static_cast<Blob*>(aBlob), aPath, rv);
   request.forget(_retval);
   return rv.StealNSResult();
 }
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
+nsDOMDeviceStorage::AddNamed(Blob* aBlob, const nsAString& aPath,
                              ErrorResult& aRv)
 {
   return AddOrAppendNamed(aBlob, aPath,
                           DEVICE_STORAGE_REQUEST_CREATE, aRv);
 }
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::AppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
+nsDOMDeviceStorage::AppendNamed(Blob* aBlob, const nsAString& aPath,
                                 ErrorResult& aRv)
 {
   return AddOrAppendNamed(aBlob, aPath,
                           DEVICE_STORAGE_REQUEST_APPEND, aRv);
 }
 
 
 already_AddRefed<DOMRequest>
-nsDOMDeviceStorage::AddOrAppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
+nsDOMDeviceStorage::AddOrAppendNamed(Blob* aBlob, const nsAString& aPath,
                                      const int32_t aRequestType, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // if the blob is null here, bail
   if (!aBlob) {
     return nullptr;
   }
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -28,16 +28,20 @@ class nsPIDOMWindow;
 #include "nsIStringBundle.h"
 #include "mozilla/Mutex.h"
 #include "prtime.h"
 #include "DeviceStorage.h"
 #include "mozilla/StaticPtr.h"
 
 namespace mozilla {
 class ErrorResult;
+
+namespace dom {
+class Blob;
+}
 } // namespace mozilla
 
 #define POST_ERROR_EVENT_FILE_EXISTS                 "NoModificationAllowedError"
 #define POST_ERROR_EVENT_FILE_DOES_NOT_EXIST         "NotFoundError"
 #define POST_ERROR_EVENT_FILE_NOT_ENUMERABLE         "TypeMismatchError"
 #define POST_ERROR_EVENT_PERMISSION_DENIED           "SecurityError"
 #define POST_ERROR_EVENT_ILLEGAL_TYPE                "TypeMismatchError"
 #define POST_ERROR_EVENT_UNKNOWN                     "Unknown"
@@ -152,17 +156,17 @@ class DeviceStorageTypeChecker final
 public:
   static DeviceStorageTypeChecker* CreateOrGet();
 
   DeviceStorageTypeChecker();
   ~DeviceStorageTypeChecker();
 
   void InitFromBundle(nsIStringBundle* aBundle);
 
-  bool Check(const nsAString& aType, nsIDOMBlob* aBlob);
+  bool Check(const nsAString& aType, mozilla::dom::Blob* aBlob);
   bool Check(const nsAString& aType, nsIFile* aFile);
   bool Check(const nsAString& aType, const nsString& aPath);
   void GetTypeFromFile(nsIFile* aFile, nsAString& aType);
   void GetTypeFromFileName(const nsAString& aFileName, nsAString& aType);
 
   static nsresult GetPermissionForType(const nsAString& aType, nsACString& aPermissionResult);
   static nsresult GetAccessForRequest(const DeviceStorageRequestType aRequestType, nsACString& aAccessResult);
   static bool IsVolumeBased(const nsAString& aType);
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -299,21 +299,25 @@ DataTransfer::GetFiles(ErrorResult& aRv)
         continue;
 
       nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
 
       nsRefPtr<File> domFile;
       if (file) {
         domFile = File::CreateFromFile(GetParentObject(), file);
       } else {
-        nsCOMPtr<FileImpl> fileImpl = do_QueryInterface(supports);
-        if (!fileImpl) {
+        nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(supports);
+        if (!blobImpl) {
           continue;
         }
-        domFile = new File(GetParentObject(), static_cast<FileImpl*>(fileImpl.get()));
+
+        MOZ_ASSERT(blobImpl->IsFile());
+
+        domFile = File::Create(GetParentObject(), blobImpl);
+        MOZ_ASSERT(domFile);
       }
 
       if (!mFiles->Append(domFile)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return nullptr;
       }
     }
   }
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -441,20 +441,20 @@ ExtractFromArrayBufferView(const ArrayBu
   aBuffer.ComputeLengthAndData();
   //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
   return NS_NewByteInputStream(aStream,
                                reinterpret_cast<char*>(aBuffer.Data()),
                                aBuffer.Length(), NS_ASSIGNMENT_COPY);
 }
 
 nsresult
-ExtractFromBlob(const File& aFile, nsIInputStream** aStream,
+ExtractFromBlob(const Blob& aBlob, nsIInputStream** aStream,
                 nsCString& aContentType)
 {
-  nsRefPtr<FileImpl> impl = aFile.Impl();
+  nsRefPtr<BlobImpl> impl = aBlob.Impl();
   nsresult rv = impl->GetInternalStream(aStream);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsAutoString type;
   impl->GetType(type);
   aContentType = NS_ConvertUTF16toUTF8(type);
@@ -768,17 +768,17 @@ private:
       body.BeginReading(bodyIter);
       body.EndReading(bodyEnd);
       char *p = copy;
       while (bodyIter != bodyEnd) {
         *p++ = *bodyIter++;
       }
       p = nullptr;
 
-      nsRefPtr<File> file =
+      nsRefPtr<Blob> file =
         File::CreateMemoryFile(mParentObject,
                                reinterpret_cast<void *>(copy), body.Length(),
                                NS_ConvertUTF8toUTF16(mFilename),
                                NS_ConvertUTF8toUTF16(mContentType), /* aLastModifiedDate */ 0);
       Optional<nsAString> dummy;
       mFormData->Append(name, *file, dummy);
     }
 
@@ -905,17 +905,17 @@ ExtractByteStreamFromBody(const OwningAr
 
   if (aBodyInit.IsArrayBuffer()) {
     const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
     return ExtractFromArrayBuffer(buf, aStream);
   } else if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream);
   } else if (aBodyInit.IsBlob()) {
-    const File& blob = aBodyInit.GetAsBlob();
+    const Blob& blob = aBodyInit.GetAsBlob();
     return ExtractFromBlob(blob, aStream, aContentType);
   } else if (aBodyInit.IsFormData()) {
     nsFormData& form = aBodyInit.GetAsFormData();
     return ExtractFromFormData(form, aStream, aContentType);
   } else if (aBodyInit.IsUSVString()) {
     nsAutoString str;
     str.Assign(aBodyInit.GetAsUSVString());
     return ExtractFromUSVString(str, aStream, aContentType);
@@ -937,17 +937,17 @@ ExtractByteStreamFromBody(const ArrayBuf
 
   if (aBodyInit.IsArrayBuffer()) {
     const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
     return ExtractFromArrayBuffer(buf, aStream);
   } else if (aBodyInit.IsArrayBufferView()) {
     const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
     return ExtractFromArrayBufferView(buf, aStream);
   } else if (aBodyInit.IsBlob()) {
-    const File& blob = aBodyInit.GetAsBlob();
+    const Blob& blob = aBodyInit.GetAsBlob();
     return ExtractFromBlob(blob, aStream, aContentType);
   } else if (aBodyInit.IsFormData()) {
     nsFormData& form = aBodyInit.GetAsFormData();
     return ExtractFromFormData(form, aStream, aContentType);
   } else if (aBodyInit.IsUSVString()) {
     nsAutoString str;
     str.Assign(aBodyInit.GetAsUSVString());
     return ExtractFromUSVString(str, aStream, aContentType);
@@ -1502,19 +1502,20 @@ FetchBody<Derived>::ContinueConsumeBody(
       JS::Rooted<JS::Value> val(cx);
       val.setObjectOrNull(arrayBuffer);
       localPromise->MaybeResolve(cx, val);
       // ArrayBuffer takes over ownership.
       autoFree.Reset();
       return;
     }
     case CONSUME_BLOB: {
-      nsRefPtr<File> blob =
-        File::CreateMemoryFile(DerivedClass()->GetParentObject(),
-                               reinterpret_cast<void *>(aResult), aResultLength, NS_ConvertUTF8toUTF16(mMimeType));
+      nsRefPtr<dom::Blob> blob =
+        Blob::CreateMemoryBlob(DerivedClass()->GetParentObject(),
+                               reinterpret_cast<void *>(aResult), aResultLength,
+                               NS_ConvertUTF8toUTF16(mMimeType));
 
       if (!blob) {
         localPromise->MaybeReject(NS_ERROR_DOM_UNKNOWN_ERR);
         return;
       }
 
       localPromise->MaybeResolve(blob);
       // File takes over ownership.
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -203,19 +203,19 @@ FetchDriver::BasicFetch()
       response->SetBody(body);
       BeginResponse(response);
       return SucceedWithResponse();
     }
     return FailWithNetworkError();
   }
 
   if (scheme.LowerCaseEqualsLiteral("blob")) {
-    nsRefPtr<FileImpl> blobImpl;
+    nsRefPtr<BlobImpl> blobImpl;
     rv = NS_GetBlobForBlobURI(uri, getter_AddRefs(blobImpl));
-    FileImpl* blob = static_cast<FileImpl*>(blobImpl.get());
+    BlobImpl* blob = static_cast<BlobImpl*>(blobImpl.get());
     if (NS_WARN_IF(NS_FAILED(rv))) {
       FailWithNetworkError();
       return rv;
     }
 
     nsRefPtr<InternalResponse> response = new InternalResponse(200, NS_LITERAL_CSTRING("OK"));
     {
       ErrorResult result;
--- a/dom/filehandle/FileHandle.cpp
+++ b/dom/filehandle/FileHandle.cpp
@@ -617,20 +617,20 @@ FileHandleBase::GetInputStream(const Arr
   }
 
   *aInputLength = length;
   return stream.forget();
 }
 
 // static
 already_AddRefed<nsIInputStream>
-FileHandleBase::GetInputStream(const File& aValue, uint64_t* aInputLength,
+FileHandleBase::GetInputStream(const Blob& aValue, uint64_t* aInputLength,
                                ErrorResult& aRv)
 {
-  File& file = const_cast<File&>(aValue);
+  Blob& file = const_cast<Blob&>(aValue);
   uint64_t length = file.GetSize(aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   nsCOMPtr<nsIInputStream> stream;
   aRv = file.GetInternalStream(getter_AddRefs(stream));
   if (aRv.Failed()) {
--- a/dom/filehandle/FileHandle.h
+++ b/dom/filehandle/FileHandle.h
@@ -20,17 +20,17 @@
 #include "nsIRunnable.h"
 #include "nsTArray.h"
 
 class nsAString;
 
 namespace mozilla {
 namespace dom {
 
-class File;
+class Blob;
 class FileHelper;
 class FileRequestBase;
 class FileService;
 class FinishHelper;
 class MetadataHelper;
 class MutableFileBase;
 
 /**
@@ -235,17 +235,17 @@ protected:
   nsresult
   Finish();
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(const ArrayBuffer& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 
   static already_AddRefed<nsIInputStream>
-  GetInputStream(const File& aValue, uint64_t* aInputLength,
+  GetInputStream(const Blob& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(const nsAString& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 };
 
 class FinishHelper final : public nsIRunnable
--- a/dom/filesystem/CreateFileTask.cpp
+++ b/dom/filesystem/CreateFileTask.cpp
@@ -22,17 +22,17 @@
 
 namespace mozilla {
 namespace dom {
 
 uint32_t CreateFileTask::sOutputBufferSize = 0;
 
 CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
                                const nsAString& aPath,
-                               File* aBlobData,
+                               Blob* aBlobData,
                                InfallibleTArray<uint8_t>& aArrayData,
                                bool replace,
                                ErrorResult& aRv)
   : FileSystemTaskBase(aFileSystem)
   , mTargetRealPath(aPath)
   , mReplace(replace)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
@@ -74,17 +74,17 @@ CreateFileTask::CreateFileTask(FileSyste
   auto& data = aParam.data();
 
   if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
     mArrayData = data;
     return;
   }
 
   BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
-  nsRefPtr<FileImpl> blobImpl = bp->GetBlobImpl();
+  nsRefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
   MOZ_ASSERT(blobImpl, "blobData should not be null.");
 
   nsresult rv = blobImpl->GetInternalStream(getter_AddRefs(mBlobStream));
   NS_WARN_IF(NS_FAILED(rv));
 }
 
 CreateFileTask::~CreateFileTask()
 {
@@ -122,34 +122,32 @@ CreateFileTask::GetRequestParams(const n
   }
   return param;
 }
 
 FileSystemResponseValue
 CreateFileTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
-  nsRefPtr<File> file = new File(mFileSystem->GetWindow(),
-                                       mTargetFileImpl);
-  BlobParent* actor = GetBlobParent(file);
+  BlobParent* actor = GetBlobParent(mTargetBlobImpl);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
 
 void
 CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   FileSystemFileResponse r = aValue;
   BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
-  mTargetFileImpl = actor->GetBlobImpl();
+  mTargetBlobImpl = actor->GetBlobImpl();
 }
 
 nsresult
 CreateFileTask::Work()
 {
   class AutoClose
   {
   public:
@@ -256,17 +254,17 @@ CreateFileTask::Work()
 
     mBlobStream->Close();
     mBlobStream = nullptr;
 
     if (mFileSystem->IsShutdown()) {
       return NS_ERROR_FAILURE;
     }
 
-    mTargetFileImpl = new FileImplFile(file);
+    mTargetBlobImpl = new BlobImplFile(file);
     return NS_OK;
   }
 
   // Write file content from array data.
 
   uint32_t written;
   rv = bufferedOutputStream->Write(
     reinterpret_cast<char*>(mArrayData.Elements()),
@@ -275,17 +273,17 @@ CreateFileTask::Work()
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (mArrayData.Length() != written) {
     return NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
   }
 
-  mTargetFileImpl = new FileImplFile(file);
+  mTargetBlobImpl = new BlobImplFile(file);
   return NS_OK;
 }
 
 void
 CreateFileTask::HandlerCallback()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mFileSystem->IsShutdown()) {
@@ -298,18 +296,18 @@ CreateFileTask::HandlerCallback()
     nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
       mErrorValue);
     mPromise->MaybeRejectBrokenly(domError);
     mPromise = nullptr;
     mBlobData = nullptr;
     return;
   }
 
-  nsCOMPtr<nsIDOMFile> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
-  mPromise->MaybeResolve(file);
+  nsRefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetBlobImpl);
+  mPromise->MaybeResolve(blob);
   mPromise = nullptr;
   mBlobData = nullptr;
 }
 
 void
 CreateFileTask::GetPermissionAccessType(nsCString& aAccess) const
 {
   if (mReplace) {
--- a/dom/filesystem/CreateFileTask.h
+++ b/dom/filesystem/CreateFileTask.h
@@ -11,27 +11,27 @@
 #include "nsAutoPtr.h"
 #include "mozilla/ErrorResult.h"
 
 class nsIInputStream;
 
 namespace mozilla {
 namespace dom {
 
-class File;
-class FileImpl;
+class Blob;
+class BlobImpl;
 class Promise;
 
 class CreateFileTask final
   : public FileSystemTaskBase
 {
 public:
   CreateFileTask(FileSystemBase* aFileSystem,
                  const nsAString& aPath,
-                 File* aBlobData,
+                 Blob* aBlobData,
                  InfallibleTArray<uint8_t>& aArrayData,
                  bool replace,
                  ErrorResult& aRv);
   CreateFileTask(FileSystemBase* aFileSystem,
                  const FileSystemCreateFileParams& aParam,
                  FileSystemRequestParent* aParent);
 
   virtual
@@ -63,23 +63,23 @@ private:
   void
   GetOutputBufferSize() const;
 
   static uint32_t sOutputBufferSize;
   nsRefPtr<Promise> mPromise;
   nsString mTargetRealPath;
 
   // Not thread-safe and should be released on main thread.
-  nsRefPtr<File> mBlobData;
+  nsRefPtr<Blob> mBlobData;
 
   nsCOMPtr<nsIInputStream> mBlobStream;
   InfallibleTArray<uint8_t> mArrayData;
   bool mReplace;
 
   // This cannot be a File because this object is created on a different
-  // thread and File is not thread-safe. Let's use the FileImpl instead.
-  nsRefPtr<FileImpl> mTargetFileImpl;
+  // thread and File is not thread-safe. Let's use the BlobImpl instead.
+  nsRefPtr<BlobImpl> mTargetBlobImpl;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CreateFileTask_h
--- a/dom/filesystem/DeviceStorageFileSystem.cpp
+++ b/dom/filesystem/DeviceStorageFileSystem.cpp
@@ -109,17 +109,17 @@ DeviceStorageFileSystem::GetLocalFile(co
   nsresult rv = NS_NewLocalFile(localPath, false, getter_AddRefs(file));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
   return file.forget();
 }
 
 bool
-DeviceStorageFileSystem::GetRealPath(FileImpl* aFile, nsAString& aRealPath) const
+DeviceStorageFileSystem::GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const
 {
   MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
              "Should be on parent process!");
   MOZ_ASSERT(aFile, "aFile Should not be null.");
 
   aRealPath.Truncate();
 
   nsAutoString filePath;
--- a/dom/filesystem/DeviceStorageFileSystem.h
+++ b/dom/filesystem/DeviceStorageFileSystem.h
@@ -32,17 +32,17 @@ public:
 
   virtual nsPIDOMWindow*
   GetWindow() const override;
 
   virtual already_AddRefed<nsIFile>
   GetLocalFile(const nsAString& aRealPath) const override;
 
   virtual bool
-  GetRealPath(FileImpl* aFile, nsAString& aRealPath) const override;
+  GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const override;
 
   virtual const nsAString&
   GetRootName() const override;
 
   virtual bool
   IsSafeFile(nsIFile* aFile) const override;
 
   virtual bool
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -95,17 +95,17 @@ Directory::GetName(nsString& aRetval) co
 }
 
 already_AddRefed<Promise>
 Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
                       ErrorResult& aRv)
 {
   nsresult error = NS_OK;
   nsString realPath;
-  nsRefPtr<File> blobData;
+  nsRefPtr<Blob> blobData;
   InfallibleTArray<uint8_t> arrayData;
   bool replace = (aOptions.mIfExists == CreateIfExistsMode::Replace);
 
   // Get the file content.
   if (aOptions.mData.WasPassed()) {
     auto& data = aOptions.mData.Value();
     if (data.IsString()) {
       NS_ConvertUTF16toUTF8 str(data.GetAsString());
@@ -187,37 +187,37 @@ Directory::RemoveDeep(const StringOrFile
 }
 
 already_AddRefed<Promise>
 Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
                           ErrorResult& aRv)
 {
   nsresult error = NS_OK;
   nsString realPath;
-  nsRefPtr<FileImpl> file;
+  nsRefPtr<BlobImpl> blob;
 
   // Check and get the target path.
 
   if (aPath.IsFile()) {
-    file = aPath.GetAsFile().Impl();
+    blob = aPath.GetAsFile().Impl();
   } else if (aPath.IsString()) {
     if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) {
       error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
     }
   } else if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) {
     error = NS_ERROR_DOM_SECURITY_ERR;
   } else {
     realPath = aPath.GetAsDirectory().mPath;
     // The target must be a descendant of this directory.
     if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) {
       error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
     }
   }
 
-  nsRefPtr<RemoveTask> task = new RemoveTask(mFileSystem, mPath, file, realPath,
+  nsRefPtr<RemoveTask> task = new RemoveTask(mFileSystem, mPath, blob, realPath,
     aRecursive, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
   task->SetError(error);
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
--- a/dom/filesystem/FileSystemBase.h
+++ b/dom/filesystem/FileSystemBase.h
@@ -10,18 +10,18 @@
 #include "nsAutoPtr.h"
 #include "nsString.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
+class BlobImpl;
 class Directory;
-class FileImpl;
 
 class FileSystemBase
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileSystemBase)
 public:
 
   // Create file system object from its string representation.
   static already_AddRefed<FileSystemBase>
@@ -68,17 +68,17 @@ public:
   IsSafeDirectory(Directory* aDir) const;
 
   /*
    * Get the real path (absolute DOM path) of the DOM file in the file system.
    * If succeeded, returns true. Otherwise, returns false and set aRealPath to
    * empty string.
    */
   virtual bool
-  GetRealPath(FileImpl* aFile, nsAString& aRealPath) const = 0;
+  GetRealPath(BlobImpl* aFile, nsAString& aRealPath) const = 0;
 
   /*
    * Get the permission name required to access this file system.
    */
   const nsCString&
   GetPermission() const
   {
     return mPermission;
--- a/dom/filesystem/FileSystemTaskBase.cpp
+++ b/dom/filesystem/FileSystemTaskBase.cpp
@@ -149,33 +149,43 @@ bool
 FileSystemTaskBase::Recv__delete__(const FileSystemResponseValue& aValue)
 {
   SetRequestResult(aValue);
   HandlerCallback();
   return true;
 }
 
 BlobParent*
-FileSystemTaskBase::GetBlobParent(nsIDOMFile* aFile) const
+FileSystemTaskBase::GetBlobParent(BlobImpl* aFile) const
 {
   MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
              "Only call from parent process!");
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   MOZ_ASSERT(aFile);
 
   // Load the lazy dom file data from the parent before sending to the child.
   nsString mimeType;
   aFile->GetType(mimeType);
-  uint64_t fileSize;
-  aFile->GetSize(&fileSize);
-  int64_t lastModifiedDate;
-  aFile->GetMozLastModifiedDate(&lastModifiedDate);
+
+  // We call GetSize and GetLastModified to prepopulate the value in the
+  // BlobImpl.
+  {
+    ErrorResult rv;
+    aFile->GetSize(rv);
+    rv.SuppressException();
+  }
+
+  {
+    ErrorResult rv;
+    aFile->GetLastModified(rv);
+    rv.SuppressException();
+  }
 
   ContentParent* cp = static_cast<ContentParent*>(mRequestParent->Manager());
-  return cp->GetOrCreateActorForBlob(static_cast<File*>(aFile));
+  return cp->GetOrCreateActorForBlobImpl(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,20 @@
 
 #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 BlobImpl;
 class BlobParent;
 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
@@ -200,17 +199,17 @@ protected:
   bool
   HasError() const { return mErrorValue != NS_OK; }
 
   // Overrides PFileSystemRequestChild
   virtual bool
   Recv__delete__(const FileSystemResponseValue& value) override;
 
   BlobParent*
-  GetBlobParent(nsIDOMFile* aFile) const;
+  GetBlobParent(BlobImpl* aBlob) 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,35 +77,34 @@ GetFileOrDirectoryTask::GetRequestParams
 FileSystemResponseValue
 GetFileOrDirectoryTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mIsDirectory) {
     return FileSystemDirectoryResponse(mTargetRealPath);
   }
 
-  nsRefPtr<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
-  BlobParent* actor = GetBlobParent(file);
+  BlobParent* actor = GetBlobParent(mTargetBlobImpl);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
 
 void
 GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   switch (aValue.type()) {
     case FileSystemResponseValue::TFileSystemFileResponse: {
       FileSystemFileResponse r = aValue;
       BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
-      mTargetFileImpl = actor->GetBlobImpl();
+      mTargetBlobImpl = actor->GetBlobImpl();
       mIsDirectory = false;
       break;
     }
     case FileSystemResponseValue::TFileSystemDirectoryResponse: {
       FileSystemDirectoryResponse r = aValue;
       mTargetRealPath = r.realPath();
       mIsDirectory = true;
       break;
@@ -180,17 +179,17 @@ GetFileOrDirectoryTask::Work()
     // Neither directory or file.
     return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
   }
 
   if (!mFileSystem->IsSafeFile(file)) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
-  mTargetFileImpl = new FileImplFile(file);
+  mTargetBlobImpl = new BlobImplFile(file);
 
   return NS_OK;
 }
 
 void
 GetFileOrDirectoryTask::HandlerCallback()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
@@ -209,18 +208,18 @@ GetFileOrDirectoryTask::HandlerCallback(
 
   if (mIsDirectory) {
     nsRefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
     mPromise->MaybeResolve(dir);
     mPromise = nullptr;
     return;
   }
 
-  nsRefPtr<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
-  mPromise->MaybeResolve(file);
+  nsRefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetBlobImpl);
+  mPromise->MaybeResolve(blob);
   mPromise = nullptr;
 }
 
 void
 GetFileOrDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
 {
   aAccess.AssignLiteral("read");
 }
--- a/dom/filesystem/GetFileOrDirectoryTask.h
+++ b/dom/filesystem/GetFileOrDirectoryTask.h
@@ -9,17 +9,17 @@
 
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "nsAutoPtr.h"
 #include "mozilla/ErrorResult.h"
 
 namespace mozilla {
 namespace dom {
 
-class FileImpl;
+class BlobImpl;
 
 class GetFileOrDirectoryTask final
   : public FileSystemTaskBase
 {
 public:
   // If aDirectoryOnly is set, we should ensure that the target is a directory.
   GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
                          const nsAString& aTargetPath,
@@ -55,16 +55,16 @@ protected:
 
 private:
   nsRefPtr<Promise> mPromise;
   nsString mTargetRealPath;
   // Whether we get a directory.
   bool mIsDirectory;
 
   // This cannot be a File bacause this object is created on a different
-  // thread and File is not thread-safe. Let's use the FileImpl instead.
-  nsRefPtr<FileImpl> mTargetFileImpl;
+  // thread and File is not thread-safe. Let's use the BlobImpl instead.
+  nsRefPtr<BlobImpl> mTargetBlobImpl;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_GetFileOrDirectory_h
--- a/dom/filesystem/RemoveTask.cpp
+++ b/dom/filesystem/RemoveTask.cpp
@@ -16,23 +16,23 @@
 #include "nsIFile.h"
 #include "nsStringGlue.h"
 
 namespace mozilla {
 namespace dom {
 
 RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
                        const nsAString& aDirPath,
-                       FileImpl* aTargetFile,
+                       BlobImpl* aTargetBlob,
                        const nsAString& aTargetPath,
                        bool aRecursive,
                        ErrorResult& aRv)
   : FileSystemTaskBase(aFileSystem)
   , mDirRealPath(aDirPath)
-  , mTargetFileImpl(aTargetFile)
+  , mTargetBlobImpl(aTargetBlob)
   , mTargetRealPath(aTargetPath)
   , mRecursive(aRecursive)
   , mReturnValue(false)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   MOZ_ASSERT(aFileSystem);
   nsCOMPtr<nsIGlobalObject> globalObject =
     do_QueryInterface(aFileSystem->GetWindow());
@@ -61,18 +61,18 @@ RemoveTask::RemoveTask(FileSystemBase* a
   const FileSystemPathOrFileValue& target = aParam.target();
 
   if (target.type() == FileSystemPathOrFileValue::TnsString) {
     mTargetRealPath = target;
     return;
   }
 
   BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(target));
-  mTargetFileImpl = bp->GetBlobImpl();
-  MOZ_ASSERT(mTargetFileImpl);
+  mTargetBlobImpl = bp->GetBlobImpl();
+  MOZ_ASSERT(mTargetBlobImpl);
 }
 
 RemoveTask::~RemoveTask()
 {
   MOZ_ASSERT(!mPromise || NS_IsMainThread(),
              "mPromise should be released on main thread!");
 }
 
@@ -86,20 +86,21 @@ RemoveTask::GetPromise()
 FileSystemParams
 RemoveTask::GetRequestParams(const nsString& aFileSystem) const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   FileSystemRemoveParams param;
   param.filesystem() = aFileSystem;
   param.directory() = mDirRealPath;
   param.recursive() = mRecursive;
-  if (mTargetFileImpl) {
-    nsRefPtr<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
+  if (mTargetBlobImpl) {
+    nsRefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(),
+                                       mTargetBlobImpl);
     BlobChild* actor
-      = ContentChild::GetSingleton()->GetOrCreateActorForBlob(file);
+      = ContentChild::GetSingleton()->GetOrCreateActorForBlob(blob);
     if (actor) {
       param.target() = actor;
     }
   } else {
     param.target() = mTargetRealPath;
   }
   return param;
 }
@@ -126,18 +127,18 @@ RemoveTask::Work()
              "Only call from parent process!");
   MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!");
 
   if (mFileSystem->IsShutdown()) {
     return NS_ERROR_FAILURE;
   }
 
   // Get the DOM path if a File is passed as the target.
-  if (mTargetFileImpl) {
-    if (!mFileSystem->GetRealPath(mTargetFileImpl, mTargetRealPath)) {
+  if (mTargetBlobImpl) {
+    if (!mFileSystem->GetRealPath(mTargetBlobImpl, mTargetRealPath)) {
       return NS_ERROR_DOM_SECURITY_ERR;
     }
     if (!FileSystemUtils::IsDescendantPath(mDirRealPath, mTargetRealPath)) {
       return NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
     }
   }
 
   nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
--- a/dom/filesystem/RemoveTask.h
+++ b/dom/filesystem/RemoveTask.h
@@ -9,26 +9,26 @@
 
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "nsAutoPtr.h"
 #include "mozilla/ErrorResult.h"
 
 namespace mozilla {
 namespace dom {
 
-class FileImpl;
+class BlobImpl;
 class Promise;
 
 class RemoveTask final
   : public FileSystemTaskBase
 {
 public:
   RemoveTask(FileSystemBase* aFileSystem,
              const nsAString& aDirPath,
-             FileImpl* aTargetFile,
+             BlobImpl* aTargetBlob,
              const nsAString& aTargetPath,
              bool aRecursive,
              ErrorResult& aRv);
   RemoveTask(FileSystemBase* aFileSystem,
              const FileSystemRemoveParams& aParam,
              FileSystemRequestParent* aParent);
 
   virtual
@@ -55,18 +55,18 @@ protected:
 
   virtual void
   HandlerCallback() override;
 
 private:
   nsRefPtr<Promise> mPromise;
   nsString mDirRealPath;
   // This cannot be a File because this object will be used on a different
-  // thread and File is not thread-safe. Let's use the FileImpl instead.
-  nsRefPtr<FileImpl> mTargetFileImpl;
+  // thread and File is not thread-safe. Let's use the BlobImpl instead.
+  nsRefPtr<BlobImpl> mTargetBlobImpl;
   nsString mTargetRealPath;
   bool mRecursive;
   bool mReturnValue;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -550,29 +550,29 @@ HTMLCanvasElement::ToBlob(JSContext* aCx
   class EncodeCallback : public EncodeCompleteCallback
   {
   public:
     EncodeCallback(nsIGlobalObject* aGlobal, FileCallback* aCallback)
       : mGlobal(aGlobal)
       , mFileCallback(aCallback) {}
 
     // This is called on main thread.
-    nsresult ReceiveBlob(already_AddRefed<File> aBlob)
+    nsresult ReceiveBlob(already_AddRefed<Blob> aBlob)
     {
-      nsRefPtr<File> blob = aBlob;
+      nsRefPtr<Blob> blob = aBlob;
       uint64_t size;
       nsresult rv = blob->GetSize(&size);
       if (NS_SUCCEEDED(rv)) {
         AutoJSAPI jsapi;
         if (jsapi.Init(mGlobal)) {
           JS_updateMallocCounter(jsapi.cx(), size);
         }
       }
 
-      nsRefPtr<File> newBlob = new File(mGlobal, blob->Impl());
+      nsRefPtr<Blob> newBlob = Blob::Create(mGlobal, blob->Impl());
 
       mozilla::ErrorResult error;
       mFileCallback->Call(*newBlob, error);
 
       mGlobal = nullptr;
       mFileCallback = nullptr;
 
       return error.StealNSResult();
@@ -613,21 +613,21 @@ HTMLCanvasElement::MozGetAsFile(const ns
   OwnerDoc()->WarnOnceAbout(nsIDocument::eMozGetAsFile);
 
   // do a trust check if this is a write-only canvas
   if ((mWriteOnly) &&
       !nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
-  return MozGetAsFileImpl(aName, aType, aResult);
+  return MozGetAsBlobImpl(aName, aType, aResult);
 }
 
 nsresult
-HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
+HTMLCanvasElement::MozGetAsBlobImpl(const nsAString& aName,
                                     const nsAString& aType,
                                     nsIDOMFile** aResult)
 {
   nsCOMPtr<nsIInputStream> stream;
   nsAutoString type(aType);
   nsresult rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -227,17 +227,17 @@ protected:
                        bool* usingCustomParseOptions);
   nsresult ExtractData(nsAString& aType,
                        const nsAString& aOptions,
                        nsIInputStream** aStream);
   nsresult ToDataURLImpl(JSContext* aCx,
                          const nsAString& aMimeType,
                          const JS::Value& aEncoderOptions,
                          nsAString& aDataURL);
-  nsresult MozGetAsFileImpl(const nsAString& aName,
+  nsresult MozGetAsBlobImpl(const nsAString& aName,
                             const nsAString& aType,
                             nsIDOMFile** aResult);
   void CallPrintCallback();
 
   CanvasContextType mCurrentContextType;
   nsRefPtr<HTMLCanvasElement> mOriginalCanvas;
   nsRefPtr<PrintCallback> mPrintCallback;
   nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -213,59 +213,66 @@ const Decimal HTMLInputElement::kStepAny
 static const uint32_t kProgressEventInterval = 50; // ms
 
 class HTMLInputElementState final : public nsISupports
 {
   public:
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_INPUT_ELEMENT_STATE_IID)
     NS_DECL_ISUPPORTS
 
-    bool IsCheckedSet() {
+    bool IsCheckedSet()
+    {
       return mCheckedSet;
     }
 
-    bool GetChecked() {
+    bool GetChecked()
+    {
       return mChecked;
     }
 
-    void SetChecked(bool aChecked) {
+    void SetChecked(bool aChecked)
+    {
       mChecked = aChecked;
       mCheckedSet = true;
     }
 
-    const nsString& GetValue() {
+    const nsString& GetValue()
+    {
       return mValue;
     }
 
-    void SetValue(const nsAString& aValue) {
+    void SetValue(const nsAString& aValue)
+    {
       mValue = aValue;
     }
 
-    const nsTArray<nsRefPtr<FileImpl>>& GetFileImpls() {
-      return mFileImpls;
-    }
-
-    void SetFileImpls(const nsTArray<nsRefPtr<File>>& aFile) {
-      mFileImpls.Clear();
+    const nsTArray<nsRefPtr<BlobImpl>>& GetBlobImpls()
+    {
+      return mBlobImpls;
+    }
+
+    void SetBlobImpls(const nsTArray<nsRefPtr<File>>& aFile)
+    {
+      mBlobImpls.Clear();
       for (uint32_t i = 0, len = aFile.Length(); i < len; ++i) {
-        mFileImpls.AppendElement(aFile[i]->Impl());
+        mBlobImpls.AppendElement(aFile[i]->Impl());
       }
     }
 
     HTMLInputElementState()
       : mValue()
       , mChecked(false)
       , mCheckedSet(false)
-    {};
+    {}
 
   protected:
     ~HTMLInputElementState() {}
 
     nsString mValue;
-    nsTArray<nsRefPtr<FileImpl>> mFileImpls;
+    nsTArray<nsRefPtr<BlobImpl>> mBlobImpls;
     bool mChecked;
     bool mCheckedSet;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(HTMLInputElementState, NS_INPUT_ELEMENT_STATE_IID)
 
 NS_IMPL_ISUPPORTS(HTMLInputElementState, HTMLInputElementState)
 
@@ -389,19 +396,19 @@ public:
     NS_ConvertUTF8toUTF16 path(relDescriptor);
     nsAutoString leafName;
     mNextFile->GetLeafName(leafName);
     MOZ_ASSERT(leafName.Length() <= path.Length());
     int32_t length = path.Length() - leafName.Length();
     MOZ_ASSERT(length >= 0);
     if (length > 0) {
       // Note that we leave the trailing "/" on the path.
-      FileImplFile* fileImpl = static_cast<FileImplFile*>(domFile->Impl());
-      MOZ_ASSERT(fileImpl);
-      fileImpl->SetPath(Substring(path, 0, uint32_t(length)));
+      BlobImplFile* blobImpl = static_cast<BlobImplFile*>(domFile->Impl());
+      MOZ_ASSERT(blobImpl);
+      blobImpl->SetPath(Substring(path, 0, uint32_t(length)));
     }
     *aResult = domFile.forget().downcast<nsIDOMFile>().take();
     LookupAndCacheNext();
     return NS_OK;
   }
 
   NS_IMETHOD
   HasMoreElements(bool* aResult) override
@@ -556,17 +563,18 @@ public:
     if (mCanceled) { // The last progress event may have canceled us
       return NS_OK;
     }
 
     // Recreate File with the correct parent object.
     nsCOMPtr<nsIGlobalObject> global = mInput->OwnerDoc()->GetScopeObject();
     for (uint32_t i = 0; i < mFileList.Length(); ++i) {
       MOZ_ASSERT(!mFileList[i]->GetParentObject());
-      mFileList[i] = new File(global, mFileList[i]->Impl());
+      mFileList[i] = File::Create(global, mFileList[i]->Impl());
+      MOZ_ASSERT(mFileList[i]);
     }
 
     // The text control frame (if there is one) isn't going to send a change
     // event because it will think this is done by a script.
     // So, we can safely send one by ourself.
     mInput->SetFiles(mFileList, true);
     nsresult rv =
       nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
@@ -2342,17 +2350,20 @@ HTMLInputElement::MozSetFileArray(const 
 {
   nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
   MOZ_ASSERT(global);
   if (!global) {
     return;
   }
   nsTArray<nsRefPtr<File>> files;
   for (uint32_t i = 0; i < aFiles.Length(); ++i) {
-    files.AppendElement(new File(global, aFiles[i].get()->Impl()));
+    nsRefPtr<File> file = File::Create(global, aFiles[i].get()->Impl());
+    MOZ_ASSERT(file);
+
+    files.AppendElement(file);
   }
   SetFiles(files, true);
 }
 
 void
 HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv)
 {
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
@@ -5800,17 +5811,17 @@ HTMLInputElement::SaveState()
       if (mCheckedChanged) {
         inputState = new HTMLInputElementState();
         inputState->SetChecked(mChecked);
       }
       break;
     case VALUE_MODE_FILENAME:
       if (!mFiles.IsEmpty()) {
         inputState = new HTMLInputElementState();
-        inputState->SetFileImpls(mFiles);
+        inputState->SetBlobImpls(mFiles);
       }
       break;
     case VALUE_MODE_VALUE:
     case VALUE_MODE_DEFAULT:
       // VALUE_MODE_DEFAULT shouldn't have their value saved except 'hidden',
       // mType shouldn't be NS_FORM_INPUT_PASSWORD and value should have changed.
       if ((GetValueMode() == VALUE_MODE_DEFAULT &&
            mType != NS_FORM_INPUT_HIDDEN) ||
@@ -6006,24 +6017,26 @@ HTMLInputElement::RestoreState(nsPresSta
       case VALUE_MODE_DEFAULT_ON:
         if (inputState->IsCheckedSet()) {
           restoredCheckedState = true;
           DoSetChecked(inputState->GetChecked(), true, true);
         }
         break;
       case VALUE_MODE_FILENAME:
         {
-          const nsTArray<nsRefPtr<FileImpl>>& fileImpls = inputState->GetFileImpls();
+          const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = inputState->GetBlobImpls();
 
           nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
           MOZ_ASSERT(global);
 
           nsTArray<nsRefPtr<File>> files;
-          for (uint32_t i = 0, len = fileImpls.Length(); i < len; ++i) {
-            nsRefPtr<File> file = new File(global, fileImpls[i]);
+          for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
+            nsRefPtr<File> file = File::Create(global, blobImpls[i]);
+            MOZ_ASSERT(file);
+
             files.AppendElement(file);
           }
 
           SetFiles(files, true);
         }
         break;
       case VALUE_MODE_VALUE:
       case VALUE_MODE_DEFAULT:
--- a/dom/html/nsFormSubmission.cpp
+++ b/dom/html/nsFormSubmission.cpp
@@ -72,28 +72,29 @@ public:
     : nsEncodingFormSubmission(aCharset, aOriginatingElement),
       mMethod(aMethod),
       mDocument(aDocument),
       mWarnedFileControl(false)
   {
   }
 
   virtual nsresult AddNameValuePair(const nsAString& aName,
-                                    const nsAString& aValue);
+                                    const nsAString& aValue) override;
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   File* aBlob);
+                                   File* aFile) override;
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
-                                        nsIInputStream** aPostDataStream);
+                                        nsIInputStream** aPostDataStream)
+                                                                       override;
 
-  virtual bool SupportsIsindexSubmission()
+  virtual bool SupportsIsindexSubmission() override
   {
     return true;
   }
 
-  virtual nsresult AddIsindex(const nsAString& aValue);
+  virtual nsresult AddIsindex(const nsAString& aValue) override;
 
 protected:
 
   /**
    * URL encode a Unicode string by encoding it to bytes, converting linebreaks
    * properly, and then escaping many bytes as %xx.
    *
    * @param aStr the string to encode
@@ -160,26 +161,26 @@ nsFSURLEncoded::AddIsindex(const nsAStri
     mQueryString += NS_LITERAL_CSTRING("&isindex=") + convValue;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsFSURLEncoded::AddNameFilePair(const nsAString& aName,
-                                File* aBlob)
+                                File* aFile)
 {
   if (!mWarnedFileControl) {
     SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nullptr, 0);
     mWarnedFileControl = true;
   }
 
   nsAutoString filename;
-  if (aBlob && aBlob->IsFile()) {
-    aBlob->GetName(filename);
+  if (aFile) {
+    aFile->GetName(filename);
   }
 
   return AddNameValuePair(aName, filename);
 }
 
 static void
 HandleMailtoSubject(nsCString& aPath) {
 
@@ -434,62 +435,59 @@ nsFSMultipartFormData::AddNameValuePair(
                  + nameStr + NS_LITERAL_CSTRING("\"" CRLF CRLF)
                  + valueStr + NS_LITERAL_CSTRING(CRLF);
 
   return NS_OK;
 }
 
 nsresult
 nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
-                                       File* aBlob)
+                                       File* aFile)
 {
   // Encode the control name
   nsAutoCString nameStr;
   nsresult rv = EncodeVal(aName, nameStr, true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCString filename, contentType;
   nsCOMPtr<nsIInputStream> fileStream;
-  if (aBlob) {
-    // Since Bug 1127150, any Blob received from FormData must be a File
-    // instance with a valid name (possibly "blob").
-    MOZ_ASSERT(aBlob->IsFile());
+  if (aFile) {
     nsAutoString filename16;
-    rv = aBlob->GetName(filename16);
+    rv = aFile->GetName(filename16);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsAutoString filepath16;
-    rv = aBlob->GetPath(filepath16);
+    rv = aFile->GetPath(filepath16);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     if (!filepath16.IsEmpty()) {
       // File.path includes trailing "/"
       filename16 = filepath16 + filename16;
     }
 
     rv = EncodeVal(filename16, filename, true);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Get content type
     nsAutoString contentType16;
-    rv = aBlob->GetType(contentType16);
+    rv = aFile->GetType(contentType16);
     if (NS_FAILED(rv) || contentType16.IsEmpty()) {
       contentType16.AssignLiteral("application/octet-stream");
     }
     contentType.Adopt(nsLinebreakConverter::
                       ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(),
                                         nsLinebreakConverter::eLinebreakAny,
                                         nsLinebreakConverter::eLinebreakSpace));
 
     // Get input stream
-    rv = aBlob->GetInternalStream(getter_AddRefs(fileStream));
+    rv = aFile->GetInternalStream(getter_AddRefs(fileStream));
     NS_ENSURE_SUCCESS(rv, rv);
     if (fileStream) {
       // Create buffered stream (for efficiency)
       nsCOMPtr<nsIInputStream> bufferedStream;
       rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
                                      fileStream, 8192);
       NS_ENSURE_SUCCESS(rv, rv);
 
@@ -514,17 +512,17 @@ nsFSMultipartFormData::AddNameFilePair(c
        + nameStr + NS_LITERAL_CSTRING("\"; filename=\"")
        + filename + NS_LITERAL_CSTRING("\"" CRLF)
        + NS_LITERAL_CSTRING("Content-Type: ")
        + contentType + NS_LITERAL_CSTRING(CRLF CRLF);
 
   // We should not try to append an invalid stream. That will happen for example
   // if we try to update a file that actually do not exist.
   uint64_t size;
-  if (fileStream && NS_SUCCEEDED(aBlob->GetSize(&size))) {
+  if (fileStream && NS_SUCCEEDED(aFile->GetSize(&size))) {
     // We need to dump the data up to this point into the POST data stream here,
     // since we're about to add the file input stream
     AddPostDataStream();
 
     mPostDataStream->AppendStream(fileStream);
     mTotalLength += size;
   }
 
@@ -582,21 +580,22 @@ class nsFSTextPlain : public nsEncodingF
 {
 public:
   nsFSTextPlain(const nsACString& aCharset, nsIContent* aOriginatingElement)
     : nsEncodingFormSubmission(aCharset, aOriginatingElement)
   {
   }
 
   virtual nsresult AddNameValuePair(const nsAString& aName,
-                                    const nsAString& aValue);
+                                    const nsAString& aValue) override;
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   File* aBlob);
+                                   File* aFile) override;
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
-                                        nsIInputStream** aPostDataStream);
+                                        nsIInputStream** aPostDataStream)
+                                                                       override;
 
 private:
   nsString mBody;
 };
 
 nsresult
 nsFSTextPlain::AddNameValuePair(const nsAString& aName,
                                 const nsAString& aValue)
@@ -607,21 +606,21 @@ nsFSTextPlain::AddNameValuePair(const ns
   mBody.Append(aName + NS_LITERAL_STRING("=") + aValue +
                NS_LITERAL_STRING(CRLF));
 
   return NS_OK;
 }
 
 nsresult
 nsFSTextPlain::AddNameFilePair(const nsAString& aName,
-                               File* aBlob)
+                               File* aFile)
 {
   nsAutoString filename;
-  if (aBlob && aBlob->IsFile()) {
-    aBlob->GetName(filename);
+  if (aFile) {
+    aFile->GetName(filename);
   }
 
   AddNameValuePair(aName, filename);
   return NS_OK;
 }
 
 nsresult
 nsFSTextPlain::GetEncodedSubmission(nsIURI* aURI,
--- a/dom/html/nsFormSubmission.h
+++ b/dom/html/nsFormSubmission.h
@@ -43,20 +43,20 @@ public:
    */
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) = 0;
 
   /**
    * Submit a name/file pair
    *
    * @param aName the name of the parameter
-   * @param aBlob the file to submit. The file's name will be used
+   * @param aFile the file to submit. The file's name will be used
    */
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   mozilla::dom::File* aBlob) = 0;
+                                   mozilla::dom::File* aFile) = 0;
 
   /**
    * Reports whether the instance supports AddIsindex().
    *
    * @return true if supported.
    */
   virtual bool SupportsIsindexSubmission()
   {
@@ -155,17 +155,17 @@ public:
    */
   nsFSMultipartFormData(const nsACString& aCharset,
                         nsIContent* aOriginatingElement);
   ~nsFSMultipartFormData();
  
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) override;
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   mozilla::dom::File* aBlob) override;
+                                   mozilla::dom::File* aFile) override;
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream) override;
 
   void GetContentType(nsACString& aContentType)
   {
     aContentType =
       NS_LITERAL_CSTRING("multipart/form-data; boundary=") + mBoundary;
   }
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -606,37 +606,37 @@ ConvertActorsToBlobs(IDBDatabase* aDatab
 
   if (!blobs.IsEmpty()) {
     const uint32_t count = blobs.Length();
     aFiles.SetCapacity(count);
 
     for (uint32_t index = 0; index < count; index++) {
       BlobChild* actor = static_cast<BlobChild*>(blobs[index]);
 
-      nsRefPtr<FileImpl> blobImpl = actor->GetBlobImpl();
+      nsRefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
       MOZ_ASSERT(blobImpl);
 
-      nsRefPtr<File> blob = new File(aDatabase->GetOwner(), blobImpl);
+      nsRefPtr<Blob> blob = Blob::Create(aDatabase->GetOwner(), blobImpl);
 
       nsRefPtr<FileInfo> fileInfo;
       if (!fileInfos.IsEmpty()) {
         fileInfo = dont_AddRef(reinterpret_cast<FileInfo*>(fileInfos[index]));
 
         MOZ_ASSERT(fileInfo);
         MOZ_ASSERT(fileInfo->Id() > 0);
 
         blob->AddFileInfo(fileInfo);
       }
 
       aDatabase->NoteReceivedBlob(blob);
 
       StructuredCloneFile* file = aFiles.AppendElement();
       MOZ_ASSERT(file);
 
-      file->mFile.swap(blob);
+      file->mBlob.swap(blob);
       file->mFileInfo.swap(fileInfo);
     }
   }
 }
 
 void
 DispatchErrorEvent(IDBRequest* aRequest,
                    nsresult aErrorCode,
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -5833,17 +5833,17 @@ private:
   Cleanup() override;
 };
 
 class DatabaseFile final
   : public PBackgroundIDBDatabaseFileParent
 {
   friend class Database;
 
-  nsRefPtr<FileImpl> mBlobImpl;
+  nsRefPtr<BlobImpl> mBlobImpl;
   nsRefPtr<FileInfo> mFileInfo;
 
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::indexedDB::DatabaseFile);
 
   FileInfo*
   GetFileInfo() const
   {
@@ -5879,17 +5879,17 @@ private:
   explicit DatabaseFile(FileInfo* aFileInfo)
     : mFileInfo(aFileInfo)
   {
     AssertIsOnBackgroundThread();
     MOZ_ASSERT(aFileInfo);
   }
 
   // Called when receiving from the child.
-  DatabaseFile(FileImpl* aBlobImpl, FileInfo* aFileInfo)
+  DatabaseFile(BlobImpl* aBlobImpl, FileInfo* aFileInfo)
     : mBlobImpl(aBlobImpl)
     , mFileInfo(aFileInfo)
   {
     AssertIsOnBackgroundThread();
     MOZ_ASSERT(aBlobImpl);
     MOZ_ASSERT(aFileInfo);
   }
 
@@ -7693,36 +7693,37 @@ public:
 
   NS_INLINE_DECL_REFCOUNTING(DatabaseLoggingInfo)
 
 private:
   ~DatabaseLoggingInfo();
 };
 
 class NonMainThreadHackBlobImpl final
-  : public FileImplFile
+  : public BlobImplFile
 {
 public:
   NonMainThreadHackBlobImpl(nsIFile* aFile, FileInfo* aFileInfo)
-    : FileImplFile(aFile, aFileInfo)
+    : BlobImplFile(aFile, aFileInfo)
   {
     // Getting the content type is not currently supported off the main thread.
     // This isn't a problem here because:
     //
     //   1. The real content type is stored in the structured clone data and
     //      that's all that the DOM will see. This blob's data will be updated
     //      during RecvSetMysteryBlobInfo().
     //   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
@@ -8151,17 +8152,17 @@ ConvertBlobsToActors(PBackgroundParent* 
 
     MOZ_ASSERT(NS_SUCCEEDED(nativeFile->Exists(&exists)));
     MOZ_ASSERT(exists);
 
     DebugOnly<bool> isFile;
     MOZ_ASSERT(NS_SUCCEEDED(nativeFile->IsFile(&isFile)));
     MOZ_ASSERT(isFile);
 
-    nsRefPtr<FileImpl> impl =
+    nsRefPtr<BlobImpl> impl =
       new NonMainThreadHackBlobImpl(nativeFile, file.mFileInfo);
 
     PBlobParent* actor =
       BackgroundParent::GetOrCreateActorForBlobImpl(aBackgroundActor, impl);
     if (!actor) {
       // This can only fail if the child has crashed.
       IDB_REPORT_INTERNAL_ERR();
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@@ -11835,17 +11836,17 @@ Database::ActorDestroy(ActorDestroyReaso
 }
 
 PBackgroundIDBDatabaseFileParent*
 Database::AllocPBackgroundIDBDatabaseFileParent(PBlobParent* aBlobParent)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aBlobParent);
 
-  nsRefPtr<FileImpl> blobImpl =
+  nsRefPtr<BlobImpl> blobImpl =
     static_cast<BlobParent*>(aBlobParent)->GetBlobImpl();
   MOZ_ASSERT(blobImpl);
 
   nsRefPtr<DatabaseFile> actor;
 
   if (nsRefPtr<FileInfo> fileInfo = blobImpl->GetFileInfo(mFileManager)) {
     // This blob was previously shared with the child.
     actor = new DatabaseFile(fileInfo);
--- a/dom/indexedDB/FileSnapshot.cpp
+++ b/dom/indexedDB/FileSnapshot.cpp
@@ -15,23 +15,23 @@
 #include "nsXULAppAPI.h"
 #endif
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 // Create as a stored file
-FileImplSnapshot::FileImplSnapshot(const nsAString& aName,
+BlobImplSnapshot::BlobImplSnapshot(const nsAString& aName,
                                    const nsAString& aContentType,
                                    MetadataParameters* aMetadataParams,
                                    nsIFile* aFile,
                                    IDBFileHandle* aFileHandle,
                                    FileInfo* aFileInfo)
-  : FileImplBase(aName,
+  : BlobImplBase(aName,
                  aContentType,
                  aMetadataParams->Size(),
                  aMetadataParams->LastModified())
   , mFile(aFile)
   , mWholeFile(true)
 {
   AssertSanity();
   MOZ_ASSERT(aMetadataParams);
@@ -43,21 +43,21 @@ FileImplSnapshot::FileImplSnapshot(const
 
   mFileInfos.AppendElement(aFileInfo);
 
   mFileHandle =
     do_GetWeakReference(NS_ISUPPORTS_CAST(EventTarget*, aFileHandle));
 }
 
 // Create slice
-FileImplSnapshot::FileImplSnapshot(const FileImplSnapshot* aOther,
+BlobImplSnapshot::BlobImplSnapshot(const BlobImplSnapshot* aOther,
                                    uint64_t aStart,
                                    uint64_t aLength,
                                    const nsAString& aContentType)
-  : FileImplBase(aContentType, aOther->mStart + aStart, aLength)
+  : BlobImplBase(aContentType, aOther->mStart + aStart, aLength)
   , mFile(aOther->mFile)
   , mFileHandle(aOther->mFileHandle)
   , mWholeFile(false)
 {
   AssertSanity();
   MOZ_ASSERT(aOther);
 
   FileInfo* fileInfo;
@@ -67,36 +67,36 @@ FileImplSnapshot::FileImplSnapshot(const
   } else {
     MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
     fileInfo = aOther->GetFileInfo();
   }
 
   mFileInfos.AppendElement(fileInfo);
 }
 
-FileImplSnapshot::~FileImplSnapshot()
+BlobImplSnapshot::~BlobImplSnapshot()
 {
 }
 
 #ifdef DEBUG
 
 // static
 void
-FileImplSnapshot::AssertSanity()
+BlobImplSnapshot::AssertSanity()
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 #endif // DEBUG
 
-NS_IMPL_ISUPPORTS_INHERITED(FileImplSnapshot, FileImpl, PIFileImplSnapshot)
+NS_IMPL_ISUPPORTS_INHERITED(BlobImplSnapshot, BlobImpl, PIBlobImplSnapshot)
 
 nsresult
-FileImplSnapshot::GetInternalStream(nsIInputStream** aStream)
+BlobImplSnapshot::GetInternalStream(nsIInputStream** aStream)
 {
   AssertSanity();
 
   nsCOMPtr<EventTarget> et = do_QueryReferent(mFileHandle);
   nsRefPtr<IDBFileHandle> fileHandle = static_cast<IDBFileHandle*>(et.get());
   if (!fileHandle) {
     return NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR;
   }
@@ -105,58 +105,58 @@ FileImplSnapshot::GetInternalStream(nsII
                                             aStream);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   return NS_OK;
 }
 
-already_AddRefed<FileImpl>
-FileImplSnapshot::CreateSlice(uint64_t aStart,
+already_AddRefed<BlobImpl>
+BlobImplSnapshot::CreateSlice(uint64_t aStart,
                               uint64_t aLength,
                               const nsAString& aContentType,
                               ErrorResult& aRv)
 {
   AssertSanity();
 
-  nsRefPtr<FileImpl> impl =
-    new FileImplSnapshot(this, aStart, aLength, aContentType);
+  nsRefPtr<BlobImpl> impl =
+    new BlobImplSnapshot(this, aStart, aLength, aContentType);
 
   return impl.forget();
 }
 
 void
-FileImplSnapshot::GetMozFullPathInternal(nsAString& aFilename,
+BlobImplSnapshot::GetMozFullPathInternal(nsAString& aFilename,
                                          ErrorResult& aRv)
 {
   AssertSanity();
   MOZ_ASSERT(mIsFile);
 
   aRv = mFile->GetPath(aFilename);
 }
 
 bool
-FileImplSnapshot::IsStoredFile() const
+BlobImplSnapshot::IsStoredFile() const
 {
   AssertSanity();
 
   return true;
 }
 
 bool
-FileImplSnapshot::IsWholeFile() const
+BlobImplSnapshot::IsWholeFile() const
 {
   AssertSanity();
 
   return mWholeFile;
 }
 
 bool
-FileImplSnapshot::IsSnapshot() const
+BlobImplSnapshot::IsSnapshot() const
 {
   AssertSanity();
 
   return true;
 }
 
 } // namespace indexedDB
 } // namespace dom
--- a/dom/indexedDB/FileSnapshot.h
+++ b/dom/indexedDB/FileSnapshot.h
@@ -12,63 +12,63 @@
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsISupports.h"
 #include "nsWeakPtr.h"
 
 #define FILEIMPLSNAPSHOT_IID \
   {0x0dfc11b1, 0x75d3, 0x473b, {0x8c, 0x67, 0xb7, 0x23, 0xf4, 0x67, 0xd6, 0x73}}
 
-class PIFileImplSnapshot : public nsISupports
+class PIBlobImplSnapshot : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(FILEIMPLSNAPSHOT_IID)
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(PIFileImplSnapshot, FILEIMPLSNAPSHOT_IID)
+NS_DEFINE_STATIC_IID_ACCESSOR(PIBlobImplSnapshot, FILEIMPLSNAPSHOT_IID)
 
 namespace mozilla {
 namespace dom {
 
 class MetadataParameters;
 
 namespace indexedDB {
 
 class IDBFileHandle;
 
-class FileImplSnapshot final
-  : public FileImplBase
-  , public PIFileImplSnapshot
+class BlobImplSnapshot final
+  : public BlobImplBase
+  , public PIBlobImplSnapshot
 {
   typedef mozilla::dom::MetadataParameters MetadataParameters;
 
   nsCOMPtr<nsIFile> mFile;
   nsWeakPtr mFileHandle;
 
   bool mWholeFile;
 
 public:
   // Create as a stored file
-  FileImplSnapshot(const nsAString& aName,
+  BlobImplSnapshot(const nsAString& aName,
                    const nsAString& aContentType,
                    MetadataParameters* aMetadataParams,
                    nsIFile* aFile,
                    IDBFileHandle* aFileHandle,
                    FileInfo* aFileInfo);
 
   NS_DECL_ISUPPORTS_INHERITED
 
 private:
   // Create slice
-  FileImplSnapshot(const FileImplSnapshot* aOther,
+  BlobImplSnapshot(const BlobImplSnapshot* aOther,
                    uint64_t aStart,
                    uint64_t aLength,
                    const nsAString& aContentType);
 
-  ~FileImplSnapshot();
+  ~BlobImplSnapshot();
 
   static void
   AssertSanity()
 #ifdef DEBUG
   ;
 #else
   { }
 #endif
@@ -79,17 +79,17 @@ private:
   virtual nsresult
   GetInternalStream(nsIInputStream** aStream) override;
 
   virtual bool MayBeClonedToOtherThreads() const override
   {
     return false;
   }
 
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t aStart,
               uint64_t aLength,
               const nsAString& aContentType,
               ErrorResult& aRv) override;
 
   virtual bool
   IsStoredFile() const override;
 
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -954,34 +954,34 @@ IDBDatabase::AbortTransactions(bool aSho
       transaction->GetCallerLocation(filename, &lineNo);
 
       LogWarning(kWarningMessage, filename, lineNo);
     }
   }
 }
 
 PBackgroundIDBDatabaseFileChild*
-IDBDatabase::GetOrCreateFileActorForBlob(File* aBlob)
+IDBDatabase::GetOrCreateFileActorForBlob(Blob* aBlob)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aBlob);
   MOZ_ASSERT(mBackgroundActor);
 
   // We use the File's nsIWeakReference as the key to the table because
   // a) it is unique per blob, b) it is reference-counted so that we can
   // guarantee that it stays alive, and c) it doesn't hold the actual File
   // alive.
   nsCOMPtr<nsIDOMBlob> blob = aBlob;
   nsCOMPtr<nsIWeakReference> weakRef = do_GetWeakReference(blob);
   MOZ_ASSERT(weakRef);
 
   PBackgroundIDBDatabaseFileChild* actor = nullptr;
 
   if (!mFileActors.Get(weakRef, &actor)) {
-    FileImpl* blobImpl = aBlob->Impl();
+    BlobImpl* blobImpl = aBlob->Impl();
     MOZ_ASSERT(blobImpl);
 
     if (mReceivedBlobs.GetEntry(weakRef)) {
       // This blob was previously retrieved from the database.
       nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(blobImpl);
       MOZ_ASSERT(remoteBlob);
 
       BlobChild* blobChild = remoteBlob->GetBlobChild();
@@ -1063,25 +1063,25 @@ IDBDatabase::NoteFinishedFileActor(PBack
       return PL_DHASH_NEXT;
     }
   };
 
   mFileActors.Enumerate(&Helper::Remove, aFileActor);
 }
 
 void
-IDBDatabase::NoteReceivedBlob(File* aBlob)
+IDBDatabase::NoteReceivedBlob(Blob* aBlob)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aBlob);
   MOZ_ASSERT(mBackgroundActor);
 
 #ifdef DEBUG
   {
-    nsRefPtr<FileImpl> blobImpl = aBlob->Impl();
+    nsRefPtr<BlobImpl> blobImpl = aBlob->Impl();
     MOZ_ASSERT(blobImpl);
 
     nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(blobImpl);
     MOZ_ASSERT(remoteBlob);
 
     BlobChild* blobChild = remoteBlob->GetBlobChild();
     MOZ_ASSERT(blobChild);
 
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -23,17 +23,17 @@ class nsPIDOMWindow;
 
 namespace mozilla {
 
 class ErrorResult;
 class EventChainPostVisitor;
 
 namespace dom {
 
-class File;
+class Blob;
 class DOMStringList;
 struct IDBObjectStoreParameters;
 template <class> class Optional;
 class StringOrStringSequence;
 
 namespace indexedDB {
 
 class BackgroundDatabaseChild;
@@ -172,23 +172,23 @@ public:
 
   void
   UnregisterTransaction(IDBTransaction* aTransaction);
 
   void
   AbortTransactions(bool aShouldWarn);
 
   PBackgroundIDBDatabaseFileChild*
-  GetOrCreateFileActorForBlob(File* aBlob);
+  GetOrCreateFileActorForBlob(Blob* aBlob);
 
   void
   NoteFinishedFileActor(PBackgroundIDBDatabaseFileChild* aFileActor);
 
   void
-  NoteReceivedBlob(File* aBlob);
+  NoteReceivedBlob(Blob* aBlob);
 
   void
   DelayedMaybeExpireFileActors();
 
   // XXX This doesn't really belong here... It's only needed for IDBMutableFile
   //     serialization and should be removed someday.
   nsresult
   GetQuotaInfo(nsACString& aOrigin, PersistenceType* aPersistenceType);
--- a/dom/indexedDB/IDBMutableFile.cpp
+++ b/dom/indexedDB/IDBMutableFile.cpp
@@ -327,26 +327,28 @@ IDBMutableFile::GetFileId() const
 
   return mFileInfo->Id();
 }
 
 already_AddRefed<nsIDOMFile>
 IDBMutableFile::CreateFileObject(IDBFileHandle* aFileHandle,
                                  MetadataParameters* aMetadataParams)
 {
-  nsRefPtr<FileImpl> impl =
-    new FileImplSnapshot(mName,
+  nsRefPtr<BlobImpl> impl =
+    new BlobImplSnapshot(mName,
                          mType,
                          aMetadataParams,
                          mFile,
                          aFileHandle,
                          mFileInfo);
 
-  nsCOMPtr<nsIDOMFile> fileSnapshot = new File(GetOwner(), impl);
-  return fileSnapshot.forget();
+  nsRefPtr<File> file = File::Create(GetOwner(), impl);
+  MOZ_ASSERT(file);
+
+  return file.forget();
 }
 
 already_AddRefed<DOMRequest>
 IDBMutableFile::GetFile(ErrorResult& aError)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (QuotaManager::IsShuttingDown() || FileService::IsShuttingDown()) {
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -57,17 +57,17 @@ namespace indexedDB {
 using namespace mozilla::dom::quota;
 using namespace mozilla::dom::workers;
 using namespace mozilla::ipc;
 
 struct IDBObjectStore::StructuredCloneWriteInfo
 {
   struct BlobOrFileInfo
   {
-    nsRefPtr<File> mBlob;
+    nsRefPtr<Blob> mBlob;
     nsRefPtr<FileInfo> mFileInfo;
 
     bool
     operator==(const BlobOrFileInfo& aOther) const
     {
       return this->mBlob == aOther.mBlob && this->mFileInfo == aOther.mFileInfo;
     }
   };
@@ -295,17 +295,17 @@ StructuredCloneWriteCallback(JSContext* 
       newBlobOrFileInfo =
         cloneWriteInfo->mBlobOrFileInfos.AppendElement();
     newBlobOrFileInfo->mFileInfo.swap(fileInfo);
 
     return true;
   }
 
   {
-    File* blob = nullptr;
+    Blob* blob = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
       uint64_t size;
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetSize(&size)));
 
       size = NativeEndian::swapToLittleEndian(size);
 
       nsString type;
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetType(type)));
@@ -327,25 +327,26 @@ StructuredCloneWriteCallback(JSContext* 
                               blob->IsFile() ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
                               index) ||
           !JS_WriteBytes(aWriter, &size, sizeof(size)) ||
           !JS_WriteBytes(aWriter, &convTypeLength, sizeof(convTypeLength)) ||
           !JS_WriteBytes(aWriter, convType.get(), convType.Length())) {
         return false;
       }
 
-      if (blob->IsFile()) {
+      nsRefPtr<File> file = blob->ToFile();
+      if (file) {
         int64_t lastModifiedDate;
         MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
-          blob->GetMozLastModifiedDate(&lastModifiedDate)));
+          file->GetMozLastModifiedDate(&lastModifiedDate)));
 
         lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate);
 
         nsString name;
-        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetName(name)));
+        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(file->GetName(name)));
 
         NS_ConvertUTF16toUTF8 convName(name);
         uint32_t convNameLength =
           NativeEndian::swapToLittleEndian(convName.Length());
 
         if (!JS_WriteBytes(aWriter, &lastModifiedDate, sizeof(lastModifiedDate)) || 
             !JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
             !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
@@ -397,21 +398,21 @@ GetAddInfoCallback(JSContext* aCx, void*
                                                 &data->mCloneWriteInfo)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   return NS_OK;
 }
 
 BlobChild*
-ActorFromRemoteBlob(File* aBlob)
+ActorFromRemoteBlobImpl(BlobImpl* aImpl)
 {
-  MOZ_ASSERT(aBlob);
+  MOZ_ASSERT(aImpl);
 
-  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob->Impl());
+  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aImpl);
   if (remoteBlob) {
     BlobChild* actor = remoteBlob->GetBlobChild();
     MOZ_ASSERT(actor);
 
     if (actor->GetContentManager()) {
       return nullptr;
     }
 
@@ -423,36 +424,36 @@ ActorFromRemoteBlob(File* aBlob)
 
     return actor;
   }
 
   return nullptr;
 }
 
 bool
-ResolveMysteryFile(File* aBlob,
+ResolveMysteryFile(BlobImpl* aImpl,
                    const nsString& aName,
                    const nsString& aContentType,
                    uint64_t aSize,
                    uint64_t aLastModifiedDate)
 {
-  BlobChild* actor = ActorFromRemoteBlob(aBlob);
+  BlobChild* actor = ActorFromRemoteBlobImpl(aImpl);
   if (actor) {
     return actor->SetMysteryBlobInfo(aName, aContentType,
                                      aSize, aLastModifiedDate);
   }
   return true;
 }
 
 bool
-ResolveMysteryBlob(File* aBlob,
+ResolveMysteryBlob(BlobImpl* aImpl,
                    const nsString& aContentType,
                    uint64_t aSize)
 {
-  BlobChild* actor = ActorFromRemoteBlob(aBlob);
+  BlobChild* actor = ActorFromRemoteBlobImpl(aImpl);
   if (actor) {
     return actor->SetMysteryBlobInfo(aContentType, aSize);
   }
   return true;
 }
 
 bool
 StructuredCloneReadString(JSStructuredCloneReader* aReader,
@@ -600,17 +601,17 @@ public:
                           IDBDatabase* aDatabase,
                           StructuredCloneFile& aFile,
                           const BlobOrFileData& aData,
                           JS::MutableHandle<JSObject*> aResult)
   {
     MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
                aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
                aData.tag == SCTAG_DOM_BLOB);
-    MOZ_ASSERT(aFile.mFile);
+    MOZ_ASSERT(aFile.mBlob);
 
     // It can happen that this IDB is chrome code, so there is no parent, but
     // still we want to set a correct parent for the new File object.
     nsCOMPtr<nsISupports> parent;
     if (NS_IsMainThread()) {
       if (aDatabase && aDatabase->GetParentObject()) {
         parent = aDatabase->GetParentObject();
       } else {
@@ -622,46 +623,49 @@ public:
 
       WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
       MOZ_ASSERT(globalScope);
 
       parent = do_QueryObject(globalScope);
     }
 
     MOZ_ASSERT(parent);
-    nsRefPtr<File> file = new File(parent, aFile.mFile->Impl());
 
     if (aData.tag == SCTAG_DOM_BLOB) {
-      if (NS_WARN_IF(!ResolveMysteryBlob(aFile.mFile,
+      if (NS_WARN_IF(!ResolveMysteryBlob(aFile.mBlob->Impl(),
                                          aData.type,
                                          aData.size))) {
         return false;
       }
 
+      MOZ_ASSERT(!aFile.mBlob->IsFile());
+
       JS::Rooted<JS::Value> wrappedBlob(aCx);
-      if (!GetOrCreateDOMReflector(aCx, aFile.mFile, &wrappedBlob)) {
+      if (!ToJSValue(aCx, aFile.mBlob, &wrappedBlob)) {
         return false;
       }
 
       aResult.set(&wrappedBlob.toObject());
       return true;
     }
 
-    MOZ_ASSERT(aFile.mFile->IsFile());
-
-    if (NS_WARN_IF(!ResolveMysteryFile(aFile.mFile,
+    if (NS_WARN_IF(!ResolveMysteryFile(aFile.mBlob->Impl(),
                                        aData.name,
                                        aData.type,
                                        aData.size,
                                        aData.lastModifiedDate))) {
       return false;
     }
 
+    MOZ_ASSERT(aFile.mBlob->IsFile());
+    nsRefPtr<File> file = aFile.mBlob->ToFile();
+    MOZ_ASSERT(file);
+
     JS::Rooted<JS::Value> wrappedFile(aCx);
-    if (!GetOrCreateDOMReflector(aCx, aFile.mFile, &wrappedFile)) {
+    if (!ToJSValue(aCx, file, &wrappedFile)) {
       return false;
     }
 
     aResult.set(&wrappedFile.toObject());
     return true;
   }
 };
 
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -10,27 +10,27 @@
 #include "js/StructuredClone.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 
-class File;
+class Blob;
 
 namespace indexedDB {
 
 class FileInfo;
 class IDBDatabase;
 class SerializedStructuredCloneReadInfo;
 
 struct StructuredCloneFile
 {
-  nsRefPtr<File> mFile;
+  nsRefPtr<Blob> mBlob;
   nsRefPtr<FileInfo> mFileInfo;
 
   // In IndexedDatabaseInlines.h
   inline
   StructuredCloneFile();
 
   // In IndexedDatabaseInlines.h
   inline
--- a/dom/indexedDB/IndexedDatabaseInlines.h
+++ b/dom/indexedDB/IndexedDatabaseInlines.h
@@ -31,17 +31,17 @@ StructuredCloneFile::~StructuredCloneFil
 {
   MOZ_COUNT_DTOR(StructuredCloneFile);
 }
 
 inline
 bool
 StructuredCloneFile::operator==(const StructuredCloneFile& aOther) const
 {
-  return this->mFile == aOther.mFile &&
+  return this->mBlob == aOther.mBlob &&
          this->mFileInfo == aOther.mFileInfo;
 }
 
 inline
 StructuredCloneReadInfo::StructuredCloneReadInfo()
   : mDatabase(nullptr)
 {
   MOZ_COUNT_CTOR(StructuredCloneReadInfo);
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -183,17 +183,17 @@ private:
 
   static void
   LoggingModePrefChangedCallback(const char* aPrefName, void* aClosure);
 
   // Maintains a list of all file managers per origin. This list isn't
   // protected by any mutex but it is only ever touched on the IO thread.
   nsClassHashtable<nsCStringHashKey, FileManagerInfo> mFileManagerInfos;
 
-  // Lock protecting FileManager.mFileInfos and FileImplBase.mFileInfos
+  // Lock protecting FileManager.mFileInfos and BlobImplBase.mFileInfos
   // It's s also used to atomically update FileInfo.mRefCnt, FileInfo.mDBRefCnt
   // and FileInfo.mSliceRefCnt
   mozilla::Mutex mFileMutex;
 
   static bool sIsMainProcess;
   static bool sFullSynchronousMode;
   static PRLogModuleInfo* sLoggingModule;
   static Atomic<LoggingMode> sLoggingMode;
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -24,17 +24,17 @@
 #include "mozilla/dom/PBlobStreamChild.h"
 #include "mozilla/dom/PBlobStreamParent.h"
 #include "mozilla/dom/indexedDB/FileSnapshot.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/PBackgroundParent.h"
 #include "mozilla/ipc/PFileDescriptorSetParent.h"
-#include "MultipartFileImpl.h"
+#include "MultipartBlobImpl.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsID.h"
 #include "nsIInputStream.h"
 #include "nsIIPCSerializableInputStream.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsIRemoteBlob.h"
 #include "nsISeekableStream.h"
@@ -400,30 +400,30 @@ NS_DEFINE_STATIC_IID_ACCESSOR(IPrivateRe
 // This class exists to keep a blob alive at least as long as its internal
 // stream.
 class BlobInputStreamTether final
   : public nsIMultiplexInputStream
   , public nsISeekableStream
   , public nsIIPCSerializableInputStream
 {
   nsCOMPtr<nsIInputStream> mStream;
-  nsRefPtr<FileImpl> mBlobImpl;
+  nsRefPtr<BlobImpl> mBlobImpl;
 
   nsIMultiplexInputStream* mWeakMultiplexStream;
   nsISeekableStream* mWeakSeekableStream;
   nsIIPCSerializableInputStream* mWeakSerializableStream;
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_FORWARD_NSIINPUTSTREAM(mStream->)
   NS_FORWARD_SAFE_NSIMULTIPLEXINPUTSTREAM(mWeakMultiplexStream)
   NS_FORWARD_SAFE_NSISEEKABLESTREAM(mWeakSeekableStream)
   NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(mWeakSerializableStream)
 
-  BlobInputStreamTether(nsIInputStream* aStream, FileImpl* aBlobImpl)
+  BlobInputStreamTether(nsIInputStream* aStream, BlobImpl* aBlobImpl)
     : mStream(aStream)
     , mBlobImpl(aBlobImpl)
     , mWeakMultiplexStream(nullptr)
     , mWeakSeekableStream(nullptr)
     , mWeakSerializableStream(nullptr)
   {
     MOZ_ASSERT(aStream);
     MOZ_ASSERT(aBlobImpl);
@@ -471,29 +471,29 @@ class RemoteInputStream final
   : public nsIInputStream
   , public nsISeekableStream
   , public nsIIPCSerializableInputStream
   , public IPrivateRemoteInputStream
 {
   Monitor mMonitor;
   BlobChild* mActor;
   nsCOMPtr<nsIInputStream> mStream;
-  nsRefPtr<FileImpl> mBlobImpl;
+  nsRefPtr<BlobImpl> mBlobImpl;
   nsCOMPtr<nsIEventTarget> mEventTarget;
   nsISeekableStream* mWeakSeekableStream;
   uint64_t mStart;
   uint64_t mLength;
 
 public:
-  RemoteInputStream(FileImpl* aBlobImpl,
+  RemoteInputStream(BlobImpl* aBlobImpl,
                     uint64_t aStart,
                     uint64_t aLength);
 
   RemoteInputStream(BlobChild* aActor,
-                    FileImpl* aBlobImpl,
+                    BlobImpl* aBlobImpl,
                     uint64_t aStart,
                     uint64_t aLength);
 
   bool
   IsOnOwningThread() const
   {
     return EventTargetIsOnCurrentThread(mEventTarget);
   }
@@ -653,43 +653,43 @@ private:
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) override
   {
     // Nothing needs to be done here.
   }
 };
 
 class EmptyBlobImpl final
-  : public FileImplBase
+  : public BlobImplBase
 {
 public:
   explicit EmptyBlobImpl(const nsAString& aContentType)
-    : FileImplBase(aContentType, 0)
+    : BlobImplBase(aContentType, 0)
   {
     mImmutable = true;
   }
 
   EmptyBlobImpl(const nsAString& aName,
                 const nsAString& aContentType,
                 int64_t aLastModifiedDate)
-    : FileImplBase(aName, aContentType, 0, aLastModifiedDate)
+    : BlobImplBase(aName, aContentType, 0, aLastModifiedDate)
   {
     mImmutable = true;
   }
 
 private:
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t /* aStart */,
               uint64_t aLength,
               const nsAString& aContentType,
               ErrorResult& /* aRv */) override
   {
     MOZ_ASSERT(!aLength);
 
-    nsRefPtr<FileImpl> sliceImpl = new EmptyBlobImpl(aContentType);
+    nsRefPtr<BlobImpl> sliceImpl = new EmptyBlobImpl(aContentType);
 
     DebugOnly<bool> isMutable;
     MOZ_ASSERT(NS_SUCCEEDED(sliceImpl->GetMutable(&isMutable)));
     MOZ_ASSERT(!isMutable);
 
     return sliceImpl.forget();
   }
 
@@ -703,52 +703,52 @@ private:
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     return NS_OK;
   }
 };
 
-// This is only needed for IndexedDB FileImplSnapshot.
+// This is only needed for IndexedDB BlobImplSnapshot.
 class SameProcessInputStreamBlobImpl final
-  : public FileImplBase
+  : public BlobImplBase
 {
   nsCOMPtr<nsIInputStream> mInputStream;
 
 public:
   SameProcessInputStreamBlobImpl(const nsAString& aContentType,
                                  uint64_t aLength,
                                  nsIInputStream* aInputStream)
-    : FileImplBase(aContentType, aLength)
+    : BlobImplBase(aContentType, aLength)
     , mInputStream(aInputStream)
   {
     MOZ_ASSERT(aLength != UINT64_MAX);
     MOZ_ASSERT(aInputStream);
 
     mImmutable = true;
   }
 
   SameProcessInputStreamBlobImpl(const nsAString& aName,
                                  const nsAString& aContentType,
                                  uint64_t aLength,
                                  int64_t aLastModifiedDate,
                                  nsIInputStream* aInputStream)
-    : FileImplBase(aName, aContentType, aLength, aLastModifiedDate)
+    : BlobImplBase(aName, aContentType, aLength, aLastModifiedDate)
     , mInputStream(aInputStream)
   {
     MOZ_ASSERT(aLength != UINT64_MAX);
     MOZ_ASSERT(aLastModifiedDate != INT64_MAX);
     MOZ_ASSERT(aInputStream);
 
     mImmutable = true;
   }
 
 private:
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t /* aStart */,
               uint64_t /* aLength */,
               const nsAString& /* aContentType */,
               ErrorResult& /* aRv */) override
   {
     MOZ_CRASH("Not implemented");
   }
 
@@ -790,48 +790,48 @@ struct MOZ_STACK_CLASS CreateBlobImplMet
 
   bool
   IsFile() const
   {
     return !mName.IsVoid();
   }
 };
 
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 CreateBlobImpl(const nsID& aKnownBlobIDData,
                const CreateBlobImplMetadata& aMetadata)
 {
   MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
   MOZ_ASSERT(aMetadata.mHasRecursed);
 
-  nsRefPtr<FileImpl> blobImpl = BlobParent::GetBlobImplForID(aKnownBlobIDData);
+  nsRefPtr<BlobImpl> blobImpl = BlobParent::GetBlobImplForID(aKnownBlobIDData);
   if (NS_WARN_IF(!blobImpl)) {
     ASSERT_UNLESS_FUZZING();
     return nullptr;
   }
 
   DebugOnly<bool> isMutable;
   MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
   MOZ_ASSERT(!isMutable);
 
   return blobImpl.forget();
 }
 
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 CreateBlobImpl(const nsTArray<uint8_t>& aMemoryData,
                const CreateBlobImplMetadata& aMetadata)
 {
   static_assert(sizeof(aMemoryData.Length()) <= sizeof(size_t),
                 "String length won't fit in size_t!");
   static_assert(sizeof(size_t) <= sizeof(uint64_t),
                 "size_t won't fit in uint64_t!");
 
   MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
 
-  nsRefPtr<FileImpl> blobImpl;
+  nsRefPtr<BlobImpl> blobImpl;
 
   if (auto length = static_cast<size_t>(aMemoryData.Length())) {
     static MOZ_CONSTEXPR_VAR size_t elementSizeMultiplier =
       sizeof(aMemoryData[0]) / sizeof(char);
 
     if (!aMetadata.mHasRecursed &&
         NS_WARN_IF(aMetadata.mLength != uint64_t(length))) {
       ASSERT_UNLESS_FUZZING();
@@ -842,52 +842,52 @@ CreateBlobImpl(const nsTArray<uint8_t>& 
     if (NS_WARN_IF(!buffer)) {
       return nullptr;
     }
 
     memcpy(buffer, aMemoryData.Elements(), length * elementSizeMultiplier);
 
     if (!aMetadata.mHasRecursed && aMetadata.IsFile()) {
       blobImpl =
-        new FileImplMemory(buffer,
+        new BlobImplMemory(buffer,
                            uint64_t(length),
                            aMetadata.mName,
                            aMetadata.mContentType,
                            aMetadata.mLastModifiedDate);
     } else {
       blobImpl =
-        new FileImplMemory(buffer, uint64_t(length), aMetadata.mContentType);
+        new BlobImplMemory(buffer, uint64_t(length), aMetadata.mContentType);
     }
   } else if (!aMetadata.mHasRecursed && aMetadata.IsFile()) {
     blobImpl =
       new EmptyBlobImpl(aMetadata.mName,
                         aMetadata.mContentType,
                         aMetadata.mLastModifiedDate);
   } else {
     blobImpl = new EmptyBlobImpl(aMetadata.mContentType);
   }
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
 
   return blobImpl.forget();
 }
 
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 CreateBlobImpl(intptr_t aAddRefedInputStream,
                const CreateBlobImplMetadata& aMetadata)
 {
   MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
   MOZ_ASSERT(aMetadata.mIsSameProcessActor);
   MOZ_ASSERT(aAddRefedInputStream);
 
   nsCOMPtr<nsIInputStream> inputStream =
     dont_AddRef(
       reinterpret_cast<nsIInputStream*>(aAddRefedInputStream));
 
-  nsRefPtr<FileImpl> blobImpl;
+  nsRefPtr<BlobImpl> blobImpl;
   if (!aMetadata.mHasRecursed && aMetadata.IsFile()) {
     blobImpl =
       new SameProcessInputStreamBlobImpl(aMetadata.mName,
                                          aMetadata.mContentType,
                                          aMetadata.mLength,
                                          aMetadata.mLastModifiedDate,
                                          inputStream);
   } else {
@@ -899,27 +899,27 @@ CreateBlobImpl(intptr_t aAddRefedInputSt
 
   DebugOnly<bool> isMutable;
   MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
   MOZ_ASSERT(!isMutable);
 
   return blobImpl.forget();
 }
 
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 CreateBlobImpl(const nsTArray<BlobData>& aBlobData,
                CreateBlobImplMetadata& aMetadata);
 
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 CreateBlobImplFromBlobData(const BlobData& aBlobData,
                            CreateBlobImplMetadata& aMetadata)
 {
   MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
 
-  nsRefPtr<FileImpl> blobImpl;
+  nsRefPtr<BlobImpl> blobImpl;
 
   switch (aBlobData.type()) {
     case BlobData::TnsID: {
       blobImpl = CreateBlobImpl(aBlobData.get_nsID(), aMetadata);
       break;
     }
 
     case BlobData::TArrayOfuint8_t: {
@@ -939,81 +939,81 @@ CreateBlobImplFromBlobData(const BlobDat
 
     default:
       MOZ_CRASH("Unknown params!");
   }
 
   return blobImpl.forget();
 }
 
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 CreateBlobImpl(const nsTArray<BlobData>& aBlobDatas,
                CreateBlobImplMetadata& aMetadata)
 {
   MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
 
   // Special case for a multipart blob with only one part.
   if (aBlobDatas.Length() == 1) {
     const BlobData& blobData = aBlobDatas[0];
 
-    nsRefPtr<FileImpl> blobImpl =
+    nsRefPtr<BlobImpl> blobImpl =
       CreateBlobImplFromBlobData(blobData, aMetadata);
     if (NS_WARN_IF(!blobImpl)) {
       return nullptr;
     }
 
     DebugOnly<bool> isMutable;
     MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
     MOZ_ASSERT(!isMutable);
 
     return blobImpl.forget();
   }
 
-  FallibleTArray<nsRefPtr<FileImpl>> fallibleBlobImpls;
+  FallibleTArray<nsRefPtr<BlobImpl>> fallibleBlobImpls;
   if (NS_WARN_IF(!fallibleBlobImpls.SetLength(aBlobDatas.Length()))) {
     return nullptr;
   }
 
-  nsTArray<nsRefPtr<FileImpl>> blobImpls;
+  nsTArray<nsRefPtr<BlobImpl>> blobImpls;
   fallibleBlobImpls.SwapElements(blobImpls);
 
   const bool hasRecursed = aMetadata.mHasRecursed;
   aMetadata.mHasRecursed = true;
 
   for (uint32_t count = aBlobDatas.Length(), index = 0;
        index < count;
        index++) {
     const BlobData& blobData = aBlobDatas[index];
-    nsRefPtr<FileImpl>& blobImpl = blobImpls[index];
+    nsRefPtr<BlobImpl>& blobImpl = blobImpls[index];
 
     blobImpl = CreateBlobImplFromBlobData(blobData, aMetadata);
     if (NS_WARN_IF(!blobImpl)) {
       return nullptr;
     }
 
     DebugOnly<bool> isMutable;
     MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
     MOZ_ASSERT(!isMutable);
   }
 
-  nsRefPtr<FileImpl> blobImpl;
+  nsRefPtr<BlobImpl> blobImpl;
   if (!hasRecursed && aMetadata.IsFile()) {
     blobImpl =
-      new MultipartFileImpl(blobImpls, aMetadata.mName, aMetadata.mContentType);
+      new MultipartBlobImpl(blobImpls, aMetadata.mName, aMetadata.mContentType);
   } else {
     blobImpl =
-      new MultipartFileImpl(blobImpls, aMetadata.mContentType);
+      new MultipartBlobImpl(blobImpls, aMetadata.mContentType);
   }
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
 
   return blobImpl.forget();
 }
 
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 CreateBlobImpl(const ParentBlobConstructorParams& aParams,
                const BlobData& aBlobData,
                bool aIsSameProcessActor)
 {
   MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
   MOZ_ASSERT(aParams.blobParams().type() ==
                AnyBlobConstructorParams::TNormalBlobConstructorParams ||
              aParams.blobParams().type() ==
@@ -1048,28 +1048,28 @@ CreateBlobImpl(const ParentBlobConstruct
     }
 
     metadata.mContentType = params.contentType();
     metadata.mName = params.name();
     metadata.mLength = params.length();
     metadata.mLastModifiedDate = params.modDate();
   }
 
-  nsRefPtr<FileImpl> blobImpl =
+  nsRefPtr<BlobImpl> blobImpl =
     CreateBlobImplFromBlobData(aBlobData, metadata);
   return blobImpl.forget();
 }
 
 void
-BlobDataFromBlobImpl(FileImpl* aBlobImpl, BlobData& aBlobData)
+BlobDataFromBlobImpl(BlobImpl* aBlobImpl, BlobData& aBlobData)
 {
   MOZ_ASSERT(gProcessType != GeckoProcessType_Default);
   MOZ_ASSERT(aBlobImpl);
 
-  const nsTArray<nsRefPtr<FileImpl>>* subBlobs = aBlobImpl->GetSubBlobImpls();
+  const nsTArray<nsRefPtr<BlobImpl>>* subBlobs = aBlobImpl->GetSubBlobImpls();
 
   if (subBlobs) {
     aBlobData = nsTArray<BlobData>();
 
     nsTArray<BlobData>& subBlobDatas = aBlobData.get_ArrayOfBlobData();
     subBlobDatas.SetLength(subBlobs->Length());
 
     for (uint32_t count = subBlobs->Length(), index = 0;
@@ -1113,17 +1113,17 @@ BlobDataFromBlobImpl(FileImpl* aBlobImpl
 
   uint32_t readCount;
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
     inputStream->Read(reinterpret_cast<char*>(blobData.Elements()),
                       uint32_t(available),
                       &readCount)));
 }
 
-RemoteInputStream::RemoteInputStream(FileImpl* aBlobImpl,
+RemoteInputStream::RemoteInputStream(BlobImpl* aBlobImpl,
                                      uint64_t aStart,
                                      uint64_t aLength)
   : mMonitor("RemoteInputStream.mMonitor")
   , mActor(nullptr)
   , mBlobImpl(aBlobImpl)
   , mWeakSeekableStream(nullptr)
   , mStart(aStart)
   , mLength(aLength)
@@ -1134,17 +1134,17 @@ RemoteInputStream::RemoteInputStream(Fil
     mEventTarget = do_GetCurrentThread();
     MOZ_ASSERT(mEventTarget);
   }
 
   MOZ_ASSERT(IsOnOwningThread());
 }
 
 RemoteInputStream::RemoteInputStream(BlobChild* aActor,
-                                     FileImpl* aBlobImpl,
+                                     BlobImpl* aBlobImpl,
                                      uint64_t aStart,
                                      uint64_t aLength)
   : mMonitor("RemoteInputStream.mMonitor")
   , mActor(aActor)
   , mBlobImpl(aBlobImpl)
   , mEventTarget(NS_GetCurrentThread())
   , mWeakSeekableStream(nullptr)
   , mStart(aStart)
@@ -1283,17 +1283,17 @@ NS_INTERFACE_MAP_BEGIN(RemoteInputStream
 NS_INTERFACE_MAP_END
 
 NS_IMETHODIMP
 RemoteInputStream::Close()
 {
   nsresult rv = BlockAndWaitForStream();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<FileImpl> blobImpl;
+  nsRefPtr<BlobImpl> blobImpl;
   mBlobImpl.swap(blobImpl);
 
   rv = mStream->Close();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
@@ -1488,21 +1488,21 @@ StaticAutoPtr<Mutex> BlobParent::sIDTabl
 /*******************************************************************************
  * BlobParent::IDTableEntry Declaration
  ******************************************************************************/
 
 class BlobParent::IDTableEntry final
 {
   const nsID mID;
   const intptr_t mProcessID;
-  const nsRefPtr<FileImpl> mBlobImpl;
+  const nsRefPtr<BlobImpl> mBlobImpl;
 
 public:
   static already_AddRefed<IDTableEntry>
-  Create(const nsID& aID, intptr_t aProcessID, FileImpl* aBlobImpl)
+  Create(const nsID& aID, intptr_t aProcessID, BlobImpl* aBlobImpl)
   {
     MOZ_ASSERT(aBlobImpl);
 
     DebugOnly<bool> isMutable;
     MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable)));
     MOZ_ASSERT(!isMutable);
 
     return GetOrCreateInternal(aID,
@@ -1531,17 +1531,17 @@ public:
                                0,
                                nullptr,
                                /* aMayCreate */ false,
                                /* aMayGet */ true,
                                /* aIgnoreProcessID */ true);
   }
 
   static already_AddRefed<IDTableEntry>
-  GetOrCreate(const nsID& aID, intptr_t aProcessID, FileImpl* aBlobImpl)
+  GetOrCreate(const nsID& aID, intptr_t aProcessID, BlobImpl* aBlobImpl)
   {
     MOZ_ASSERT(aBlobImpl);
 
     DebugOnly<bool> isMutable;
     MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable)));
     MOZ_ASSERT(!isMutable);
 
     return GetOrCreateInternal(aID,
@@ -1559,32 +1559,32 @@ public:
   }
 
   intptr_t
   ProcessID() const
   {
     return mProcessID;
   }
 
-  FileImpl*
-  BlobImpl() const
+  BlobImpl*
+  GetBlobImpl() const
   {
     return mBlobImpl;
   }
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(IDTableEntry)
 
 private:
-  IDTableEntry(const nsID& aID, intptr_t aProcessID, FileImpl* aBlobImpl);
+  IDTableEntry(const nsID& aID, intptr_t aProcessID, BlobImpl* aBlobImpl);
   ~IDTableEntry();
 
   static already_AddRefed<IDTableEntry>
   GetOrCreateInternal(const nsID& aID,
                       intptr_t aProcessID,
-                      FileImpl* aBlobImpl,
+                      BlobImpl* aBlobImpl,
                       bool aMayCreate,
                       bool aMayGet,
                       bool aIgnoreProcessID);
 };
 
 /*******************************************************************************
  * BlobParent::OpenStreamRunnable Declaration
  ******************************************************************************/
@@ -1827,26 +1827,26 @@ private:
 
 NS_IMPL_ISUPPORTS_INHERITED0(BlobParent::OpenStreamRunnable, nsRunnable)
 
 /*******************************************************************************
  * BlobChild::RemoteBlobImpl Declaration
  ******************************************************************************/
 
 class BlobChild::RemoteBlobImpl
-  : public FileImplBase
+  : public BlobImplBase
   , public nsIRemoteBlob
 {
 protected:
   class CreateStreamHelper;
 
   BlobChild* mActor;
   nsCOMPtr<nsIEventTarget> mActorTarget;
 
-  nsRefPtr<FileImpl> mSameProcessFileImpl;
+  nsRefPtr<BlobImpl> mSameProcessBlobImpl;
 
   const bool mIsSlice;
 
 public:
   // For File.
   RemoteBlobImpl(BlobChild* aActor,
                  const nsAString& aName,
                  const nsAString& aContentType,
@@ -1855,25 +1855,25 @@ public:
 
   // For Blob.
   RemoteBlobImpl(BlobChild* aActor,
                  const nsAString& aContentType,
                  uint64_t aLength);
 
   // For same-process blobs.
   RemoteBlobImpl(BlobChild* aActor,
-                 FileImpl* aSameProcessBlobImpl,
+                 BlobImpl* aSameProcessBlobImpl,
                  const nsAString& aName,
                  const nsAString& aContentType,
                  uint64_t aLength,
                  int64_t aModDate);
 
   // For same-process blobs.
   RemoteBlobImpl(BlobChild* aActor,
-                 FileImpl* aSameProcessBlobImpl,
+                 BlobImpl* aSameProcessBlobImpl,
                  const nsAString& aContentType,
                  uint64_t aLength);
 
   // For mystery blobs.
   explicit
   RemoteBlobImpl(BlobChild* aActor);
 
   void
@@ -1911,17 +1911,17 @@ public:
   RemoteBlobImpl*
   BaseRemoteBlobImpl() const;
 
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual void
   GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) override;
 
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t aStart,
               uint64_t aLength,
               const nsAString& aContentType,
               ErrorResult& aRv) override;
 
   virtual nsresult
   GetInternalStream(nsIInputStream** aStream) override;
 
@@ -2041,25 +2041,25 @@ private:
   EnsureActorWasCreatedInternal();
 };
 
 /*******************************************************************************
  * BlobParent::RemoteBlobImpl Declaration
  ******************************************************************************/
 
 class BlobParent::RemoteBlobImpl final
-  : public FileImpl
+  : public BlobImpl
   , public nsIRemoteBlob
 {
   BlobParent* mActor;
   nsCOMPtr<nsIEventTarget> mActorTarget;
-  nsRefPtr<FileImpl> mBlobImpl;
+  nsRefPtr<BlobImpl> mBlobImpl;
 
 public:
-  RemoteBlobImpl(BlobParent* aActor, FileImpl* aBlobImpl);
+  RemoteBlobImpl(BlobParent* aActor, BlobImpl* aBlobImpl);
 
   void
   NoteDyingActor();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual void
   GetName(nsAString& aName) override;
@@ -2080,23 +2080,23 @@ public:
   GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) override;
 
   virtual uint64_t
   GetSize(ErrorResult& aRv) override;
 
   virtual void
   GetType(nsAString& aType) override;
 
-  virtual already_AddRefed<FileImpl>
+  virtual already_AddRefed<BlobImpl>
   CreateSlice(uint64_t aStart,
               uint64_t aLength,
               const nsAString& aContentType,
               ErrorResult& aRv) override;
 
-  virtual const nsTArray<nsRefPtr<FileImpl>>*
+  virtual const nsTArray<nsRefPtr<BlobImpl>>*
   GetSubBlobImpls() const override;
 
   virtual nsresult
   GetInternalStream(nsIInputStream** aStream) override;
 
   virtual int64_t
   GetFileId() override;
 
@@ -2161,75 +2161,75 @@ private:
  ******************************************************************************/
 
 BlobChild::
 RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
                                const nsAString& aName,
                                const nsAString& aContentType,
                                uint64_t aLength,
                                int64_t aModDate)
-  : FileImplBase(aName, aContentType, aLength, aModDate)
+  : BlobImplBase(aName, aContentType, aLength, aModDate)
   , mIsSlice(false)
 {
   CommonInit(aActor);
 }
 
 BlobChild::
 RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
                                const nsAString& aContentType,
                                uint64_t aLength)
-  : FileImplBase(aContentType, aLength)
+  : BlobImplBase(aContentType, aLength)
   , mIsSlice(false)
 {
   CommonInit(aActor);
 }
 
 BlobChild::
 RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
-                               FileImpl* aSameProcessBlobImpl,
+                               BlobImpl* aSameProcessBlobImpl,
                                const nsAString& aName,
                                const nsAString& aContentType,
                                uint64_t aLength,
                                int64_t aModDate)
-  : FileImplBase(aName, aContentType, aLength, aModDate)
-  , mSameProcessFileImpl(aSameProcessBlobImpl)
+  : BlobImplBase(aName, aContentType, aLength, aModDate)
+  , mSameProcessBlobImpl(aSameProcessBlobImpl)
   , mIsSlice(false)
 {
   MOZ_ASSERT(aSameProcessBlobImpl);
   MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
 
   CommonInit(aActor);
 }
 
 BlobChild::
 RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
-                               FileImpl* aSameProcessBlobImpl,
+                               BlobImpl* aSameProcessBlobImpl,
                                const nsAString& aContentType,
                                uint64_t aLength)
-  : FileImplBase(aContentType, aLength)
-  , mSameProcessFileImpl(aSameProcessBlobImpl)
+  : BlobImplBase(aContentType, aLength)
+  , mSameProcessBlobImpl(aSameProcessBlobImpl)
   , mIsSlice(false)
 {
   MOZ_ASSERT(aSameProcessBlobImpl);
   MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
 
   CommonInit(aActor);
 }
 
 BlobChild::
 RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor)
-  : FileImplBase(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
+  : BlobImplBase(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
   , mIsSlice(false)
 {
   CommonInit(aActor);
 }
 
 BlobChild::
 RemoteBlobImpl::RemoteBlobImpl(const nsAString& aContentType, uint64_t aLength)
-  : FileImplBase(aContentType, aLength)
+  : BlobImplBase(aContentType, aLength)
   , mActor(nullptr)
   , mIsSlice(true)
 {
   mImmutable = true;
 }
 
 void
 BlobChild::
@@ -2301,32 +2301,32 @@ RemoteBlobImpl::Destroy()
   } else {
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(destroyRunnable)));
   }
 }
 
 NS_IMPL_ADDREF(BlobChild::RemoteBlobImpl)
 NS_IMPL_RELEASE_WITH_DESTROY(BlobChild::RemoteBlobImpl, Destroy())
 NS_IMPL_QUERY_INTERFACE_INHERITED(BlobChild::RemoteBlobImpl,
-                                  FileImpl,
+                                  BlobImpl,
                                   nsIRemoteBlob)
 
 void
 BlobChild::
 RemoteBlobImpl::GetMozFullPathInternal(nsAString& aFilePath,
                                        ErrorResult& aRv)
 {
   if (!EventTargetIsOnCurrentThread(mActorTarget)) {
     MOZ_CRASH("Not implemented!");
   }
 
-  if (mSameProcessFileImpl) {
+  if (mSameProcessBlobImpl) {
     MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
 
-    mSameProcessFileImpl->GetMozFullPathInternal(aFilePath, aRv);
+    mSameProcessBlobImpl->GetMozFullPathInternal(aFilePath, aRv);
     return;
   }
 
   if (!mActor) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 
@@ -2334,75 +2334,75 @@ RemoteBlobImpl::GetMozFullPathInternal(n
   if (!mActor->SendGetFilePath(&filePath)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   aFilePath = filePath;
 }
 
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 BlobChild::
 RemoteBlobImpl::CreateSlice(uint64_t aStart,
                             uint64_t aLength,
                             const nsAString& aContentType,
                             ErrorResult& aRv)
 {
   // May be called on any thread.
-  if (mSameProcessFileImpl) {
+  if (mSameProcessBlobImpl) {
     MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
 
-    return mSameProcessFileImpl->CreateSlice(aStart,
+    return mSameProcessBlobImpl->CreateSlice(aStart,
                                              aLength,
                                              aContentType,
                                              aRv);
   }
 
   nsRefPtr<RemoteBlobSliceImpl> slice =
     new RemoteBlobSliceImpl(this, aStart, aLength, aContentType);
   return slice.forget();
 }
 
 nsresult
 BlobChild::
 RemoteBlobImpl::GetInternalStream(nsIInputStream** aStream)
 {
   // May be called on any thread.
-  if (mSameProcessFileImpl) {
+  if (mSameProcessBlobImpl) {
     MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
 
     nsCOMPtr<nsIInputStream> realStream;
     nsresult rv =
-      mSameProcessFileImpl->GetInternalStream(getter_AddRefs(realStream));
+      mSameProcessBlobImpl->GetInternalStream(getter_AddRefs(realStream));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsRefPtr<BlobInputStreamTether> tether =
-      new BlobInputStreamTether(realStream, mSameProcessFileImpl);
+      new BlobInputStreamTether(realStream, mSameProcessBlobImpl);
     tether.forget(aStream);
     return NS_OK;
   }
 
   nsRefPtr<CreateStreamHelper> helper = new CreateStreamHelper(this);
   return helper->GetStream(aStream);
 }
 
 int64_t
 BlobChild::
 RemoteBlobImpl::GetFileId()
 {
   if (!EventTargetIsOnCurrentThread(mActorTarget)) {
     MOZ_CRASH("Not implemented!");
   }
 
-  if (mSameProcessFileImpl) {
+  if (mSameProcessBlobImpl) {
     MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
 
-    return mSameProcessFileImpl->GetFileId();
+    return mSameProcessBlobImpl->GetFileId();
   }
 
   int64_t fileId;
   if (mActor && mActor->SendGetFileId(&fileId)) {
     return fileId;
   }
 
   return -1;
@@ -2431,17 +2431,17 @@ BlobChild::
 RemoteBlobImpl::SetMutable(bool aMutable)
 {
   if (!aMutable && IsSlice()) {
     // Make sure that slices are backed by a real actor now while we are still
     // on the correct thread.
     AsSlice()->EnsureActorWasCreated();
   }
 
-  nsresult rv = FileImplBase::SetMutable(aMutable);
+  nsresult rv = BlobImplBase::SetMutable(aMutable);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   MOZ_ASSERT_IF(!aMutable, mImmutable);
 
   return NS_OK;
 }
@@ -2672,17 +2672,17 @@ RemoteBlobSliceImpl::GetBlobChild()
   return RemoteBlobImpl::GetBlobChild();
 }
 
 /*******************************************************************************
  * BlobParent::RemoteBlobImpl
  ******************************************************************************/
 
 BlobParent::
-RemoteBlobImpl::RemoteBlobImpl(BlobParent* aActor, FileImpl* aBlobImpl)
+RemoteBlobImpl::RemoteBlobImpl(BlobParent* aActor, BlobImpl* aBlobImpl)
   : mActor(aActor)
   , mActorTarget(aActor->EventTarget())
   , mBlobImpl(aBlobImpl)
 {
   MOZ_ASSERT(aActor);
   aActor->AssertIsOnOwningThread();
   MOZ_ASSERT(aBlobImpl);
 
@@ -2727,17 +2727,17 @@ RemoteBlobImpl::Destroy()
   } else {
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(destroyRunnable)));
   }
 }
 
 NS_IMPL_ADDREF(BlobParent::RemoteBlobImpl)
 NS_IMPL_RELEASE_WITH_DESTROY(BlobParent::RemoteBlobImpl, Destroy())
 NS_IMPL_QUERY_INTERFACE_INHERITED(BlobParent::RemoteBlobImpl,
-                                  FileImpl,
+                                  BlobImpl,
                                   nsIRemoteBlob)
 
 void
 BlobParent::
 RemoteBlobImpl::GetName(nsAString& aName)
 {
   mBlobImpl->GetName(aName);
 }
@@ -2786,27 +2786,27 @@ RemoteBlobImpl::GetSize(ErrorResult& aRv
 
 void
 BlobParent::
 RemoteBlobImpl::GetType(nsAString& aType)
 {
   mBlobImpl->GetType(aType);
 }
 
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 BlobParent::
 RemoteBlobImpl::CreateSlice(uint64_t aStart,
                             uint64_t aLength,
                             const nsAString& aContentType,
                             ErrorResult& aRv)
 {
   return mBlobImpl->CreateSlice(aStart, aLength, aContentType, aRv);
 }
 
-const nsTArray<nsRefPtr<FileImpl>>*
+const nsTArray<nsRefPtr<BlobImpl>>*
 BlobParent::
 RemoteBlobImpl::GetSubBlobImpls() const
 {
   return mBlobImpl->GetSubBlobImpls();
 }
 
 nsresult
 BlobParent::
@@ -2921,27 +2921,27 @@ RemoteBlobImpl::GetBlobParent()
 {
   return mActor;
 }
 
 /*******************************************************************************
  * BlobChild
  ******************************************************************************/
 
-BlobChild::BlobChild(nsIContentChild* aManager, FileImpl* aBlobImpl)
+BlobChild::BlobChild(nsIContentChild* aManager, BlobImpl* aBlobImpl)
   : mBackgroundManager(nullptr)
   , mContentManager(aManager)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
 
   CommonInit(aBlobImpl);
 }
 
-BlobChild::BlobChild(PBackgroundChild* aManager, FileImpl* aBlobImpl)
+BlobChild::BlobChild(PBackgroundChild* aManager, BlobImpl* aBlobImpl)
   : mBackgroundManager(aManager)
   , mContentManager(nullptr)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
 
   if (!NS_IsMainThread()) {
     mEventTarget = do_GetCurrentThread();
@@ -2958,17 +2958,17 @@ BlobChild::BlobChild(nsIContentChild* aM
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
 
   CommonInit(aOther, /* aBlobImpl */ nullptr);
 }
 
 BlobChild::BlobChild(PBackgroundChild* aManager,
                      BlobChild* aOther,
-                     FileImpl* aBlobImpl)
+                     BlobImpl* aBlobImpl)
   : mBackgroundManager(aManager)
   , mContentManager(nullptr)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(aBlobImpl);
 
   if (!NS_IsMainThread()) {
@@ -3038,42 +3038,42 @@ BlobChild::BlobChild(PBackgroundChild* a
 BlobChild::~BlobChild()
 {
   AssertIsOnOwningThread();
 
   MOZ_COUNT_DTOR(BlobChild);
 }
 
 void
-BlobChild::CommonInit(FileImpl* aBlobImpl)
+BlobChild::CommonInit(BlobImpl* aBlobImpl)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aBlobImpl);
 
   MOZ_COUNT_CTOR(BlobChild);
 
   mBlobImpl = aBlobImpl;
   mRemoteBlobImpl = nullptr;
 
   mBlobImpl->AddRef();
   mOwnsBlobImpl = true;
 
   memset(&mParentID, 0, sizeof(mParentID));
 }
 
 void
-BlobChild::CommonInit(BlobChild* aOther, FileImpl* aBlobImpl)
+BlobChild::CommonInit(BlobChild* aOther, BlobImpl* aBlobImpl)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aOther);
   MOZ_ASSERT_IF(mContentManager, aOther->GetBackgroundManager());
   MOZ_ASSERT_IF(mContentManager, !aBlobImpl);
   MOZ_ASSERT_IF(mBackgroundManager, aBlobImpl);
 
-  nsRefPtr<FileImpl> otherImpl;
+  nsRefPtr<BlobImpl> otherImpl;
   if (mBackgroundManager && aOther->GetBackgroundManager()) {
     otherImpl = aBlobImpl;
   } else {
     otherImpl = aOther->GetBlobImpl();
   }
   MOZ_ASSERT(otherImpl);
 
   nsString contentType;
@@ -3137,20 +3137,20 @@ BlobChild::CommonInit(const ChildBlobCon
       break;
     }
 
     case AnyBlobConstructorParams::TSameProcessBlobConstructorParams: {
       MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
 
       const SameProcessBlobConstructorParams& params =
         blobParams.get_SameProcessBlobConstructorParams();
-      MOZ_ASSERT(params.addRefedFileImpl());
-
-      nsRefPtr<FileImpl> blobImpl =
-        dont_AddRef(reinterpret_cast<FileImpl*>(params.addRefedFileImpl()));
+      MOZ_ASSERT(params.addRefedBlobImpl());
+
+      nsRefPtr<BlobImpl> blobImpl =
+        dont_AddRef(reinterpret_cast<BlobImpl*>(params.addRefedBlobImpl()));
 
       ErrorResult rv;
       uint64_t size = blobImpl->GetSize(rv);
       MOZ_ASSERT(!rv.Failed());
 
       nsString contentType;
       blobImpl->GetType(contentType);
 
@@ -3236,27 +3236,27 @@ BlobChild::Startup(const FriendKey& /* a
 {
   MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default);
 
   CommonStartup();
 }
 
 // static
 BlobChild*
-BlobChild::GetOrCreate(nsIContentChild* aManager, FileImpl* aBlobImpl)
+BlobChild::GetOrCreate(nsIContentChild* aManager, BlobImpl* aBlobImpl)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
 
   return GetOrCreateFromImpl(aManager, aBlobImpl);
 }
 
 // static
 BlobChild*
-BlobChild::GetOrCreate(PBackgroundChild* aManager, FileImpl* aBlobImpl)
+BlobChild::GetOrCreate(PBackgroundChild* aManager, BlobImpl* aBlobImpl)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
 
   return GetOrCreateFromImpl(aManager, aBlobImpl);
 }
 
 // static
@@ -3280,17 +3280,17 @@ BlobChild::Create(PBackgroundChild* aMan
 
   return CreateFromParams(aManager, aParams);
 }
 
 // static
 template <class ChildManagerType>
 BlobChild*
 BlobChild::GetOrCreateFromImpl(ChildManagerType* aManager,
-                               FileImpl* aBlobImpl)
+                               BlobImpl* aBlobImpl)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(aBlobImpl);
 
   // If the blob represents a remote blob then we can simply pass its actor back
   // here.
   if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlobImpl)) {
@@ -3309,29 +3309,29 @@ BlobChild::GetOrCreateFromImpl(ChildMana
   MOZ_ASSERT(!aBlobImpl->IsSizeUnknown());
   MOZ_ASSERT(!aBlobImpl->IsDateUnknown());
 
   AnyBlobConstructorParams blobParams;
 
   nsCOMPtr<nsIInputStream> snapshotInputStream;
 
   if (gProcessType == GeckoProcessType_Default) {
-    nsCOMPtr<PIFileImplSnapshot> snapshot = do_QueryInterface(aBlobImpl);
+    nsCOMPtr<PIBlobImplSnapshot> snapshot = do_QueryInterface(aBlobImpl);
     if (snapshot) {
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
         aBlobImpl->GetInternalStream(getter_AddRefs(snapshotInputStream))));
     }
   }
 
   if (gProcessType == GeckoProcessType_Default && !snapshotInputStream) {
-    nsRefPtr<FileImpl> sameProcessImpl = aBlobImpl;
-    auto addRefedFileImpl =
+    nsRefPtr<BlobImpl> sameProcessImpl = aBlobImpl;
+    auto addRefedBlobImpl =
       reinterpret_cast<intptr_t>(sameProcessImpl.forget().take());
 
-    blobParams = SameProcessBlobConstructorParams(addRefedFileImpl);
+    blobParams = SameProcessBlobConstructorParams(addRefedBlobImpl);
   } else {
     BlobData blobData;
     if (snapshotInputStream) {
       blobData =
         reinterpret_cast<intptr_t>(snapshotInputStream.forget().take());
     } else {
       BlobDataFromBlobImpl(aBlobImpl, blobData);
     }
@@ -3428,17 +3428,17 @@ BlobChild::SendSliceConstructor(ChildMan
 
   return nullptr;
 }
 
 // static
 BlobChild*
 BlobChild::MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
                                        nsIContentChild* aManager,
-                                       FileImpl* aBlobImpl)
+                                       BlobImpl* aBlobImpl)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aRemoteBlob);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(aBlobImpl);
 
   if (BlobChild* actor = aRemoteBlob->GetBlobChild()) {
     if (actor->GetContentManager() == aManager) {
@@ -3459,17 +3459,17 @@ BlobChild::MaybeGetActorFromRemoteBlob(n
 
   return nullptr;
 }
 
 // static
 BlobChild*
 BlobChild::MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
                                        PBackgroundChild* aManager,
-                                       FileImpl* aBlobImpl)
+                                       BlobImpl* aBlobImpl)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aRemoteBlob);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(aBlobImpl);
 
   if (BlobChild* actor = aRemoteBlob->GetBlobChild()) {
     if (actor->GetBackgroundManager() == aManager) {
@@ -3492,23 +3492,23 @@ BlobChild::MaybeGetActorFromRemoteBlob(n
 const nsID&
 BlobChild::ParentID() const
 {
   MOZ_ASSERT(mRemoteBlobImpl);
 
   return mParentID;
 }
 
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 BlobChild::GetBlobImpl()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mBlobImpl);
 
-  nsRefPtr<FileImpl> blobImpl;
+  nsRefPtr<BlobImpl> blobImpl;
 
   // Remote blobs are held alive until the first call to GetBlobImpl. Thereafter
   // we only hold a weak reference. Normal blobs are held alive until the actor
   // is destroyed.
   if (mRemoteBlobImpl && mOwnsBlobImpl) {
     blobImpl = dont_AddRef(mBlobImpl);
     mOwnsBlobImpl = false;
   } else {
@@ -3661,29 +3661,29 @@ BlobParent::BlobParent(PBackgroundParent
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mEventTarget);
 
   CommonInit(aIDTableEntry);
 }
 
 BlobParent::BlobParent(nsIContentParent* aManager,
-                       FileImpl* aBlobImpl,
+                       BlobImpl* aBlobImpl,
                        IDTableEntry* aIDTableEntry)
   : mBackgroundManager(nullptr)
   , mContentManager(aManager)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
 
   CommonInit(aBlobImpl, aIDTableEntry);
 }
 
 BlobParent::BlobParent(PBackgroundParent* aManager,
-                       FileImpl* aBlobImpl,
+                       BlobImpl* aBlobImpl,
                        IDTableEntry* aIDTableEntry)
   : mBackgroundManager(aManager)
   , mContentManager(nullptr)
   , mEventTarget(do_GetCurrentThread())
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mEventTarget);
@@ -3698,31 +3698,31 @@ BlobParent::~BlobParent()
   MOZ_COUNT_DTOR(BlobParent);
 }
 
 void
 BlobParent::CommonInit(IDTableEntry* aIDTableEntry)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aIDTableEntry);
-  MOZ_ASSERT(aIDTableEntry->BlobImpl());
+  MOZ_ASSERT(aIDTableEntry->GetBlobImpl());
 
   MOZ_COUNT_CTOR(BlobParent);
 
-  mBlobImpl = aIDTableEntry->BlobImpl();
+  mBlobImpl = aIDTableEntry->GetBlobImpl();
   mRemoteBlobImpl = nullptr;
 
   mBlobImpl->AddRef();
   mOwnsBlobImpl = true;
 
   mIDTableEntry = aIDTableEntry;
 }
 
 void
-BlobParent::CommonInit(FileImpl* aBlobImpl, IDTableEntry* aIDTableEntry)
+BlobParent::CommonInit(BlobImpl* aBlobImpl, IDTableEntry* aIDTableEntry)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aBlobImpl);
   MOZ_ASSERT(aIDTableEntry);
 
   MOZ_COUNT_CTOR(BlobParent);
 
   DebugOnly<bool> isMutable;
@@ -3763,27 +3763,27 @@ BlobParent::Startup(const FriendKey& /* 
   ClearOnShutdown(&sIDTable);
 
   sIDTableMutex = new Mutex("BlobParent::sIDTableMutex");
   ClearOnShutdown(&sIDTableMutex);
 }
 
 // static
 BlobParent*
-BlobParent::GetOrCreate(nsIContentParent* aManager, FileImpl* aBlobImpl)
+BlobParent::GetOrCreate(nsIContentParent* aManager, BlobImpl* aBlobImpl)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
 
   return GetOrCreateFromImpl(aManager, aBlobImpl);
 }
 
 // static
 BlobParent*
-BlobParent::GetOrCreate(PBackgroundParent* aManager, FileImpl* aBlobImpl)
+BlobParent::GetOrCreate(PBackgroundParent* aManager, BlobImpl* aBlobImpl)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
 
   return GetOrCreateFromImpl(aManager, aBlobImpl);
 }
 
 // static
@@ -3804,40 +3804,40 @@ BlobParent::Create(PBackgroundParent* aM
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
 
   return CreateFromParams(aManager, aParams);
 }
 
 // static
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 BlobParent::GetBlobImplForID(const nsID& aID)
 {
   if (NS_WARN_IF(gProcessType != GeckoProcessType_Default)) {
     ASSERT_UNLESS_FUZZING();
     return nullptr;
   }
 
   nsRefPtr<IDTableEntry> idTableEntry = IDTableEntry::Get(aID);
   if (NS_WARN_IF(!idTableEntry)) {
     return nullptr;
   }
 
-  nsRefPtr<FileImpl> blobImpl = idTableEntry->BlobImpl();
+  nsRefPtr<BlobImpl> blobImpl = idTableEntry->GetBlobImpl();
   MOZ_ASSERT(blobImpl);
 
   return blobImpl.forget();
 }
 
 // static
 template <class ParentManagerType>
 BlobParent*
 BlobParent::GetOrCreateFromImpl(ParentManagerType* aManager,
-                                FileImpl* aBlobImpl)
+                                BlobImpl* aBlobImpl)
 {
   AssertCorrectThreadForManager(aManager);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(aBlobImpl);
 
   // If the blob represents a remote blob for this manager then we can simply
   // pass its actor back here.
   if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlobImpl)) {
@@ -3854,28 +3854,28 @@ BlobParent::GetOrCreateFromImpl(ParentMa
 
   const bool isSameProcessActor = ActorManagerIsSameProcess(aManager);
 
   AnyBlobConstructorParams blobParams;
 
   bool isSnapshot;
 
   if (isSameProcessActor) {
-    nsCOMPtr<PIFileImplSnapshot> snapshot = do_QueryInterface(aBlobImpl);
+    nsCOMPtr<PIBlobImplSnapshot> snapshot = do_QueryInterface(aBlobImpl);
     isSnapshot = !!snapshot;
   } else {
     isSnapshot = false;
   }
 
   if (isSameProcessActor && !isSnapshot) {
-    nsRefPtr<FileImpl> sameProcessImpl = aBlobImpl;
-    auto addRefedFileImpl =
+    nsRefPtr<BlobImpl> sameProcessImpl = aBlobImpl;
+    auto addRefedBlobImpl =
       reinterpret_cast<intptr_t>(sameProcessImpl.forget().take());
 
-    blobParams = SameProcessBlobConstructorParams(addRefedFileImpl);
+    blobParams = SameProcessBlobConstructorParams(addRefedBlobImpl);
   } else {
     if (aBlobImpl->IsSizeUnknown() || aBlobImpl->IsDateUnknown()) {
       // We don't want to call GetSize or GetLastModifiedDate yet since that may
       // stat a file on the this thread. Instead we'll learn the size lazily
       // from the other side.
       blobParams = MysteryBlobConstructorParams();
     } else {
       nsString contentType;
@@ -3942,17 +3942,17 @@ BlobParent::CreateFromParams(ParentManag
         blobParams.get_NormalBlobConstructorParams().optionalBlobData() :
         blobParams.get_FileBlobConstructorParams().optionalBlobData();
 
       if (NS_WARN_IF(optionalBlobData.type() != OptionalBlobData::TBlobData)) {
         ASSERT_UNLESS_FUZZING();
         return nullptr;
       }
 
-      nsRefPtr<FileImpl> blobImpl =
+      nsRefPtr<BlobImpl> blobImpl =
         CreateBlobImpl(aParams,
                        optionalBlobData.get_BlobData(),
                        ActorManagerIsSameProcess(aManager));
       if (NS_WARN_IF(!blobImpl)) {
         ASSERT_UNLESS_FUZZING();
         return nullptr;
       }
 
@@ -3978,21 +3978,21 @@ BlobParent::CreateFromParams(ParentManag
         return nullptr;
       }
 
       auto* actor =
         const_cast<BlobParent*>(
           static_cast<const BlobParent*>(params.sourceParent()));
       MOZ_ASSERT(actor);
 
-      nsRefPtr<FileImpl> source = actor->GetBlobImpl();
+      nsRefPtr<BlobImpl> source = actor->GetBlobImpl();
       MOZ_ASSERT(source);
 
       ErrorResult rv;
-      nsRefPtr<FileImpl> slice =
+      nsRefPtr<BlobImpl> slice =
         source->CreateSlice(params.begin(),
                             params.end() - params.begin(),
                             params.contentType(),
                             rv);
       if (NS_WARN_IF(rv.Failed())) {
         ASSERT_UNLESS_FUZZING();
         return nullptr;
       }
@@ -4029,18 +4029,18 @@ BlobParent::CreateFromParams(ParentManag
       if (NS_WARN_IF(!ActorManagerIsSameProcess(aManager))) {
         ASSERT_UNLESS_FUZZING();
         return nullptr;
       }
 
       const SameProcessBlobConstructorParams& params =
         blobParams.get_SameProcessBlobConstructorParams();
 
-      nsRefPtr<FileImpl> blobImpl =
-        dont_AddRef(reinterpret_cast<FileImpl*>(params.addRefedFileImpl()));
+      nsRefPtr<BlobImpl> blobImpl =
+        dont_AddRef(reinterpret_cast<BlobImpl*>(params.addRefedBlobImpl()));
       MOZ_ASSERT(blobImpl);
 
       nsID id;
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(gUUIDGenerator->GenerateUUIDInPlace(&id)));
 
       nsRefPtr<IDTableEntry> idTableEntry =
         IDTableEntry::Create(id, ActorManagerProcessID(aManager), blobImpl);
       MOZ_ASSERT(idTableEntry);
@@ -4105,23 +4105,23 @@ BlobParent::MaybeGetActorFromRemoteBlob(
   BlobParent* actor = aRemoteBlob->GetBlobParent();
   if (actor && actor->GetBackgroundManager() == aManager) {
     return actor;
   }
 
   return nullptr;
 }
 
-already_AddRefed<FileImpl>
+already_AddRefed<BlobImpl>
 BlobParent::GetBlobImpl()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mBlobImpl);
 
-  nsRefPtr<FileImpl> blobImpl;
+  nsRefPtr<BlobImpl> blobImpl;
 
   // Remote blobs are held alive until the first call to GetBlobImpl. Thereafter
   // we only hold a weak reference. Normal blobs are held alive until the actor
   // is destroyed.
   if (mRemoteBlobImpl && mOwnsBlobImpl) {
     blobImpl = dont_AddRef(mBlobImpl);
     mOwnsBlobImpl = false;
   } else {
@@ -4253,17 +4253,17 @@ BlobParent::RecvPBlobStreamConstructor(P
   uint64_t blobLength = mBlobImpl->GetSize(errorResult);
   MOZ_ASSERT(!errorResult.Failed());
 
   if (NS_WARN_IF(aStart + aLength > blobLength)) {
     ASSERT_UNLESS_FUZZING();
     return false;
   }
 
-  nsRefPtr<FileImpl> blobImpl;
+  nsRefPtr<BlobImpl> blobImpl;
 
   if (!aStart && aLength == blobLength) {
     blobImpl = mBlobImpl;
   } else {
     nsString type;
     mBlobImpl->GetType(type);
 
     blobImpl = mBlobImpl->CreateSlice(aStart, aLength, type, errorResult);
@@ -4520,17 +4520,17 @@ BlobParent::RecvGetFilePath(nsString* aF
 
 /*******************************************************************************
  * BlobParent::IDTableEntry
  ******************************************************************************/
 
 BlobParent::
 IDTableEntry::IDTableEntry(const nsID& aID,
                            intptr_t aProcessID,
-                           FileImpl* aBlobImpl)
+                           BlobImpl* aBlobImpl)
   : mID(aID)
   , mProcessID(aProcessID)
   , mBlobImpl(aBlobImpl)
 {
   MOZ_ASSERT(aBlobImpl);
 }
 
 BlobParent::
@@ -4552,17 +4552,17 @@ IDTableEntry::~IDTableEntry()
   }
 }
 
 // static
 already_AddRefed<BlobParent::IDTableEntry>
 BlobParent::
 IDTableEntry::GetOrCreateInternal(const nsID& aID,
                                   intptr_t aProcessID,
-                                  FileImpl* aBlobImpl,
+                                  BlobImpl* aBlobImpl,
                                   bool aMayCreate,
                                   bool aMayGet,
                                   bool aIgnoreProcessID)
 {
   MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
   MOZ_ASSERT(sIDTableMutex);
   sIDTableMutex->AssertNotCurrentThreadOwns();
 
@@ -4577,17 +4577,17 @@ IDTableEntry::GetOrCreateInternal(const 
       }
 
       sIDTable = new IDTable();
     }
 
     entry = sIDTable->Get(aID);
 
     if (entry) {
-      MOZ_ASSERT_IF(aBlobImpl, entry->BlobImpl() == aBlobImpl);
+      MOZ_ASSERT_IF(aBlobImpl, entry->GetBlobImpl() == aBlobImpl);
 
       if (NS_WARN_IF(!aMayGet)) {
         return nullptr;
       }
 
       if (!aIgnoreProcessID && NS_WARN_IF(entry->mProcessID != aProcessID)) {
         return nullptr;
       }
--- a/dom/ipc/BlobChild.h
+++ b/dom/ipc/BlobChild.h
@@ -20,33 +20,33 @@ namespace mozilla {
 namespace ipc {
 
 class PBackgroundChild;
 
 } // namespace ipc
 
 namespace dom {
 
+class BlobImpl;
 class ContentChild;
-class FileImpl;
 class nsIContentChild;
 class PBlobStreamChild;
 
 class BlobChild final
   : public PBlobChild
 {
   typedef mozilla::ipc::PBackgroundChild PBackgroundChild;
 
   class RemoteBlobImpl;
   friend class RemoteBlobImpl;
 
   class RemoteBlobSliceImpl;
   friend class RemoteBlobSliceImpl;
 
-  FileImpl* mBlobImpl;
+  BlobImpl* mBlobImpl;
   RemoteBlobImpl* mRemoteBlobImpl;
 
   // One of these will be null and the other non-null.
   PBackgroundChild* mBackgroundManager;
   nsCOMPtr<nsIContentChild> mContentManager;
 
   nsCOMPtr<nsIEventTarget> mEventTarget;
 
@@ -57,20 +57,20 @@ class BlobChild final
 public:
   class FriendKey;
 
   static void
   Startup(const FriendKey& aKey);
 
   // These create functions are called on the sending side.
   static BlobChild*
-  GetOrCreate(nsIContentChild* aManager, FileImpl* aBlobImpl);
+  GetOrCreate(nsIContentChild* aManager, BlobImpl* aBlobImpl);
 
   static BlobChild*
-  GetOrCreate(PBackgroundChild* aManager, FileImpl* aBlobImpl);
+  GetOrCreate(PBackgroundChild* aManager, BlobImpl* aBlobImpl);
 
   // These create functions are called on the receiving side.
   static BlobChild*
   Create(nsIContentChild* aManager, const ChildBlobConstructorParams& aParams);
 
   static BlobChild*
   Create(PBackgroundChild* aManager,
          const ChildBlobConstructorParams& aParams);
@@ -97,21 +97,21 @@ public:
   GetContentManager() const
   {
     return mContentManager;
   }
 
   const nsID&
   ParentID() const;
 
-  // Get the FileImpl associated with this actor. This may always be called
+  // Get the BlobImpl associated with this actor. This may always be called
   // on the sending side. It may also be called on the receiving side unless
   // this is a "mystery" blob that has not yet received a SetMysteryBlobInfo()
   // call.
-  already_AddRefed<FileImpl>
+  already_AddRefed<BlobImpl>
   GetBlobImpl();
 
   // Use this for files.
   bool
   SetMysteryBlobInfo(const nsString& aName,
                      const nsString& aContentType,
                      uint64_t aLength,
                      int64_t aLastModifiedDate);
@@ -125,23 +125,23 @@ public:
 #ifdef DEBUG
   ;
 #else
   { }
 #endif
 
 private:
   // These constructors are called on the sending side.
-  BlobChild(nsIContentChild* aManager, FileImpl* aBlobImpl);
+  BlobChild(nsIContentChild* aManager, BlobImpl* aBlobImpl);
 
-  BlobChild(PBackgroundChild* aManager, FileImpl* aBlobImpl);
+  BlobChild(PBackgroundChild* aManager, BlobImpl* aBlobImpl);
 
   BlobChild(nsIContentChild* aManager, BlobChild* aOther);
 
-  BlobChild(PBackgroundChild* aManager, BlobChild* aOther, FileImpl* aBlobImpl);
+  BlobChild(PBackgroundChild* aManager, BlobChild* aOther, BlobImpl* aBlobImpl);
 
   // These constructors are called on the receiving side.
   BlobChild(nsIContentChild* aManager,
             const ChildBlobConstructorParams& aParams);
 
   BlobChild(PBackgroundChild* aManager,
             const ChildBlobConstructorParams& aParams);
 
@@ -153,51 +153,51 @@ private:
   BlobChild(PBackgroundChild* aManager,
             const nsID& aParentID,
             RemoteBlobSliceImpl* aRemoteBlobSliceImpl);
 
   // Only called by Destroy().
   ~BlobChild();
 
   void
-  CommonInit(FileImpl* aBlobImpl);
+  CommonInit(BlobImpl* aBlobImpl);
 
   void
-  CommonInit(BlobChild* aOther, FileImpl* aBlobImpl);
+  CommonInit(BlobChild* aOther, BlobImpl* aBlobImpl);
 
   void
   CommonInit(const ChildBlobConstructorParams& aParams);
 
   void
   CommonInit(const nsID& aParentID, RemoteBlobImpl* aRemoteBlobImpl);
 
   template <class ChildManagerType>
   static BlobChild*
-  GetOrCreateFromImpl(ChildManagerType* aManager, FileImpl* aBlobImpl);
+  GetOrCreateFromImpl(ChildManagerType* aManager, BlobImpl* aBlobImpl);
 
   template <class ChildManagerType>
   static BlobChild*
   CreateFromParams(ChildManagerType* aManager,
                    const ChildBlobConstructorParams& aParams);
 
   template <class ChildManagerType>
   static BlobChild*
   SendSliceConstructor(ChildManagerType* aManager,
                        RemoteBlobSliceImpl* aRemoteBlobSliceImpl,
                        const ParentBlobConstructorParams& aParams);
 
   static BlobChild*
   MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
                               nsIContentChild* aManager,
-                              FileImpl* aBlobImpl);
+                              BlobImpl* aBlobImpl);
 
   static BlobChild*
   MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
                               PBackgroundChild* aManager,
-                              FileImpl* aBlobImpl);
+                              BlobImpl* aBlobImpl);
 
   void
   NoteDyingRemoteBlobImpl();
 
   nsIEventTarget*
   EventTarget() const
   {
     return mEventTarget;
--- a/dom/ipc/BlobParent.h
+++ b/dom/ipc/BlobParent.h
@@ -29,17 +29,17 @@ namespace ipc {
 
 class PBackgroundParent;
 
 } // namespace ipc
 
 namespace dom {
 
 class ContentParent;
-class FileImpl;
+class BlobImpl;
 class nsIContentParent;
 class PBlobStreamParent;
 
 class BlobParent final
   : public PBlobParent
 {
   typedef mozilla::ipc::PBackgroundParent PBackgroundParent;
 
@@ -51,17 +51,17 @@ class BlobParent final
 
   class RemoteBlobImpl;
 
   struct CreateBlobImplMetadata;
 
   static StaticAutoPtr<IDTable> sIDTable;
   static StaticAutoPtr<Mutex> sIDTableMutex;
 
-  FileImpl* mBlobImpl;
+  BlobImpl* mBlobImpl;
   RemoteBlobImpl* mRemoteBlobImpl;
 
   // One of these will be null and the other non-null.
   PBackgroundParent* mBackgroundManager;
   nsCOMPtr<nsIContentParent> mContentManager;
 
   nsCOMPtr<nsIEventTarget> mEventTarget;
 
@@ -81,37 +81,37 @@ class BlobParent final
 public:
   class FriendKey;
 
   static void
   Startup(const FriendKey& aKey);
 
   // These create functions are called on the sending side.
   static BlobParent*
-  GetOrCreate(nsIContentParent* aManager, FileImpl* aBlobImpl);
+  GetOrCreate(nsIContentParent* aManager, BlobImpl* aBlobImpl);
 
   static BlobParent*
-  GetOrCreate(PBackgroundParent* aManager, FileImpl* aBlobImpl);
+  GetOrCreate(PBackgroundParent* aManager, BlobImpl* aBlobImpl);
 
   // These create functions are called on the receiving side.
   static BlobParent*
   Create(nsIContentParent* aManager,
          const ParentBlobConstructorParams& aParams);
 
   static BlobParent*
   Create(PBackgroundParent* aManager,
          const ParentBlobConstructorParams& aParams);
 
   static void
   Destroy(PBlobParent* aActor)
   {
     delete static_cast<BlobParent*>(aActor);
   }
 
-  static already_AddRefed<FileImpl>
+  static already_AddRefed<BlobImpl>
   GetBlobImplForID(const nsID& aID);
 
   bool
   HasManager() const
   {
     return mBackgroundManager || mContentManager;
   }
 
@@ -122,18 +122,18 @@ public:
   }
 
   nsIContentParent*
   GetContentManager() const
   {
     return mContentManager;
   }
 
-  // Get the FileImpl associated with this actor.
-  already_AddRefed<FileImpl>
+  // Get the BlobImpl associated with this actor.
+  already_AddRefed<BlobImpl>
   GetBlobImpl();
 
   void
   AssertIsOnOwningThread() const
 #ifdef DEBUG
   ;
 #else
   { }
@@ -142,36 +142,36 @@ public:
 private:
   // These constructors are called on the sending side.
   BlobParent(nsIContentParent* aManager, IDTableEntry* aIDTableEntry);
 
   BlobParent(PBackgroundParent* aManager, IDTableEntry* aIDTableEntry);
 
   // These constructors are called on the receiving side.
   BlobParent(nsIContentParent* aManager,
-             FileImpl* aBlobImpl,
+             BlobImpl* aBlobImpl,
              IDTableEntry* aIDTableEntry);
 
   BlobParent(PBackgroundParent* aManager,
-             FileImpl* aBlobImpl,
+             BlobImpl* aBlobImpl,
              IDTableEntry* aIDTableEntry);
 
   // Only destroyed by BackgroundParentImpl and ContentParent.
   ~BlobParent();
 
   void
   CommonInit(IDTableEntry* aIDTableEntry);
 
   void
-  CommonInit(FileImpl* aBlobImpl, IDTableEntry* aIDTableEntry);
+  CommonInit(BlobImpl* aBlobImpl, IDTableEntry* aIDTableEntry);
 
   template <class ParentManagerType>
   static BlobParent*
   GetOrCreateFromImpl(ParentManagerType* aManager,
-                      FileImpl* aBlobImpl);
+                      BlobImpl* aBlobImpl);
 
   template <class ParentManagerType>
   static BlobParent*
   CreateFromParams(ParentManagerType* aManager,
                    const ParentBlobConstructorParams& aParams);
 
   template <class ParentManagerType>
   static BlobParent*
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2927,18 +2927,27 @@ ContentChild::RecvInvokeDragSession(nsTA
           nsCOMPtr<nsIWritableVariant> variant =
              do_CreateInstance(NS_VARIANT_CONTRACTID);
           NS_ENSURE_TRUE(variant, false);
           if (item.data().type() == IPCDataTransferData::TnsString) {
             const nsString& data = item.data().get_nsString();
             variant->SetAsAString(data);
           } else if (item.data().type() == IPCDataTransferData::TPBlobChild) {
             BlobChild* blob = static_cast<BlobChild*>(item.data().get_PBlobChild());
-            nsRefPtr<FileImpl> fileImpl = blob->GetBlobImpl();
-            variant->SetAsISupports(fileImpl);
+            nsRefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
+            nsString path;
+            ErrorResult result;
+            blobImpl->GetMozFullPathInternal(path, result);
+            if (result.Failed()) {
+              variant->SetAsISupports(blobImpl);
+            } else {
+              nsCOMPtr<nsIFile> file;
+              NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true, getter_AddRefs(file));
+              variant->SetAsISupports(file);
+            }
           } else {
             continue;
           }
           dataTransfer->SetDataWithPrincipal(NS_ConvertUTF8toUTF16(item.flavor()),
                                              variant, i,
                                              nsContentUtils::GetSystemPrincipal());
         }
       }
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -90,19 +90,19 @@ struct MysteryBlobConstructorParams
 struct KnownBlobConstructorParams
 {
   nsID id;
 };
 
 // This may only be used for same-process inter-thread communication!
 struct SameProcessBlobConstructorParams
 {
-  // This member should be reinterpret_cast'd to mozilla::dom::FileImpl. It
+  // This member should be reinterpret_cast'd to mozilla::dom::BlobImpl. It
   // carries a reference.
-  intptr_t addRefedFileImpl;
+  intptr_t addRefedBlobImpl;
 };
 
 union AnyBlobConstructorParams
 {
   // These types may be sent to/from parent and child.
   NormalBlobConstructorParams;
   FileBlobConstructorParams;
   SameProcessBlobConstructorParams;
--- a/dom/ipc/FilePickerParent.cpp
+++ b/dom/ipc/FilePickerParent.cpp
@@ -50,20 +50,20 @@ FilePickerParent::~FilePickerParent()
 // process. This runnable stat()s the file off the main thread.
 //
 // We run code in three places:
 // 1. The main thread calls Dispatch() to start the runnable.
 // 2. The stream transport thread stat()s the file in Run() and then dispatches
 // the same runnable on the main thread.
 // 3. The main thread sends the results over IPC.
 FilePickerParent::FileSizeAndDateRunnable::FileSizeAndDateRunnable(FilePickerParent *aFPParent,
-                                                                   nsTArray<nsRefPtr<FileImpl>>& aFiles)
+                                                                   nsTArray<nsRefPtr<BlobImpl>>& aBlobs)
  : mFilePickerParent(aFPParent)
 {
-  mFiles.SwapElements(aFiles);
+  mBlobs.SwapElements(aBlobs);
 }
 
 bool
 FilePickerParent::FileSizeAndDateRunnable::Dispatch()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mEventTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
@@ -77,26 +77,26 @@ FilePickerParent::FileSizeAndDateRunnabl
 
 NS_IMETHODIMP
 FilePickerParent::FileSizeAndDateRunnable::Run()
 {
   // If we're on the main thread, then that means we're done. Just send the
   // results.
   if (NS_IsMainThread()) {
     if (mFilePickerParent) {
-      mFilePickerParent->SendFiles(mFiles);
+      mFilePickerParent->SendFiles(mBlobs);
     }
     return NS_OK;
   }
 
   // We're not on the main thread, so do the stat().
-  for (unsigned i = 0; i < mFiles.Length(); i++) {
+  for (unsigned i = 0; i < mBlobs.Length(); i++) {
     ErrorResult rv;
-    mFiles[i]->GetSize(rv);
-    mFiles[i]->GetLastModified(rv);
+    mBlobs[i]->GetSize(rv);
+    mBlobs[i]->GetLastModified(rv);
   }
 
   // Dispatch ourselves back on the main thread.
   if (NS_FAILED(NS_DispatchToMainThread(this))) {
     // It's hard to see how we can recover gracefully in this case. The child
     // process is waiting for an IPC, but that can only happen on the main
     // thread.
     MOZ_CRASH();
@@ -106,71 +106,70 @@ FilePickerParent::FileSizeAndDateRunnabl
 
 void
 FilePickerParent::FileSizeAndDateRunnable::Destroy()
 {
   mFilePickerParent = nullptr;
 }
 
 void
-FilePickerParent::SendFiles(const nsTArray<nsRefPtr<FileImpl>>& aFiles)
+FilePickerParent::SendFiles(const nsTArray<nsRefPtr<BlobImpl>>& aBlobs)
 {
   nsIContentParent* parent = TabParent::GetFrom(Manager())->Manager();
-  InfallibleTArray<PBlobParent*> files;
+  InfallibleTArray<PBlobParent*> blobs;
 
-  for (unsigned i = 0; i < aFiles.Length(); i++) {
-    nsRefPtr<File> file = new File(nullptr, aFiles[i]);
-    BlobParent* blob = parent->GetOrCreateActorForBlob(file);
-    if (blob) {
-      files.AppendElement(blob);
+  for (unsigned i = 0; i < aBlobs.Length(); i++) {
+    BlobParent* blobParent = parent->GetOrCreateActorForBlobImpl(aBlobs[i]);
+    if (blobParent) {
+      blobs.AppendElement(blobParent);
     }
   }
 
-  InputFiles infiles;
-  infiles.filesParent().SwapElements(files);
-  unused << Send__delete__(this, infiles, mResult);
+  InputFiles inblobs;
+  inblobs.blobsParent().SwapElements(blobs);
+  unused << Send__delete__(this, inblobs, mResult);
 }
 
 void
 FilePickerParent::Done(int16_t aResult)
 {
   mResult = aResult;
 
   if (mResult != nsIFilePicker::returnOK) {
     unused << Send__delete__(this, void_t(), mResult);
     return;
   }
 
-  nsTArray<nsRefPtr<FileImpl>> files;
+  nsTArray<nsRefPtr<BlobImpl>> blobs;
   if (mMode == nsIFilePicker::modeOpenMultiple) {
     nsCOMPtr<nsISimpleEnumerator> iter;
     NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
 
     nsCOMPtr<nsISupports> supports;
     bool loop = true;
     while (NS_SUCCEEDED(iter->HasMoreElements(&loop)) && loop) {
       iter->GetNext(getter_AddRefs(supports));
       if (supports) {
         nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
 
-        nsRefPtr<FileImpl> fileimpl = new FileImplFile(file);
-        files.AppendElement(fileimpl);
+        nsRefPtr<BlobImpl> blobimpl = new BlobImplFile(file);
+        blobs.AppendElement(blobimpl);
       }
     }
   } else {
     nsCOMPtr<nsIFile> file;
     mFilePicker->GetFile(getter_AddRefs(file));
     if (file) {
-      nsRefPtr<FileImpl> fileimpl = new FileImplFile(file);
-      files.AppendElement(fileimpl);
+      nsRefPtr<BlobImpl> blobimpl = new BlobImplFile(file);
+      blobs.AppendElement(blobimpl);
     }
   }
 
   MOZ_ASSERT(!mRunnable);
-  mRunnable = new FileSizeAndDateRunnable(this, files);
+  mRunnable = new FileSizeAndDateRunnable(this, blobs);
   if (!mRunnable->Dispatch()) {
     unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
   }
 }
 
 bool
 FilePickerParent::CreateFilePicker()
 {
--- a/dom/ipc/FilePickerParent.h
+++ b/dom/ipc/FilePickerParent.h
@@ -25,17 +25,17 @@ class FilePickerParent : public PFilePic
                    const int16_t& aMode)
   : mTitle(aTitle)
   , mMode(aMode)
   {}
 
   virtual ~FilePickerParent();
 
   void Done(int16_t aResult);
-  void SendFiles(const nsTArray<nsRefPtr<FileImpl>>& aDomfiles);
+  void SendFiles(const nsTArray<nsRefPtr<BlobImpl>>& aDomBlobs);
 
   virtual bool RecvOpen(const int16_t& aSelectedType,
                         const bool& aAddToRecentDocs,
                         const nsString& aDefaultFile,
                         const nsString& aDefaultExtension,
                         InfallibleTArray<nsString>&& aFilters,
                         InfallibleTArray<nsString>&& aFilterNames,
                         const nsString& aDisplayDirectory) override;
@@ -60,21 +60,21 @@ class FilePickerParent : public PFilePic
   };
 
  private:
   bool CreateFilePicker();
 
   class FileSizeAndDateRunnable : public nsRunnable
   {
     FilePickerParent* mFilePickerParent;
-    nsTArray<nsRefPtr<FileImpl>> mFiles;
+    nsTArray<nsRefPtr<BlobImpl>> mBlobs;
     nsCOMPtr<nsIEventTarget> mEventTarget;
 
   public:
-    FileSizeAndDateRunnable(FilePickerParent *aFPParent, nsTArray<nsRefPtr<FileImpl>>& aFiles);
+    FileSizeAndDateRunnable(FilePickerParent *aFPParent, nsTArray<nsRefPtr<BlobImpl>>& aBlobs);
     bool Dispatch();
     NS_IMETHOD Run();
     void Destroy();
   };
 
   nsRefPtr<FileSizeAndDateRunnable> mRunnable;
   nsRefPtr<FilePickerShownCallback> mCallback;
   nsCOMPtr<nsIFilePicker> mFilePicker;
--- a/dom/ipc/PFilePicker.ipdl
+++ b/dom/ipc/PFilePicker.ipdl
@@ -9,17 +9,17 @@ include protocol PBrowser;
 
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 struct InputFiles
 {
-  PBlob[] files;
+  PBlob[] blobs;
 };
 
 union MaybeInputFiles
 {
   InputFiles;
   void_t;
 };
 
--- a/dom/ipc/StructuredCloneUtils.cpp
+++ b/dom/ipc/StructuredCloneUtils.cpp
@@ -46,33 +46,33 @@ Read(JSContext* aCx, JSStructuredCloneRe
     // nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
     // called because the static analysis thinks dereferencing XPCOM objects
     // can GC (because in some cases it can!), and a return statement with a
     // JSObject* type means that JSObject* is on the stack as a raw pointer
     // while destructors are running.
     JS::Rooted<JS::Value> val(aCx);
     {
       MOZ_ASSERT(aData < closure->mBlobs.Length());
-      nsRefPtr<File> blob = closure->mBlobs[aData];
+      nsRefPtr<Blob> blob = closure->mBlobs[aData];
 
 #ifdef DEBUG
       {
-        // File should not be mutable.
+        // Blob should not be mutable.
         bool isMutable;
         MOZ_ASSERT(NS_SUCCEEDED(blob->GetMutable(&isMutable)));
         MOZ_ASSERT(!isMutable);
       }
 #endif
 
       // Let's create a new blob with the correct parent.
       nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
       MOZ_ASSERT(global);
 
-      nsRefPtr<File> newBlob = new File(global, blob->Impl());
-      if (!GetOrCreateDOMReflector(aCx, newBlob, &val)) {
+      nsRefPtr<Blob> newBlob = Blob::Create(global, blob->Impl());
+      if (!ToJSValue(aCx, newBlob, &val)) {
         return nullptr;
       }
     }
 
     return &val.toObject();
   }
 
   return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr);
@@ -84,17 +84,17 @@ Write(JSContext* aCx, JSStructuredCloneW
 {
   MOZ_ASSERT(aClosure);
 
   StructuredCloneClosure* closure =
     static_cast<StructuredCloneClosure*>(aClosure);
 
   // See if the wrapped native is a File/Blob.
   {
-    File* blob = nullptr;
+    Blob* blob = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
         NS_SUCCEEDED(blob->SetMutable(false)) &&
         JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
                            closure->mBlobs.Length())) {
       closure->mBlobs.AppendElement(blob);
       return true;
     }
   }
--- a/dom/ipc/StructuredCloneUtils.h
+++ b/dom/ipc/StructuredCloneUtils.h
@@ -14,17 +14,17 @@
 #include "js/StructuredClone.h"
 
 namespace mozilla {
 namespace dom {
 
 struct
 StructuredCloneClosure
 {
-  nsTArray<nsRefPtr<File>> mBlobs;
+  nsTArray<nsRefPtr<Blob>> mBlobs;
 };
 
 struct
 StructuredCloneData
 {
   StructuredCloneData() : mData(nullptr), mDataLength(0) {}
   uint64_t* mData;
   size_t mDataLength;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -182,17 +182,17 @@ private:
 
             // It's probably safer to take the main thread IO hit here rather
             // than leak a file descriptor.
             CloseFile();
         }
     }
 
     // Helper method to avoid gnarly control flow for failures.
-    void OpenFileImpl()
+    void OpenBlobImpl()
     {
         MOZ_ASSERT(!NS_IsMainThread());
         MOZ_ASSERT(!mFD);
 
         nsCOMPtr<nsIFile> file;
         nsresult rv = NS_NewLocalFile(mPath, false, getter_AddRefs(file));
         NS_ENSURE_SUCCESS_VOID(rv);
 
@@ -202,17 +202,17 @@ private:
 
         mFD = fd;
     }
 
     void OpenFile()
     {
         MOZ_ASSERT(!NS_IsMainThread());
 
-        OpenFileImpl();
+        OpenBlobImpl();
 
         if (NS_FAILED(NS_DispatchToMainThread(this))) {
             NS_WARNING("Failed to dispatch to main thread!");
 
             // Intentionally leak the runnable (but not the fd) rather
             // than crash when trying to release a main thread object
             // off the main thread.
             mTabParent.forget();
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -520,17 +520,17 @@ private:
     bool mSendOfflineStatus;
 
     uint32_t mChromeFlags;
 
     struct DataTransferItem
     {
       nsCString mFlavor;
       nsString mStringData;
-      nsRefPtr<mozilla::dom::FileImpl> mBlobData;
+      nsRefPtr<mozilla::dom::BlobImpl> mBlobData;
       enum DataType
       {
         eString,
         eBlob
       };
       DataType mType;
     };
     nsTArray<nsTArray<DataTransferItem>> mInitialDataTransferItems;
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -88,25 +88,34 @@ nsIContentChild::AllocPBlobChild(const B
 bool
 nsIContentChild::DeallocPBlobChild(PBlobChild* aActor)
 {
   BlobChild::Destroy(aActor);
   return true;
 }
 
 BlobChild*
-nsIContentChild::GetOrCreateActorForBlob(File* aBlob)
+nsIContentChild::GetOrCreateActorForBlob(Blob* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
 
-  nsRefPtr<FileImpl> blobImpl = aBlob->Impl();
+  nsRefPtr<BlobImpl> blobImpl = aBlob->Impl();
   MOZ_ASSERT(blobImpl);
 
-  BlobChild* actor = BlobChild::GetOrCreate(this, blobImpl);
+  return GetOrCreateActorForBlobImpl(blobImpl);
+}
+
+BlobChild*
+nsIContentChild::GetOrCreateActorForBlobImpl(BlobImpl* aImpl)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aImpl);
+
+  BlobChild* actor = BlobChild::GetOrCreate(this, aImpl);
   NS_ENSURE_TRUE(actor, nullptr);
 
   return actor;
 }
 
 bool
 nsIContentChild::RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
--- a/dom/ipc/nsIContentChild.h
+++ b/dom/ipc/nsIContentChild.h
@@ -27,31 +27,33 @@ namespace mozilla {
 
 namespace jsipc {
 class PJavaScriptChild;
 class CpowEntry;
 } // jsipc
 
 namespace dom {
 
+class Blob;
 class BlobChild;
+class BlobImpl;
 class BlobConstructorParams;
 class ClonedMessageData;
-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(File* aBlob);
+  BlobChild* GetOrCreateActorForBlob(Blob* aBlob);
+  BlobChild* GetOrCreateActorForBlobImpl(BlobImpl* aImpl);
 
   virtual PBlobChild* SendPBlobConstructor(
     PBlobChild* aActor,
     const BlobConstructorParams& aParams) = 0;
 
   virtual bool
   SendPBrowserConstructor(PBrowserChild* aActor,
                           const TabId& aTabId,
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -154,25 +154,34 @@ nsIContentParent::AllocPBlobParent(const
 bool
 nsIContentParent::DeallocPBlobParent(PBlobParent* aActor)
 {
   BlobParent::Destroy(aActor);
   return true;
 }
 
 BlobParent*
-nsIContentParent::GetOrCreateActorForBlob(File* aBlob)
+nsIContentParent::GetOrCreateActorForBlob(Blob* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
 
-  nsRefPtr<FileImpl> blobImpl = aBlob->Impl();
+  nsRefPtr<BlobImpl> blobImpl = aBlob->Impl();
   MOZ_ASSERT(blobImpl);
 
-  BlobParent* actor = BlobParent::GetOrCreate(this, blobImpl);
+  return GetOrCreateActorForBlobImpl(blobImpl);
+}
+
+BlobParent*
+nsIContentParent::GetOrCreateActorForBlobImpl(BlobImpl* aImpl)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aImpl);
+
+  BlobParent* actor = BlobParent::GetOrCreate(this, aImpl);
   NS_ENSURE_TRUE(actor, nullptr);
 
   return actor;
 }
 
 bool
 nsIContentParent::RecvSyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -28,36 +28,38 @@ namespace mozilla {
 
 namespace jsipc {
 class PJavaScriptParent;
 class CpowEntry;
 } // namespace jsipc
 
 namespace dom {
 
+class Blob;
 class BlobConstructorParams;
+class BlobImpl;
 class BlobParent;
 class ContentParent;
-class File;
 class IPCTabContext;
 class PBlobParent;
 class PBrowserParent;
 
 class nsIContentParent : public nsISupports
                        , public mozilla::dom::ipc::MessageManagerCallback
                        , public CPOWManagerGetter
 {
     typedef mozilla::OwningSerializedStructuredCloneBuffer OwningSerializedStructuredCloneBuffer;
 
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTPARENT_IID)
 
   nsIContentParent();
 
-  BlobParent* GetOrCreateActorForBlob(File* aBlob);
+  BlobParent* GetOrCreateActorForBlob(Blob* aBlob);
+  BlobParent* GetOrCreateActorForBlobImpl(BlobImpl* aImpl);
 
   virtual ContentParentId ChildID() = 0;
   virtual bool IsForApp() = 0;
   virtual bool IsForBrowser() = 0;
 
   MOZ_WARN_UNUSED_RESULT
   virtual PBlobParent* SendPBlobConstructor(
     PBlobParent* aActor,
--- a/dom/media/EncodedBufferCache.cpp
+++ b/dom/media/EncodedBufferCache.cpp
@@ -34,41 +34,41 @@ EncodedBufferCache::AppendBuffer(nsTArra
         NS_WARNING("Failed to write media cache block!");
       }
     }
     mEncodedBuffers.Clear();
   }
 
 }
 
-already_AddRefed<dom::File>
+already_AddRefed<dom::Blob>
 EncodedBufferCache::ExtractBlob(nsISupports* aParent,
                                 const nsAString &aContentType)
 {
   MutexAutoLock lock(mMutex);
-  nsRefPtr<dom::File> blob;
+  nsRefPtr<dom::Blob> blob;
   if (mTempFileEnabled) {
     // generate new temporary file to write
-    blob = dom::File::CreateTemporaryFileBlob(aParent, mFD, 0, mDataSize,
-                                              aContentType);
+    blob = dom::Blob::CreateTemporaryBlob(aParent, mFD, 0, mDataSize,
+                                          aContentType);
     // fallback to memory blob
     mTempFileEnabled = false;
     mDataSize = 0;
     mFD = nullptr;
   } else {
     void* blobData = malloc(mDataSize);
     NS_ASSERTION(blobData, "out of memory!!");
 
     if (blobData) {
       for (uint32_t i = 0, offset = 0; i < mEncodedBuffers.Length(); i++) {
         memcpy((uint8_t*)blobData + offset, mEncodedBuffers.ElementAt(i).Elements(),
                mEncodedBuffers.ElementAt(i).Length());
         offset += mEncodedBuffers.ElementAt(i).Length();
       }
-      blob = dom::File::CreateMemoryFile(aParent, blobData, mDataSize,
+      blob = dom::Blob::CreateMemoryBlob(aParent, blobData, mDataSize,
                                          aContentType);
       mEncodedBuffers.Clear();
     } else
       return nullptr;
   }
   mDataSize = 0;
   return blob.forget();
 }
--- a/dom/media/EncodedBufferCache.h
+++ b/dom/media/EncodedBufferCache.h
@@ -11,17 +11,17 @@
 #include "nsTArray.h"
 #include "mozilla/Mutex.h"
 
 struct PRFileDesc;
 
 namespace mozilla {
 
 namespace dom {
-class File;
+class Blob;
 }
 
 /**
  * Data is moved into a temporary file when it grows beyond
  * the maximal size passed in the Init function.
  * The AppendBuffer and ExtractBlob methods are thread-safe and can be called on
  * different threads at the same time.
  */
@@ -36,17 +36,17 @@ public:
     mTempFileEnabled(false) { }
   ~EncodedBufferCache()
   {
   }
   // Append buffers in cache, check if the queue is too large then switch to write buffer to file system
   // aBuf will append to mEncodedBuffers or temporary File, aBuf also be cleared
   void AppendBuffer(nsTArray<uint8_t> & aBuf);
   // Read all buffer from memory or file System, also Remove the temporary file or clean the buffers in memory.
-  already_AddRefed<dom::File> ExtractBlob(nsISupports* aParent, const nsAString &aContentType);
+  already_AddRefed<dom::Blob> ExtractBlob(nsISupports* aParent, const nsAString &aContentType);
 
 private:
   //array for storing the encoded data.
   nsTArray<nsTArray<uint8_t> > mEncodedBuffers;
   // File handle for the temporary file
   PRFileDesc* mFD;
   // Used to protect the mEncodedBuffer for avoiding AppendBuffer/Consume on different thread at the same time.
   Mutex mMutex;
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -1012,17 +1012,17 @@ MediaRecorder::CreateAndDispatchBlobEven
     nsRefPtr<nsIDOMBlob> blob = aBlob;
     return NS_ERROR_DOM_SECURITY_ERR;
   }
   BlobEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
 
   nsCOMPtr<nsIDOMBlob> blob = aBlob;
-  init.mData = static_cast<File*>(blob.get());
+  init.mData = static_cast<Blob*>(blob.get());
 
   nsRefPtr<BlobEvent> event =
     BlobEvent::Constructor(this,
                            NS_LITERAL_STRING("dataavailable"),
                            init);
   event->SetTrusted(true);
   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -909,23 +909,42 @@ MediaStreamGraphImpl::MarkStreamBlocking
 }
 
 void
 MediaStreamGraphImpl::RecomputeBlockingAt(const nsTArray<MediaStream*>& aStreams,
                                           GraphTime aTime,
                                           GraphTime aEndBlockingDecisions,
                                           GraphTime* aEnd)
 {
+  class MOZ_STACK_CLASS AfterLoop
+  {
+  public:
+    AfterLoop(MediaStream* aStream, GraphTime& aTime)
+      : mStream(aStream)
+      , mTime(aTime)
+    {}
+
+    ~AfterLoop()
+    {
+      mStream->mBlocked.SetAtAndAfter(mTime, mStream->mBlockInThisPhase);
+    }
+
+  private:
+    MediaStream* mStream;
+    GraphTime& mTime;
+  };
+
   for (uint32_t i = 0; i < aStreams.Length(); ++i) {
     MediaStream* stream = aStreams[i];
     stream->mBlockInThisPhase = false;
   }
 
   for (uint32_t i = 0; i < aStreams.Length(); ++i) {
     MediaStream* stream = aStreams[i];
+    AfterLoop al(stream, aTime);
 
     if (stream->mFinished) {
       GraphTime endTime = StreamTimeToGraphTime(stream,
          stream->GetStreamBuffer().GetAllTracksEnd());
       if (endTime <= aTime) {
         STREAM_LOG(PR_LOG_DEBUG+1, ("MediaStream %p is blocked due to being finished", stream));
         // We'll block indefinitely
         MarkStreamBlocking(stream);
@@ -951,22 +970,18 @@ MediaStreamGraphImpl::RecomputeBlockingA
     bool underrun = WillUnderrun(stream, aTime, aEndBlockingDecisions, aEnd);
     if (underrun) {
       // We'll block indefinitely
       MarkStreamBlocking(stream);
       *aEnd = std::min(*aEnd, aEndBlockingDecisions);
       continue;
     }
   }
+
   NS_ASSERTION(*aEnd > aTime, "Failed to advance!");
-
-  for (uint32_t i = 0; i < aStreams.Length(); ++i) {
-    MediaStream* stream = aStreams[i];
-    stream->mBlocked.SetAtAndAfter(aTime, stream->mBlockInThisPhase);
-  }
 }
 
 void
 MediaStreamGraphImpl::NotifyHasCurrentData(MediaStream* aStream)
 {
   if (!aStream->mNotifiedHasCurrentData && aStream->mHasCurrentData) {
     for (uint32_t j = 0; j < aStream->mListeners.Length(); ++j) {
       MediaStreamListener* l = aStream->mListeners[j];
--- a/dom/media/imagecapture/CaptureTask.cpp
+++ b/dom/media/imagecapture/CaptureTask.cpp
@@ -10,28 +10,28 @@
 #include "mozilla/dom/ImageEncoder.h"
 #include "mozilla/dom/VideoStreamTrack.h"
 #include "gfxUtils.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 
 nsresult
-CaptureTask::TaskComplete(already_AddRefed<dom::File> aBlob, nsresult aRv)
+CaptureTask::TaskComplete(already_AddRefed<dom::Blob> aBlob, nsresult aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   DetachStream();
 
   nsresult rv;
-  nsRefPtr<dom::File> blob(aBlob);
+  nsRefPtr<dom::Blob> blob(aBlob);
 
   // We have to set the parent because the blob has been generated with a valid one.
   if (blob) {
-    blob = new dom::File(mImageCapture->GetParentObject(), blob->Impl());
+    blob = dom::Blob::Create(mImageCapture->GetParentObject(), blob->Impl());
   }
 
   if (mPrincipalChanged) {
     aRv = NS_ERROR_DOM_SECURITY_ERR;
     IC_LOG("MediaStream principal should not change during TakePhoto().");
   }
 
   if (NS_SUCCEEDED(aRv)) {
@@ -98,19 +98,19 @@ CaptureTask::NotifyQueuedTrackChanges(Me
   }
 
   // Callback for encoding complete, it calls on main thread.
   class EncodeComplete : public dom::EncodeCompleteCallback
   {
   public:
     explicit EncodeComplete(CaptureTask* aTask) : mTask(aTask) {}
 
-    nsresult ReceiveBlob(already_AddRefed<dom::File> aBlob) override
+    nsresult ReceiveBlob(already_AddRefed<dom::Blob> aBlob) override
     {
-      nsRefPtr<dom::File> blob(aBlob);
+      nsRefPtr<dom::Blob> blob(aBlob);
       mTask->TaskComplete(blob.forget(), NS_OK);
       mTask = nullptr;
       return NS_OK;
     }
 
   protected:
     nsRefPtr<CaptureTask> mTask;
   };
--- a/dom/media/imagecapture/CaptureTask.h
+++ b/dom/media/imagecapture/CaptureTask.h
@@ -8,17 +8,17 @@
 #define CAPTURETASK_H
 
 #include "DOMMediaStream.h"
 #include "MediaStreamGraph.h"
 
 namespace mozilla {
 
 namespace dom {
-class File;
+class Blob;
 class ImageCapture;
 }
 
 /**
  * CaptureTask retrieves image from MediaStream and encodes the image to jpeg in
  * ImageEncoder. The whole procedures start at AttachStream(), it will add this
  * class into MediaStream and retrieves an image in MediaStreamGraph thread.
  * Once the image is retrieved, it will be sent to ImageEncoder and the encoded
@@ -45,17 +45,17 @@ public:
 
   // CaptureTask methods.
 
   // It is called when aBlob is ready to post back to script in company with
   // aRv == NS_OK. If aRv is not NS_OK, it will post an error event to script.
   //
   // Note:
   //   this function should be called on main thread.
-  nsresult TaskComplete(already_AddRefed<dom::File> aBlob, nsresult aRv);
+  nsresult TaskComplete(already_AddRefed<dom::Blob> aBlob, nsresult aRv);
 
   // Add listeners into MediaStream and PrincipalChangeObserver. It should be on
   // main thread only.
   void AttachStream();
 
   // Remove listeners from MediaStream and PrincipalChangeObserver. It should be
   // on main thread only.
   void DetachStream();
--- a/dom/media/imagecapture/ImageCapture.cpp
+++ b/dom/media/imagecapture/ImageCapture.cpp
@@ -97,19 +97,19 @@ ImageCapture::TakePhotoByMediaEngine()
       mStream->AddPrincipalChangeObserver(this);
     }
 
     void PrincipalChanged(DOMMediaStream* aMediaStream) override
     {
       mPrincipalChanged = true;
     }
 
-    nsresult PhotoComplete(already_AddRefed<File> aBlob) override
+    nsresult PhotoComplete(already_AddRefed<Blob> aBlob) override
     {
-      nsRefPtr<File> blob = aBlob;
+      nsRefPtr<Blob> blob = aBlob;
 
       if (mPrincipalChanged) {
         return PhotoError(NS_ERROR_DOM_SECURITY_ERR);
       }
       return mImageCapture->PostBlobEvent(blob);
     }
 
     nsresult PhotoError(nsresult aRv) override
@@ -167,17 +167,17 @@ ImageCapture::TakePhoto(ErrorResult& aRe
 
     // It adds itself into MediaStreamGraph, so ImageCapture doesn't need to hold
     // the reference.
     task->AttachStream();
   }
 }
 
 nsresult
-ImageCapture::PostBlobEvent(File* aBlob)
+ImageCapture::PostBlobEvent(Blob* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!CheckPrincipal()) {
     // Media is not same-origin, don't allow the data out.
     return PostErrorEvent(ImageCaptureError::PHOTO_ERROR, NS_ERROR_DOM_SECURITY_ERR);
   }
 
   BlobEventInit init;
--- a/dom/media/imagecapture/ImageCapture.h
+++ b/dom/media/imagecapture/ImageCapture.h
@@ -25,17 +25,17 @@ PRLogModuleInfo* GetICLog();
 #ifndef IC_LOG
 #define IC_LOG(...)
 #endif
 
 #endif // PR_LOGGING
 
 namespace dom {
 
-class File;
+class Blob;
 class VideoStreamTrack;
 
 /**
  *  Implementation of https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-
  *  capture/ImageCapture.html.
  *  The ImageCapture accepts a VideoStreamTrack as input source. The image will
  *  be sent back as a JPG format via Blob event.
  *
@@ -73,17 +73,17 @@ public:
 
   static already_AddRefed<ImageCapture> Constructor(const GlobalObject& aGlobal,
                                                     VideoStreamTrack& aTrack,
                                                     ErrorResult& aRv);
 
   ImageCapture(VideoStreamTrack* aVideoStreamTrack, nsPIDOMWindow* aOwnerWindow);
 
   // Post a Blob event to script.
-  nsresult PostBlobEvent(File* aBlob);
+  nsresult PostBlobEvent(Blob* aBlob);
 
   // Post an error event to script.
   // aErrorCode should be one of error codes defined in ImageCaptureError.h.
   // aReason is the nsresult which maps to a error string in dom/base/domerr.msg.
   nsresult PostErrorEvent(uint16_t aErrorCode, nsresult aReason = NS_OK);
 
   bool CheckPrincipal();
 
--- a/dom/media/test/crashtests/1158427.html
+++ b/dom/media/test/crashtests/1158427.html
@@ -1,18 +1,23 @@
 <!DOCTYPE html>
 <html>
 <head>
 <script>
 
 function boom()
 {
+  dump("before capture\n");
   document.createElement("audio").mozCaptureStreamUntilEnded();
+  dump("before context\n");
   new window.AudioContext();
+  dump("before mozapps\n");
   navigator.mozApps;
+  dump("before gc\n");
   SpecialPowers.forceCC();
+  dump("after gc\n");
 }
 
 </script>
 </head>
 <body onload="boom();"></body>
 </html>
 
--- a/dom/media/webrtc/MediaEngine.h
+++ b/dom/media/webrtc/MediaEngine.h
@@ -1,26 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MEDIAENGINE_H_
 #define MEDIAENGINE_H_
 
 #include "mozilla/RefPtr.h"
-#include "nsIDOMFile.h"
 #include "DOMMediaStream.h"
 #include "MediaStreamGraph.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/dom/VideoStreamTrack.h"
 
 namespace mozilla {
 
 namespace dom {
-class File;
+class Blob;
 }
 
 enum {
   kVideoTrack = 1,
   kAudioTrack = 2,
   kTrackCount
 };
 
@@ -125,17 +124,17 @@ public:
   // Callback interface for TakePhoto(). Either PhotoComplete() or PhotoError()
   // should be called.
   class PhotoCallback {
   public:
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PhotoCallback)
 
     // aBlob is the image captured by MediaEngineSource. It is
     // called on main thread.
-    virtual nsresult PhotoComplete(already_AddRefed<dom::File> aBlob) = 0;
+    virtual nsresult PhotoComplete(already_AddRefed<dom::Blob> aBlob) = 0;
 
     // It is called on main thread. aRv is the error code.
     virtual nsresult PhotoError(nsresult aRv) = 0;
 
   protected:
     virtual ~PhotoCallback() {}
   };
 
--- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
@