Merge m-c to b2g-inbound a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 08 Oct 2014 17:17:46 -0700
changeset 209595 1befba96c7a5a59a8fae9d24ab89528ce61f2b18
parent 209594 250814619d2532498d2e22b086c495abec8b41c9 (current diff)
parent 209460 f0bb13ef0ee488d4ece70467e4e819cb7506f5e3 (diff)
child 209596 bebea3ea07b4ae9472e43dd9c1867581b3256557
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmerge
milestone35.0a1
Merge m-c to b2g-inbound a=merge
content/base/public/nsDOMFile.h
content/base/src/nsDOMBlobBuilder.cpp
content/base/src/nsDOMBlobBuilder.h
content/base/src/nsDOMFile.cpp
dom/workers/File.cpp
dom/workers/File.h
--- a/b2g/components/FilePicker.js
+++ b/b2g/components/FilePicker.js
@@ -176,17 +176,17 @@ FilePicker.prototype = {
 
     let data = message.data;
     if (!data.success || !data.result.blob) {
       this.fireError();
       return;
     }
 
     // The name to be shown can be part of the message, or can be taken from
-    // the DOMFile (if the blob is a DOMFile).
+    // the File (if the blob is a File).
     let name = data.result.name;
     if (!name &&
         (data.result.blob instanceof this.mParent.File) &&
         data.result.blob.name) {
       name = data.result.blob.name;
     }
 
     // Let's try to remove the full path and take just the filename.
@@ -202,19 +202,19 @@ FilePicker.prototype = {
         let mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
         let mimeInfo = mimeSvc.getFromTypeAndExtension(data.result.blob.type, '');
         if (mimeInfo) {
           name += '.' + mimeInfo.primaryExtension;
         }
       }
     }
 
-    let file = new this.mParent.File(data.result.blob,
-                                     { name: name,
-                                       type: data.result.blob.type });
+    let file = new this.mParent.File([data.result.blob],
+                                     name,
+                                     { type: data.result.blob.type });
 
     if (file) {
       this.fireSuccess(file);
     } else {
       this.fireError();
     }
   }
 };
--- a/b2g/components/test/mochitest/test_filepicker_path.html
+++ b/b2g/components/test/mochitest/test_filepicker_path.html
@@ -62,17 +62,17 @@ var testCases = [
                               blob: new File(['1234567890'],
                                              'useless-name.txt',
                                              { type: 'text/plain' }),
                               name: 'test5.txt'
                             }
                 },
     fileName: 'test5.txt'},
   // case 6: returns file without name. This case may fail because we
-  //         need to make sure the DOMFile can be sent through
+  //         need to make sure the File can be sent through
   //         sendAsyncMessage API.
   { pickedResult: { success: true,
                     result: {
                               type: 'text/plain',
                               blob: new File(['1234567890'],
                                              'test6.txt',
                                              { type: 'text/plain' })
                             }
@@ -91,17 +91,17 @@ chromeScript.addMessageListener('file-pi
 function handleMessage(data) {
   var fileInput = document.getElementById('fileInput');
   switch (data.type) {
     case 'pick-result-updated':
       fileInput.click();
       break;
     case 'file-picked-posted':
       is(fileInput.value, activeTestCase.fileName,
-         'DOMFile should be able to send through message.');
+         'File should be able to send through message.');
       processTestCase();
       break;
   }
 }
 
 function processTestCase() {
   if (!testCases.length) {
     SimpleTest.finish();
@@ -122,9 +122,9 @@ function processTestCase() {
     expectedResult.result.name = name
   }
   chromeScript.sendAsyncMessage('update-pick-result', expectedResult);
 }
 
 </script>
 <input type="file" id="fileInput">
 </body>
-</html>
\ No newline at end of file
+</html>
--- a/browser/app/macbuild/Contents/MacOS-files.in
+++ b/browser/app/macbuild/Contents/MacOS-files.in
@@ -1,9 +1,10 @@
 /*.app/***
 /*.dylib
 /certutil
 /firefox-bin
+/gtest/***
 /pk12util
 /ssltunnel
 /webapprt-stub
 /xpcshell
 /XUL
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -393,18 +393,17 @@ panel[noactions] > richlistbox > richlis
 panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .ac-action-icon {
   visibility: collapse;
 }
 
 panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .ac-url > .ac-url-text {
   visibility: visible;
 }
 
-#urlbar:not([actiontype]) > #urlbar-display-box,
-#urlbar:not([actiontype="switchtab"]) > #urlbar-display-box > .urlbar-display-switchtab {
+#urlbar:not([actiontype="switchtab"]) > #urlbar-display-box {
   display: none;
 }
 
 #PopupAutoComplete {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#browser-autocomplete-result-popup");
 }
 
 #PopupAutoCompleteRichResult {
--- a/browser/base/content/test/general/browser_blob-channelname.js
+++ b/browser/base/content/test/general/browser_blob-channelname.js
@@ -1,11 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 Cu.import("resource://gre/modules/NetUtil.jsm");
 
 function test() {
-    var file = new File(new Blob(['test'], {type: 'text/plain'}), {name: 'test-name'});
+    var file = new File([new Blob(['test'], {type: 'text/plain'})], "test-name");
     var url = URL.createObjectURL(file);
     var channel = NetUtil.newChannel(url);
 
     is(channel.contentDispositionFilename, 'test-name', "filename matches");
 }
--- a/browser/components/loop/GoogleImporter.jsm
+++ b/browser/components/loop/GoogleImporter.jsm
@@ -420,17 +420,17 @@ this.GoogleImporter.prototype = {
           ["locality", "city"],
           ["postalCode", "postcode"],
           ["region", "region"],
           ["streetAddress", "street"]
         ]), addressNode, kNS_GD);
         if (Object.keys(adr).length) {
           adr.pref = (addressNode.getAttribute("primary") == "true");
           adr.type = [getFieldType(addressNode)];
-          contacts.adr.push(adr);
+          contact.adr.push(adr);
         }
       }
     }
 
     // Process email addresses.
     let emailNodes = entry.getElementsByTagNameNS(kNS_GD, "email");
     if (emailNodes.length) {
       contact.email = [];
--- a/browser/components/loop/ui/ui-showcase.js
+++ b/browser/components/loop/ui/ui-showcase.js
@@ -53,16 +53,23 @@
   var stageFeedbackApiClient = new loop.FeedbackAPIClient(
     "https://input.allizom.org/api/v1/feedback", {
       product: "Loop"
     }
   );
 
   // Local mocks
 
+  var mockContact = {
+    name: ["Mr Smith"],
+    email: [{
+      value: "smith@invalid.com"
+    }]
+  };
+
   var mockClient = {
     requestCallUrl: noop,
     requestCallUrlInfo: noop
   };
 
   var mockSDK = {};
 
   var mockConversationModel = new loop.shared.models.ConversationModel({}, {
@@ -249,17 +256,18 @@
               )
             )
           ), 
 
           Section({name: "PendingConversationView (Desktop)"}, 
             Example({summary: "Connecting", dashed: "true", 
                      style: {width: "260px", height: "265px"}}, 
               React.DOM.div({className: "fx-embedded"}, 
-                DesktopPendingConversationView({callState: "gather", calleeId: "Mr Smith"})
+                DesktopPendingConversationView({callState: "gather", 
+                                                contact: mockContact})
               )
             )
           ), 
 
           Section({name: "CallFailedView"}, 
             Example({summary: "Call Failed", dashed: "true", 
                      style: {width: "260px", height: "265px"}}, 
               React.DOM.div({className: "fx-embedded"}, 
--- a/browser/components/loop/ui/ui-showcase.jsx
+++ b/browser/components/loop/ui/ui-showcase.jsx
@@ -53,16 +53,23 @@
   var stageFeedbackApiClient = new loop.FeedbackAPIClient(
     "https://input.allizom.org/api/v1/feedback", {
       product: "Loop"
     }
   );
 
   // Local mocks
 
+  var mockContact = {
+    name: ["Mr Smith"],
+    email: [{
+      value: "smith@invalid.com"
+    }]
+  };
+
   var mockClient = {
     requestCallUrl: noop,
     requestCallUrlInfo: noop
   };
 
   var mockSDK = {};
 
   var mockConversationModel = new loop.shared.models.ConversationModel({}, {
@@ -249,17 +256,18 @@
               </div>
             </Example>
           </Section>
 
           <Section name="PendingConversationView (Desktop)">
             <Example summary="Connecting" dashed="true"
                      style={{width: "260px", height: "265px"}}>
               <div className="fx-embedded">
-                <DesktopPendingConversationView callState={"gather"} calleeId="Mr Smith" />
+                <DesktopPendingConversationView callState={"gather"}
+                                                contact={mockContact} />
               </div>
             </Example>
           </Section>
 
           <Section name="CallFailedView">
             <Example summary="Call Failed" dashed="true"
                      style={{width: "260px", height: "265px"}}>
               <div className="fx-embedded">
--- a/browser/config/mozconfigs/win32/common-opt
+++ b/browser/config/mozconfigs/win32/common-opt
@@ -14,17 +14,17 @@ else
 fi
 ac_add_options --with-google-api-keyfile=${_gapi_keyfile}
 
 if [ -f /c/builds/google-oauth-api.key ]; then
   _google_oauth_api_keyfile=/c/builds/google-oauth-api.key
 else
   _google_oauth_api_keyfile=/e/builds/google-oauth-api.key
 fi
-ac_add_options --with-google-api-keyfile=${_google_oauth_api_keyfile}
+ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
--- a/browser/config/mozconfigs/win64/common-opt
+++ b/browser/config/mozconfigs/win64/common-opt
@@ -12,17 +12,17 @@ else
 fi
 ac_add_options --with-google-api-keyfile=${_gapi_keyfile}
 
 if [ -f /c/builds/google-oauth-api.key ]; then
   _google_oauth_api_keyfile=/c/builds/google-oauth-api.key
 else
   _google_oauth_api_keyfile=/e/builds/google-oauth-api.key
 fi
-ac_add_options --with-google-api-keyfile=${_google_oauth_api_keyfile}
+ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
--- a/build/autoconf/hooks.m4
+++ b/build/autoconf/hooks.m4
@@ -42,17 +42,17 @@ define([AC_OUTPUT_SUBDIRS],
     if test ! -e "$_CONFIG_SHELL" -a -e "${_CONFIG_SHELL}.exe"; then
         _CONFIG_SHELL="${_CONFIG_SHELL}.exe"
     fi
     dnl Yes, this is horrible. But since msys doesn't preserve environment
     dnl variables and command line arguments as they are when transitioning
     dnl from msys (this script) to python (below), we have to resort to hacks,
     dnl storing the environment and command line arguments from a msys process
     dnl (perl), and reading it from python.
-    dumpenv="$PERL $srcdir/build/win32/dumpenv4python.pl $ac_configure_args | "
+    dumpenv="$PERL $_topsrcdir/build/win32/dumpenv4python.pl $ac_configure_args | "
     ;;
   esac
 
   eval $dumpenv $PYTHON $_topsrcdir/build/subconfigure.py --prepare "$srcdir" "$moz_config_dir" "$_CONFIG_SHELL" $ac_configure_args ifelse($2,,,--cache-file="$2")
 
   dnl Execute subconfigure, unless --no-recursion was passed to configure.
   if test "$no_recursion" != yes; then
     trap '' EXIT
--- a/configure.in
+++ b/configure.in
@@ -1418,17 +1418,16 @@ if test "$GNU_CC"; then
     # -Wall - turn on a lot of warnings
     # -Wchar-subscripts - catches array index using signed char
     # -Wcomment - catches nested comments
     # -Wdeclaration-after-statement - MSVC doesn't like these
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
     # -Wendif-labels - catches `#else FOO` and `#endif FOO` not in comment
     # -Wenum-compare - catches comparison of different enum types
     # -Wignored-qualifiers - catches returns types with qualifiers like const
-    # -Wimplicit-int - catches C variable declaration without a type
     # -Wint-to-pointer-cast - catches cast to pointer from integer of different size
     # -Wmultichar - catches multicharacter integer constants like 'THIS'
     # -Wnonnull - catches NULL used with functions arguments marked as non-null
     # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
     # -Wpointer-sign - catches mixing pointers to signed and unsigned types
     # -Wpointer-to-int-cast - catches casts from pointer to different sized int
     # -Wreturn-type - catches missing returns, zero false positives
     # -Wsequence-point - catches undefined order behavior like `a = a++`
@@ -1445,17 +1444,16 @@ if test "$GNU_CC"; then
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wtype-limits"
 
     # Treat some warnings as errors:
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=char-subscripts"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=comment"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=endif-labels"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=enum-compare"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=ignored-qualifiers"
-    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=implicit-int"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=int-to-pointer-cast"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=multichar"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=nonnull"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-arith"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-sign"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=return-type"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=sequence-point"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=trigraphs"
@@ -6959,16 +6957,17 @@ dnl ====================================
 MOZ_ARG_DISABLE_BOOL(logging,
 [  --disable-logging       Disable logging facilities],
     NS_DISABLE_LOGGING=1,
     NS_DISABLE_LOGGING= )
 if test "$NS_DISABLE_LOGGING"; then
     AC_DEFINE(NS_DISABLE_LOGGING)
 else
     AC_DEFINE(MOZ_LOGGING)
+    AC_DEFINE(FORCE_PR_LOG)
 fi
 
 dnl ========================================================
 dnl = This will enable logging of addref, release, ctor, dtor.
 dnl ========================================================
 _ENABLE_LOGREFCNT=42
 MOZ_ARG_ENABLE_BOOL(logrefcnt,
 [  --enable-logrefcnt      Enable logging of refcounts (default=debug) ],
@@ -9054,19 +9053,25 @@ dnl ICU Support
 dnl ========================================================
 
 # Internationalization isn't built or exposed by default in non-desktop
 # builds.  Bugs to enable:
 #
 #   Android:  bug 864843
 #   B2G:      bug 866301
 
-if test "$MOZ_WIDGET_TOOLKIT" = "android" ||
-   test "$MOZ_BUILD_APP" = "b2g"; then
+if test "$MOZ_WIDGET_TOOLKIT" = "android"; then
     _INTL_API=no
+elif test "$MOZ_BUILD_APP" = "b2g"; then
+    if test "$MOZ_WIDGET_TOOLKIT" = "cocoa"; then
+        # nsCollationMacUC needs ICU
+        _INTL_API=yes
+    else
+        _INTL_API=no
+    fi
 else
     _INTL_API=yes
 fi
 
 MOZ_CONFIG_ICU()
 
 if test -z "$JS_SHARED_LIBRARY"; then
   AC_DEFINE(MOZ_STATIC_JS)
new file mode 100644
--- /dev/null
+++ b/content/base/public/BlobSet.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_BlobSet_h
+#define mozilla_dom_BlobSet_h
+
+#include "mozilla/CheckedInt.h"
+#include "mozilla/dom/File.h"
+
+namespace mozilla {
+namespace dom {
+
+class BlobSet {
+public:
+  BlobSet()
+    : mData(nullptr), mDataLen(0), mDataBufferLen(0)
+  {}
+
+  ~BlobSet()
+  {
+    moz_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);
+
+  nsTArray<nsRefPtr<FileImpl>>& GetBlobImpls() { Flush(); return mBlobImpls; }
+
+  already_AddRefed<File> GetBlobInternal(nsISupports* aParent,
+                                         const nsACString& aContentType);
+
+protected:
+  bool ExpandBufferSize(uint64_t aSize)
+  {
+    using mozilla::CheckedUint32;
+
+    if (mDataBufferLen >= mDataLen + aSize) {
+      mDataLen += aSize;
+      return true;
+    }
+
+    // Start at 1 or we'll loop forever.
+    CheckedUint32 bufferLen =
+      std::max<uint32_t>(static_cast<uint32_t>(mDataBufferLen), 1);
+    while (bufferLen.isValid() && bufferLen.value() < mDataLen + aSize)
+      bufferLen *= 2;
+
+    if (!bufferLen.isValid())
+      return false;
+
+    void* data = moz_realloc(mData, bufferLen.value());
+    if (!data)
+      return false;
+
+    mData = data;
+    mDataBufferLen = bufferLen.value();
+    mDataLen += aSize;
+    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());
+      mBlobImpls.AppendElement(blobImpl);
+      mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer
+      mDataLen = 0;
+      mDataBufferLen = 0;
+    }
+  }
+
+  nsTArray<nsRefPtr<FileImpl>> mBlobImpls;
+  void* mData;
+  uint64_t mDataLen;
+  uint64_t mDataBufferLen;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_BlobSet_h
rename from content/base/public/nsDOMFile.h
rename to content/base/public/File.h
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/File.h
@@ -1,209 +1,267 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsDOMFile_h__
-#define nsDOMFile_h__
+#ifndef mozilla_dom_File_h
+#define mozilla_dom_File_h
 
 #include "mozilla/Attributes.h"
-#include "nsICharsetDetectionObserver.h"
-#include "nsIFile.h"
-#include "nsIDOMFile.h"
-#include "nsIDOMFileList.h"
-#include "nsIInputStream.h"
-#include "nsIJSNativeInitializer.h"
-#include "nsIMutable.h"
-#include "nsCOMArray.h"
-#include "nsCOMPtr.h"
-#include "nsString.h"
-#include "nsIXMLHttpRequest.h"
-#include "nsAutoPtr.h"
-#include "nsFileStreams.h"
-#include "nsTemporaryFileInputStream.h"
 
 #include "mozilla/GuardObjects.h"
 #include "mozilla/LinkedList.h"
-#include <stdint.h>
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
-#include "mozilla/dom/DOMError.h"
+#include "mozilla/dom/Date.h"
 #include "mozilla/dom/indexedDB/FileInfo.h"
 #include "mozilla/dom/indexedDB/FileManager.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
+#include "mozilla/dom/UnionTypes.h"
+#include "nsAutoPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsCOMPtr.h"
+#include "nsIDOMFile.h"
+#include "nsIDOMFileList.h"
+#include "nsIFile.h"
+#include "nsIMutable.h"
+#include "nsIXMLHttpRequest.h"
+#include "nsString.h"
+#include "nsTemporaryFileInputStream.h"
 #include "nsWrapperCache.h"
-#include "nsCycleCollectionParticipant.h"
 #include "nsWeakReference.h"
 
 class nsDOMMultipartFile;
 class nsIFile;
 class nsIInputStream;
 class nsIClassInfo;
 
-#define PIDOMFILEIMPL_IID \
+#define PIFILEIMPL_IID \
   { 0x218ee173, 0xf44f, 0x4d30, \
     { 0xab, 0x0c, 0xd6, 0x66, 0xea, 0xc2, 0x84, 0x47 } }
 
-class PIDOMFileImpl : public nsISupports
+class PIFileImpl : public nsISupports
 {
 public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(PIDOMFILEIMPL_IID)
+  NS_DECLARE_STATIC_IID_ACCESSOR(PIFILEIMPL_IID)
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(PIDOMFileImpl, PIDOMFILEIMPL_IID)
+NS_DEFINE_STATIC_IID_ACCESSOR(PIFileImpl, PIFILEIMPL_IID)
 
 namespace mozilla {
 namespace dom {
 
 namespace indexedDB {
 class FileInfo;
 };
 
-class DOMFileImpl;
+struct BlobPropertyBag;
+struct ChromeFilePropertyBag;
+struct FilePropertyBag;
+class FileImpl;
 
-class DOMFile MOZ_FINAL : public nsIDOMFile
-                        , public nsIXHRSendable
-                        , public nsIMutable
-                        , public nsIJSNativeInitializer
-                        , public nsSupportsWeakReference
+class File MOZ_FINAL : public nsIDOMFile
+                     , public nsIXHRSendable
+                     , public nsIMutable
+                     , public nsSupportsWeakReference
+                     , public nsWrapperCache
 {
 public:
   NS_DECL_NSIDOMBLOB
   NS_DECL_NSIDOMFILE
   NS_DECL_NSIXHRSENDABLE
   NS_DECL_NSIMUTABLE
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DOMFile, nsIDOMFile)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(File, nsIDOMFile)
+
+  static already_AddRefed<File>
+  Create(nsISupports* aParent, const nsAString& aName,
+         const nsAString& aContentType, uint64_t aLength,
+         uint64_t aLastModifiedDate);
 
-  static already_AddRefed<DOMFile>
-  Create(const nsAString& aName, const nsAString& aContentType,
-         uint64_t aLength, uint64_t aLastModifiedDate);
+  static already_AddRefed<File>
+  Create(nsISupports* aParent, const nsAString& aName,
+         const nsAString& aContentType, uint64_t aLength);
 
-  static already_AddRefed<DOMFile>
-  Create(const nsAString& aName, const nsAString& aContentType,
+  static already_AddRefed<File>
+  Create(nsISupports* aParent, const nsAString& aContentType,
          uint64_t aLength);
 
-  static already_AddRefed<DOMFile>
-  Create(const nsAString& aContentType, uint64_t aLength);
-
-  static already_AddRefed<DOMFile>
-  Create(const nsAString& aContentType, uint64_t aStart,
+  static already_AddRefed<File>
+  Create(nsISupports* aParent, const nsAString& aContentType, uint64_t aStart,
          uint64_t aLength);
 
-  static already_AddRefed<DOMFile>
-  CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
+  static already_AddRefed<File>
+  CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
                    const nsAString& aName, const nsAString& aContentType,
                    uint64_t aLastModifiedDate);
 
-  static already_AddRefed<DOMFile>
-  CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
+  static already_AddRefed<File>
+  CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
                    const nsAString& aContentType);
 
-  static already_AddRefed<DOMFile>
-  CreateTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos,
-                          uint64_t aLength,
+  static already_AddRefed<File>
+  CreateTemporaryFileBlob(nsISupports* aParent, PRFileDesc* aFD,
+                          uint64_t aStartPos, uint64_t aLength,
                           const nsAString& aContentType);
 
-  static already_AddRefed<DOMFile>
-  CreateFromFile(nsIFile* aFile);
+  static already_AddRefed<File>
+  CreateFromFile(nsISupports* aParent, nsIFile* aFile);
 
-  static already_AddRefed<DOMFile>
-  CreateFromFile(const nsAString& aContentType, uint64_t aLength,
+  static already_AddRefed<File>
+  CreateFromFile(nsISupports* aParent, const nsAString& aContentType,
+                 uint64_t aLength, nsIFile* aFile,
+                 indexedDB::FileInfo* aFileInfo);
+
+  static already_AddRefed<File>
+  CreateFromFile(nsISupports* aParent, const nsAString& aName,
+                 const nsAString& aContentType, uint64_t aLength,
                  nsIFile* aFile, indexedDB::FileInfo* aFileInfo);
 
-  static already_AddRefed<DOMFile>
-  CreateFromFile(const nsAString& aName, const nsAString& aContentType,
-                 uint64_t aLength, nsIFile* aFile,
-                    indexedDB::FileInfo* aFileInfo);
+  static already_AddRefed<File>
+  CreateFromFile(nsISupports* aParent, nsIFile* aFile,
+                 indexedDB::FileInfo* aFileInfo);
 
-  static already_AddRefed<DOMFile>
-  CreateFromFile(nsIFile* aFile, indexedDB::FileInfo* aFileInfo);
-
-  static already_AddRefed<DOMFile>
-  CreateFromFile(nsIFile* aFile, const nsAString& aName,
+  static already_AddRefed<File>
+  CreateFromFile(nsISupports* aParent, nsIFile* aFile, const nsAString& aName,
                  const nsAString& aContentType);
 
-  explicit DOMFile(DOMFileImpl* aImpl)
-    : mImpl(aImpl)
-  {
-    MOZ_ASSERT(mImpl);
-  }
+  File(nsISupports* aParent, FileImpl* aImpl);
 
-  DOMFileImpl* Impl() const
+  FileImpl* Impl() const
   {
     return mImpl;
   }
 
-  const nsTArray<nsRefPtr<DOMFileImpl>>* GetSubBlobImpls() const;
+  const nsTArray<nsRefPtr<FileImpl>>* GetSubBlobImpls() const;
 
   bool IsSizeUnknown() const;
 
   bool IsDateUnknown() const;
 
   bool IsFile() const;
 
   void SetLazyData(const nsAString& aName, const nsAString& aContentType,
                    uint64_t aLength, uint64_t aLastModifiedDate);
 
-  already_AddRefed<nsIDOMBlob>
-  CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType);
+  already_AddRefed<File>
+  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
+              ErrorResult& aRv);
+
+  // WebIDL methods
+  nsISupports* GetParentObject() const
+  {
+    return mParent;
+  }
+
+  // Blob constructor
+  static already_AddRefed<File>
+  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+
+  // Blob constructor
+  static already_AddRefed<File>
+  Constructor(const GlobalObject& aGlobal,
+              const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+              const BlobPropertyBag& aBag,
+              ErrorResult& aRv);
+
+  // File constructor
+  static already_AddRefed<File>
+  Constructor(const GlobalObject& aGlobal,
+              const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+              const nsAString& aName,
+              const FilePropertyBag& aBag,
+              ErrorResult& aRv);
 
-  // nsIJSNativeInitializer
-  NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
-                        const JS::CallArgs& aArgs) MOZ_OVERRIDE;
+  // File constructor - ChromeOnly
+  static already_AddRefed<File>
+  Constructor(const GlobalObject& aGlobal,
+              File& aData,
+              const ChromeFilePropertyBag& aBag,
+              ErrorResult& aRv);
+
+  // File constructor - ChromeOnly
+  static already_AddRefed<File>
+  Constructor(const GlobalObject& aGlobal,
+              const nsAString& aData,
+              const ChromeFilePropertyBag& aBag,
+              ErrorResult& aRv);
+
+  // File constructor - ChromeOnly
+  static already_AddRefed<File>
+  Constructor(const GlobalObject& aGlobal,
+              nsIFile* aData,
+              const ChromeFilePropertyBag& aBag,
+              ErrorResult& aRv);
+
+  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+  uint64_t GetSize(ErrorResult& aRv);
+
+  // XPCOM GetType is OK
+
+  // XPCOM GetName is OK
+
+  int64_t GetLastModified(ErrorResult& aRv);
+
+  Date GetLastModifiedDate(ErrorResult& aRv);
+
+  void GetMozFullPath(nsAString& aFilename, ErrorResult& aRv);
+
+  already_AddRefed<File> Slice(const Optional<int64_t>& aStart,
+                               const Optional<int64_t>& aEnd,
+                               const nsAString& aContentType,
+                               ErrorResult& aRv);
 
 private:
-  ~DOMFile() {};
+  ~File() {};
 
-  // The member is the real backend implementation of this DOMFile/DOMBlob.
+  // 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!
-  const nsRefPtr<DOMFileImpl> mImpl;
+  const nsRefPtr<FileImpl> mImpl;
+
+  nsCOMPtr<nsISupports> mParent;
 };
 
-// This is the abstract class for any DOMFile backend. It must be nsISupports
+// 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 DOMFileImpl : public PIDOMFileImpl
+class FileImpl : public PIFileImpl
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
-  DOMFileImpl() {}
+  FileImpl() {}
 
-  virtual nsresult GetName(nsAString& aName) = 0;
+  virtual void GetName(nsAString& aName) = 0;
 
   virtual nsresult GetPath(nsAString& aName) = 0;
 
-  virtual nsresult
-  GetLastModifiedDate(JSContext* aCx,
-                      JS::MutableHandle<JS::Value> aDate) = 0;
+  virtual int64_t GetLastModified(ErrorResult& aRv) = 0;
+
+  virtual void GetMozFullPath(nsAString& aName, ErrorResult& aRv) = 0;
 
-  virtual nsresult GetMozFullPath(nsAString& aName) = 0;
+  virtual void GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) = 0;
 
-  virtual nsresult GetMozFullPathInternal(nsAString &aFileName) = 0;
+  virtual uint64_t GetSize(ErrorResult& aRv) = 0;
 
-  virtual nsresult GetSize(uint64_t* aSize) = 0;
+  virtual void GetType(nsAString& aType) = 0;
 
-  virtual nsresult GetType(nsAString& aType) = 0;
-
-  virtual nsresult GetMozLastModifiedDate(uint64_t* aDate) = 0;
+  already_AddRefed<FileImpl>
+  Slice(const Optional<int64_t>& aStart, const Optional<int64_t>& aEnd,
+        const nsAString& aContentType, ErrorResult& aRv);
 
-  nsresult Slice(int64_t aStart, int64_t aEnd, const nsAString& aContentType,
-                 uint8_t aArgc, DOMFileImpl** aBlobImpl);
+  virtual already_AddRefed<FileImpl>
+  CreateSlice(uint64_t aStart, uint64_t aLength,
+              const nsAString& aContentType, ErrorResult& aRv) = 0;
 
-  virtual already_AddRefed<DOMFileImpl>
-  CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) = 0;
-
-  virtual const nsTArray<nsRefPtr<DOMFileImpl>>*
+  virtual const nsTArray<nsRefPtr<FileImpl>>*
   GetSubBlobImpls() const = 0;
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) = 0;
 
   virtual int64_t GetFileId() = 0;
 
   virtual void AddFileInfo(indexedDB::FileInfo* aFileInfo) = 0;
 
@@ -227,118 +285,122 @@ public:
   virtual bool IsMemoryFile() const = 0;
 
   virtual bool IsSizeUnknown() const = 0;
 
   virtual bool IsDateUnknown() const = 0;
 
   virtual bool IsFile() const = 0;
 
-  virtual nsresult Initialize(nsISupports* aOwner, JSContext* aCx,
-                              JSObject* aObj, const JS::CallArgs& aArgs) = 0;
-
   // These 2 methods are used when the implementation has to CC something.
   virtual void Unlink() = 0;
   virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) = 0;
 
   virtual bool IsCCed() const
   {
     return false;
   }
 
 protected:
-  virtual ~DOMFileImpl() {}
+  virtual ~FileImpl() {}
 };
 
-class DOMFileImplBase : public DOMFileImpl
+class FileImplBase : public FileImpl
 {
 public:
-  DOMFileImplBase(const nsAString& aName, const nsAString& aContentType,
-                  uint64_t aLength, uint64_t aLastModifiedDate)
+  FileImplBase(const nsAString& aName, const nsAString& aContentType,
+               uint64_t aLength, uint64_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);
   }
 
-  DOMFileImplBase(const nsAString& aName, const nsAString& aContentType,
-                  uint64_t aLength)
+  FileImplBase(const nsAString& aName, const nsAString& aContentType,
+               uint64_t aLength)
     : mIsFile(true)
     , mImmutable(false)
     , mContentType(aContentType)
     , mName(aName)
     , mStart(0)
     , mLength(aLength)
     , mLastModificationDate(UINT64_MAX)
   {
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
   }
 
-  DOMFileImplBase(const nsAString& aContentType, uint64_t aLength)
+  FileImplBase(const nsAString& aContentType, uint64_t aLength)
     : mIsFile(false)
     , mImmutable(false)
     , mContentType(aContentType)
     , mStart(0)
     , mLength(aLength)
     , mLastModificationDate(UINT64_MAX)
   {
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
   }
 
-  DOMFileImplBase(const nsAString& aContentType, uint64_t aStart,
-                  uint64_t aLength)
+  FileImplBase(const nsAString& aContentType, uint64_t aStart,
+               uint64_t aLength)
     : mIsFile(false)
     , mImmutable(false)
     , mContentType(aContentType)
     , mStart(aStart)
     , mLength(aLength)
     , mLastModificationDate(UINT64_MAX)
   {
     NS_ASSERTION(aLength != UINT64_MAX,
                  "Must know length when creating slice");
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
   }
 
-  virtual nsresult GetName(nsAString& aName) MOZ_OVERRIDE;
+  virtual void GetName(nsAString& aName) MOZ_OVERRIDE;
 
   virtual nsresult GetPath(nsAString& aName) MOZ_OVERRIDE;
 
-  virtual nsresult GetLastModifiedDate(JSContext* aCx,
-                               JS::MutableHandle<JS::Value> aDate) MOZ_OVERRIDE;
+  virtual int64_t GetLastModified(ErrorResult& aRv) MOZ_OVERRIDE;
 
-  virtual nsresult GetMozFullPath(nsAString& aName) MOZ_OVERRIDE;
+  virtual void GetMozFullPath(nsAString& aName, ErrorResult& aRv) MOZ_OVERRIDE;
 
-  virtual nsresult GetMozFullPathInternal(nsAString& aFileName) MOZ_OVERRIDE;
-
-  virtual nsresult GetSize(uint64_t* aSize) MOZ_OVERRIDE;
+  virtual void GetMozFullPathInternal(nsAString& aFileName,
+                                      ErrorResult& aRv) MOZ_OVERRIDE;
 
-  virtual nsresult GetType(nsAString& aType) MOZ_OVERRIDE;
+  virtual uint64_t GetSize(ErrorResult& aRv) MOZ_OVERRIDE
+  {
+    return mLength;
+  }
 
-  virtual nsresult GetMozLastModifiedDate(uint64_t* aDate) MOZ_OVERRIDE;
+  virtual void GetType(nsAString& aType) MOZ_OVERRIDE;
 
-  virtual already_AddRefed<DOMFileImpl>
+  virtual already_AddRefed<FileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType, ErrorResult& aRv) MOZ_OVERRIDE
+  {
+    return nullptr;
+  }
 
-  virtual const nsTArray<nsRefPtr<DOMFileImpl>>*
+  virtual const nsTArray<nsRefPtr<FileImpl>>*
   GetSubBlobImpls() const MOZ_OVERRIDE
   {
     return nullptr;
   }
 
-  virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
+  virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE
+  {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
 
   virtual int64_t GetFileId() MOZ_OVERRIDE;
 
   virtual void AddFileInfo(indexedDB::FileInfo* aFileInfo) MOZ_OVERRIDE;
 
   virtual indexedDB::FileInfo*
   GetFileInfo(indexedDB::FileManager* aFileManager) MOZ_OVERRIDE;
 
@@ -395,27 +457,21 @@ public:
     return false;
   }
 
   virtual bool IsSizeUnknown() const
   {
     return mLength == UINT64_MAX;
   }
 
-  virtual nsresult Initialize(nsISupports* aOwner, JSContext* aCx,
-                              JSObject* aObj, const JS::CallArgs& aArgs)
-  {
-    return NS_OK;
-  }
-
   virtual void Unlink() {}
   virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) {}
 
 protected:
-  virtual ~DOMFileImplBase() {}
+  virtual ~FileImplBase() {}
 
   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);
   }
@@ -435,45 +491,42 @@ 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 DOMFileImplMemory MOZ_FINAL : public DOMFileImplBase
+class FileImplMemory MOZ_FINAL : public FileImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
-  DOMFileImplMemory(void* aMemoryBuffer, uint64_t aLength,
-                    const nsAString& aName,
-                    const nsAString& aContentType,
-                    uint64_t aLastModifiedDate)
-    : DOMFileImplBase(aName, aContentType, aLength, aLastModifiedDate)
+  FileImplMemory(void* aMemoryBuffer, uint64_t aLength, const nsAString& aName,
+                 const nsAString& aContentType, uint64_t aLastModifiedDate)
+    : FileImplBase(aName, aContentType, aLength, aLastModifiedDate)
     , mDataOwner(new DataOwner(aMemoryBuffer, aLength))
   {
     NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
   }
 
-  DOMFileImplMemory(void* aMemoryBuffer,
-                    uint64_t aLength,
-                    const nsAString& aContentType)
-    : DOMFileImplBase(aContentType, aLength)
+  FileImplMemory(void* aMemoryBuffer, uint64_t aLength,
+                 const nsAString& aContentType)
+    : FileImplBase(aContentType, aLength)
     , mDataOwner(new DataOwner(aMemoryBuffer, aLength))
   {
     NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
   }
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
-  virtual already_AddRefed<DOMFileImpl>
+  virtual already_AddRefed<FileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType, ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual bool IsMemoryFile() const MOZ_OVERRIDE
   {
     return true;
   }
 
   class DataOwner MOZ_FINAL : public mozilla::LinkedListElement<DataOwner> {
   public:
@@ -516,195 +569,194 @@ public:
     static bool sMemoryReporterRegistered;
 
     void* mData;
     uint64_t mLength;
   };
 
 private:
   // Create slice
-  DOMFileImplMemory(const DOMFileImplMemory* aOther, uint64_t aStart,
-                    uint64_t aLength, const nsAString& aContentType)
-    : DOMFileImplBase(aContentType, aOther->mStart + aStart, aLength)
+  FileImplMemory(const FileImplMemory* aOther, uint64_t aStart,
+                 uint64_t aLength, const nsAString& aContentType)
+    : FileImplBase(aContentType, aOther->mStart + aStart, aLength)
     , mDataOwner(aOther->mDataOwner)
   {
     NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
     mImmutable = aOther->mImmutable;
   }
 
-  ~DOMFileImplMemory() {}
+  ~FileImplMemory() {}
 
   // Used when backed by a memory store
   nsRefPtr<DataOwner> mDataOwner;
 };
 
-class DOMFileImplTemporaryFileBlob MOZ_FINAL : public DOMFileImplBase
+class FileImplTemporaryFileBlob MOZ_FINAL : public FileImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
-  DOMFileImplTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos,
-                               uint64_t aLength, const nsAString& aContentType)
-    : DOMFileImplBase(aContentType, aLength)
+  FileImplTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos,
+                            uint64_t aLength, const nsAString& aContentType)
+    : FileImplBase(aContentType, aLength)
     , mLength(aLength)
     , mStartPos(aStartPos)
     , mContentType(aContentType)
   {
     mFileDescOwner = new nsTemporaryFileInputStream::FileDescOwner(aFD);
   }
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
-  virtual already_AddRefed<DOMFileImpl>
+  virtual already_AddRefed<FileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType, ErrorResult& aRv) MOZ_OVERRIDE;
 
 private:
-  DOMFileImplTemporaryFileBlob(const DOMFileImplTemporaryFileBlob* aOther,
-                               uint64_t aStart, uint64_t aLength,
-                               const nsAString& aContentType)
-    : DOMFileImplBase(aContentType, aLength)
+  FileImplTemporaryFileBlob(const FileImplTemporaryFileBlob* aOther,
+                            uint64_t aStart, uint64_t aLength,
+                            const nsAString& aContentType)
+    : FileImplBase(aContentType, aLength)
     , mLength(aLength)
     , mStartPos(aStart)
     , mFileDescOwner(aOther->mFileDescOwner)
     , mContentType(aContentType) {}
 
-  ~DOMFileImplTemporaryFileBlob() {}
+  ~FileImplTemporaryFileBlob() {}
 
   uint64_t mLength;
   uint64_t mStartPos;
   nsRefPtr<nsTemporaryFileInputStream::FileDescOwner> mFileDescOwner;
   nsString mContentType;
 };
 
-class DOMFileImplFile : public DOMFileImplBase
+class FileImplFile : public FileImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // Create as a file
-  explicit DOMFileImplFile(nsIFile* aFile)
-    : DOMFileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
+  explicit FileImplFile(nsIFile* aFile)
+    : FileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(false)
   {
     NS_ASSERTION(mFile, "must have file");
     // Lazily get the content type and size
     mContentType.SetIsVoid(true);
     mFile->GetLeafName(mName);
   }
 
-  DOMFileImplFile(nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
-    : DOMFileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
+  FileImplFile(nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
+    : FileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(true)
   {
     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
-  DOMFileImplFile(const nsAString& aName, const nsAString& aContentType,
-                  uint64_t aLength, nsIFile* aFile)
-    : DOMFileImplBase(aName, aContentType, aLength, UINT64_MAX)
+  FileImplFile(const nsAString& aName, const nsAString& aContentType,
+               uint64_t aLength, nsIFile* aFile)
+    : FileImplBase(aName, aContentType, aLength, UINT64_MAX)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(false)
   {
     NS_ASSERTION(mFile, "must have file");
   }
 
-  DOMFileImplFile(const nsAString& aName, const nsAString& aContentType,
-                  uint64_t aLength, nsIFile* aFile,
-                  uint64_t aLastModificationDate)
-    : DOMFileImplBase(aName, aContentType, aLength, aLastModificationDate)
+  FileImplFile(const nsAString& aName, const nsAString& aContentType,
+               uint64_t aLength, nsIFile* aFile,
+               uint64_t aLastModificationDate)
+    : FileImplBase(aName, aContentType, aLength, aLastModificationDate)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(false)
   {
     NS_ASSERTION(mFile, "must have file");
   }
 
   // Create as a file with custom name
-  DOMFileImplFile(nsIFile* aFile, const nsAString& aName,
-                  const nsAString& aContentType)
-    : DOMFileImplBase(aName, aContentType, UINT64_MAX, UINT64_MAX)
+  FileImplFile(nsIFile* aFile, const nsAString& aName,
+               const nsAString& aContentType)
+    : FileImplBase(aName, aContentType, UINT64_MAX, UINT64_MAX)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(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
-  DOMFileImplFile(const nsAString& aName, const nsAString& aContentType,
-                  uint64_t aLength, nsIFile* aFile,
-                  indexedDB::FileInfo* aFileInfo)
-    : DOMFileImplBase(aName, aContentType, aLength, UINT64_MAX)
+  FileImplFile(const nsAString& aName, const nsAString& aContentType,
+               uint64_t aLength, nsIFile* aFile,
+               indexedDB::FileInfo* aFileInfo)
+    : FileImplBase(aName, aContentType, aLength, UINT64_MAX)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(true)
   {
     NS_ASSERTION(mFile, "must have file");
     mFileInfos.AppendElement(aFileInfo);
   }
 
   // Create as a stored blob
-  DOMFileImplFile(const nsAString& aContentType, uint64_t aLength,
-                  nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
-    : DOMFileImplBase(aContentType, aLength)
+  FileImplFile(const nsAString& aContentType, uint64_t aLength,
+               nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
+    : FileImplBase(aContentType, aLength)
     , mFile(aFile)
     , mWholeFile(true)
     , mStoredFile(true)
   {
     NS_ASSERTION(mFile, "must have file");
     mFileInfos.AppendElement(aFileInfo);
   }
 
   // Create as a file to be later initialized
-  DOMFileImplFile()
-    : DOMFileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
+  FileImplFile()
+    : FileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
     , mWholeFile(true)
     , mStoredFile(false)
   {
     // Lazily get the content type and size
     mContentType.SetIsVoid(true);
     mName.SetIsVoid(true);
   }
 
   // Overrides
-  virtual nsresult GetSize(uint64_t* aSize) MOZ_OVERRIDE;
-  virtual nsresult GetType(nsAString& aType) MOZ_OVERRIDE;
-  virtual nsresult GetLastModifiedDate(JSContext* aCx,
-                               JS::MutableHandle<JS::Value> aLastModifiedDate) MOZ_OVERRIDE;
-  virtual nsresult GetMozLastModifiedDate(uint64_t* aLastModifiedDate) MOZ_OVERRIDE;
-  virtual nsresult GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
+  virtual uint64_t GetSize(ErrorResult& aRv) MOZ_OVERRIDE;
+  virtual void GetType(nsAString& aType) MOZ_OVERRIDE;
+  virtual int64_t GetLastModified(ErrorResult& aRv) MOZ_OVERRIDE;
+  virtual void GetMozFullPathInternal(nsAString& aFullPath,
+                                      ErrorResult& aRv) MOZ_OVERRIDE;
   virtual nsresult GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
 
   void SetPath(const nsAString& aFullPath);
 
 protected:
-  virtual ~DOMFileImplFile() {}
+  virtual ~FileImplFile() {}
 
 private:
   // Create slice
-  DOMFileImplFile(const DOMFileImplFile* aOther, uint64_t aStart,
-                  uint64_t aLength, const nsAString& aContentType)
-    : DOMFileImplBase(aContentType, aOther->mStart + aStart, aLength)
+  FileImplFile(const FileImplFile* aOther, uint64_t aStart,
+               uint64_t aLength, const nsAString& aContentType)
+    : FileImplBase(aContentType, aOther->mStart + aStart, aLength)
     , mFile(aOther->mFile)
     , mWholeFile(false)
     , mStoredFile(aOther->mStoredFile)
   {
     NS_ASSERTION(mFile, "must have file");
     mImmutable = aOther->mImmutable;
 
     if (mStoredFile) {
@@ -719,99 +771,107 @@ private:
         mozilla::MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
         fileInfo = aOther->GetFileInfo();
       }
 
       mFileInfos.AppendElement(fileInfo);
     }
   }
 
-  virtual already_AddRefed<DOMFileImpl>
+  virtual already_AddRefed<FileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType, ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual bool IsStoredFile() const MOZ_OVERRIDE
   {
     return mStoredFile;
   }
 
   virtual bool IsWholeFile() const MOZ_OVERRIDE
   {
     return mWholeFile;
   }
 
   nsCOMPtr<nsIFile> mFile;
   bool mWholeFile;
   bool mStoredFile;
 };
 
-} // dom namespace
-} // file namespace
-
-class nsDOMFileList MOZ_FINAL : public nsIDOMFileList,
-                                public nsWrapperCache
+class FileList MOZ_FINAL : public nsIDOMFileList,
+                           public nsWrapperCache
 {
-  ~nsDOMFileList() {}
+  ~FileList() {}
 
 public:
-  explicit nsDOMFileList(nsISupports *aParent) : mParent(aParent)
+  explicit FileList(nsISupports *aParent) : mParent(aParent)
   {
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMFileList)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FileList)
 
   NS_DECL_NSIDOMFILELIST
 
   virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
   nsISupports* GetParentObject()
   {
     return mParent;
   }
 
   void Disconnect()
   {
     mParent = nullptr;
   }
 
-  bool Append(nsIDOMFile *aFile) { return mFiles.AppendObject(aFile); }
+  bool Append(File *aFile) { return mFiles.AppendElement(aFile); }
 
-  bool Remove(uint32_t aIndex) { return mFiles.RemoveObjectAt(aIndex); }
+  bool Remove(uint32_t aIndex) {
+    if (aIndex < mFiles.Length()) {
+      mFiles.RemoveElementAt(aIndex);
+      return true;
+    }
+
+    return false;
+  }
+
   void Clear() { return mFiles.Clear(); }
 
-  static nsDOMFileList* FromSupports(nsISupports* aSupports)
+  static FileList* FromSupports(nsISupports* aSupports)
   {
 #ifdef DEBUG
     {
       nsCOMPtr<nsIDOMFileList> list_qi = do_QueryInterface(aSupports);
 
       // If this assertion fires the QI implementation for the object in
       // question doesn't use the nsIDOMFileList pointer as the nsISupports
       // pointer. That must be fixed, or we'll crash...
       NS_ASSERTION(list_qi == static_cast<nsIDOMFileList*>(aSupports),
                    "Uh, fix QI!");
     }
 #endif
 
-    return static_cast<nsDOMFileList*>(aSupports);
+    return static_cast<FileList*>(aSupports);
   }
 
-  nsIDOMFile* Item(uint32_t aIndex)
+  File* Item(uint32_t aIndex)
   {
-    return mFiles.SafeObjectAt(aIndex);
+    return mFiles.SafeElementAt(aIndex);
   }
-  nsIDOMFile* IndexedGetter(uint32_t aIndex, bool& aFound)
+  File* IndexedGetter(uint32_t aIndex, bool& aFound)
   {
-    aFound = aIndex < static_cast<uint32_t>(mFiles.Count());
-    return aFound ? mFiles.ObjectAt(aIndex) : nullptr;
+    aFound = aIndex < mFiles.Length();
+    return aFound ? mFiles.ElementAt(aIndex) : nullptr;
   }
   uint32_t Length()
   {
-    return mFiles.Count();
+    return mFiles.Length();
   }
 
 private:
-  nsCOMArray<nsIDOMFile> mFiles;
+  nsTArray<nsRefPtr<File>> mFiles;
   nsISupports *mParent;
 };
 
-#endif
+} // dom namespace
+} // file namespace
+
+#endif // mozilla_dom_File_h
--- a/content/base/public/moz.build
+++ b/content/base/public/moz.build
@@ -38,17 +38,16 @@ EXPORTS += [
     'nsContentCID.h',
     'nsContentCreatorFunctions.h',
     'nsContentPolicyUtils.h',
     'nsContentTypeParser.h',
     'nsContentUtils.h',
     'nsCopySupport.h',
     'nsDeprecatedOperationList.h',
     'nsDocElementCreatedNotificationRunner.h',
-    'nsDOMFile.h',
     'nsHostObjectProtocolHandler.h',
     'nsIAttribute.h',
     'nsIContent.h',
     'nsIContentInlines.h',
     'nsIContentIterator.h',
     'nsIContentSerializer.h',
     'nsIDocument.h',
     'nsIDocumentInlines.h',
@@ -62,19 +61,21 @@ EXPORTS += [
     'nsNameSpaceManager.h',
     'nsReferencedElement.h',
     'nsTreeSanitizer.h',
     'nsViewportInfo.h',
     'nsXMLNameSpaceMap.h',
 ]
 
 EXPORTS.mozilla.dom += [
+    'BlobSet.h',
     'DirectionalityUtils.h',
     'Element.h',
     'ElementInlines.h',
+    'File.h',
     'FragmentOrElement.h',
     'FromParser.h',
 ]
 
 EXPORTS.mozilla += [
     'CORSMode.h',
 ]
 
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1664,16 +1664,17 @@ public:
 
   /**
    * Creates an arraybuffer from a binary string.
    */
   static nsresult CreateArrayBuffer(JSContext *aCx, const nsACString& aData,
                                     JSObject** aResult);
 
   static nsresult CreateBlobBuffer(JSContext* aCx,
+                                   nsISupports* aParent,
                                    const nsACString& aData,
                                    JS::MutableHandle<JS::Value> aBlob);
 
   static void StripNullChars(const nsAString& aInStr, nsAString& aOutStr);
 
   /**
    * Strip all \n, \r and nulls from the given string
    * @param aString the string to remove newlines from [in/out]
rename from content/base/src/nsDOMFile.cpp
rename to content/base/src/File.cpp
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/File.cpp
@@ -1,23 +1,22 @@
 /* -*- Mode: C++; tab-width: 2; 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 "nsDOMFile.h"
+#include "mozilla/dom/File.h"
 
+#include "MultipartFileImpl.h"
 #include "nsCExternalHandlerService.h"
 #include "nsContentCID.h"
 #include "nsContentUtils.h"
-#include "nsDOMClassInfoID.h"
 #include "nsError.h"
 #include "nsICharsetDetector.h"
-#include "nsIClassInfo.h"
 #include "nsIConverterInputStream.h"
 #include "nsIDocument.h"
 #include "nsIFileStreams.h"
 #include "nsIInputStream.h"
 #include "nsIIPCSerializableInputStream.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMIMEService.h"
 #include "nsISeekableStream.h"
@@ -30,36 +29,38 @@
 #include "nsHostObjectProtocolHandler.h"
 #include "nsStringStream.h"
 #include "nsJSUtils.h"
 #include "nsPrintfCString.h"
 #include "mozilla/SHA1.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/BlobBinding.h"
+#include "mozilla/dom/BlobSet.h"
+#include "mozilla/dom/DOMError.h"
+#include "mozilla/dom/FileBinding.h"
+#include "mozilla/dom/WorkerPrivate.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/dom/FileListBinding.h"
 
-DOMCI_DATA(File, mozilla::dom::DOMFile)
-DOMCI_DATA(Blob, mozilla::dom::DOMFile)
-
 namespace mozilla {
 namespace dom {
 
-// XXXkhuey the input stream that we pass out of a DOMFile
-// can outlive the actual DOMFile object.  Thus, we must
+// XXXkhuey the input stream that we pass out of a File
+// 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 MOZ_FINAL : public nsIInputStream,
                                    public nsISeekableStream,
                                    public nsIIPCSerializableInputStream
 {
-  typedef DOMFileImplMemory::DataOwner DataOwner;
+  typedef FileImplMemory::DataOwner DataOwner;
 public:
   static nsresult Create(DataOwner* aDataOwner,
                          uint32_t aStart,
                          uint32_t aLength,
                          nsIInputStream** _retval);
 
   NS_DECL_THREADSAFE_ISUPPORTS
 
@@ -118,252 +119,330 @@ nsresult DataOwnerAdapter::Create(DataOw
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ADDREF(*_retval = new DataOwnerAdapter(aDataOwner, stream));
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// mozilla::dom::DOMFile implementation
+// mozilla::dom::File implementation
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(DOMFile)
+NS_IMPL_CYCLE_COLLECTION_CLASS(File)
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMFile)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(File)
   MOZ_ASSERT(tmp->mImpl);
   tmp->mImpl->Unlink();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMFile)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(File)
   MOZ_ASSERT(tmp->mImpl);
   tmp->mImpl->Traverse(cb);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMFile)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(File)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(File)
   // This class should not receive any nsIRemoteBlob QI!
   MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsIRemoteBlob)));
 
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, IsFile())
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY(nsIMutable)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, IsFile())
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !(IsFile()))
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMFile)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMFile)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(File)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(File)
 
-/* static */ already_AddRefed<DOMFile>
-DOMFile::Create(const nsAString& aName, const nsAString& aContentType,
-                uint64_t aLength, uint64_t aLastModifiedDate)
+/* static */ already_AddRefed<File>
+File::Create(nsISupports* aParent, const nsAString& aName,
+             const nsAString& aContentType, uint64_t aLength,
+             uint64_t aLastModifiedDate)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
-    new DOMFileImplBase(aName, aContentType, aLength, aLastModifiedDate));
+  nsRefPtr<File> file = new File(aParent,
+    new FileImplBase(aName, aContentType, aLength, aLastModifiedDate));
   return file.forget();
 }
 
-/* static */ already_AddRefed<DOMFile>
-DOMFile::Create(const nsAString& aName, const nsAString& aContentType,
-                uint64_t aLength)
+/* static */ already_AddRefed<File>
+File::Create(nsISupports* aParent, const nsAString& aName,
+             const nsAString& aContentType, uint64_t aLength)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
-    new DOMFileImplBase(aName, aContentType, aLength));
+  nsRefPtr<File> file = new File(aParent,
+    new FileImplBase(aName, aContentType, aLength));
   return file.forget();
 }
 
-/* static */ already_AddRefed<DOMFile>
-DOMFile::Create(const nsAString& aContentType, uint64_t aLength)
+/* static */ already_AddRefed<File>
+File::Create(nsISupports* aParent, const nsAString& aContentType,
+             uint64_t aLength)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
-    new DOMFileImplBase(aContentType, aLength));
+  nsRefPtr<File> file = new File(aParent,
+    new FileImplBase(aContentType, aLength));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<File>
+File::Create(nsISupports* aParent, const nsAString& aContentType,
+                uint64_t aStart, uint64_t aLength)
+{
+  nsRefPtr<File> file = new File(aParent,
+    new FileImplBase(aContentType, aStart, aLength));
   return file.forget();
 }
 
-/* static */ already_AddRefed<DOMFile>
-DOMFile::Create(const nsAString& aContentType, uint64_t aStart,
-                uint64_t aLength)
+/* static */ already_AddRefed<File>
+File::CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer,
+                       uint64_t aLength, const nsAString& aName,
+                       const nsAString& aContentType,
+                       uint64_t aLastModifiedDate)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
-    new DOMFileImplBase(aContentType, aStart, aLength));
+  nsRefPtr<File> file = new File(aParent,
+    new FileImplMemory(aMemoryBuffer, aLength, aName,
+                       aContentType, aLastModifiedDate));
   return file.forget();
 }
 
-/* static */ already_AddRefed<DOMFile>
-DOMFile::CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
-                          const nsAString& aName,
-                          const nsAString& aContentType,
-                          uint64_t aLastModifiedDate)
+/* static */ already_AddRefed<File>
+File::CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer,
+                       uint64_t aLength, const nsAString& aContentType)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
-    new DOMFileImplMemory(aMemoryBuffer, aLength, aName,
-                          aContentType, aLastModifiedDate));
+  nsRefPtr<File> file = new File(aParent,
+    new FileImplMemory(aMemoryBuffer, aLength, aContentType));
   return file.forget();
 }
 
-/* static */ already_AddRefed<DOMFile>
-DOMFile::CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
-                          const nsAString& aContentType)
+/* static */ already_AddRefed<File>
+File::CreateTemporaryFileBlob(nsISupports* aParent, PRFileDesc* aFD,
+                              uint64_t aStartPos, uint64_t aLength,
+                              const nsAString& aContentType)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
-    new DOMFileImplMemory(aMemoryBuffer, aLength, aContentType));
+  nsRefPtr<File> file = new File(aParent,
+    new FileImplTemporaryFileBlob(aFD, aStartPos, aLength, aContentType));
   return file.forget();
 }
 
-/* static */ already_AddRefed<DOMFile>
-DOMFile::CreateTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos,
-                                 uint64_t aLength,
-                                      const nsAString& aContentType)
+/* static */ already_AddRefed<File>
+File::CreateFromFile(nsISupports* aParent, nsIFile* aFile)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
-    new DOMFileImplTemporaryFileBlob(aFD, aStartPos, aLength, aContentType));
+  nsRefPtr<File> file = new File(aParent, new FileImplFile(aFile));
   return file.forget();
 }
 
-/* static */ already_AddRefed<DOMFile>
-DOMFile::CreateFromFile(nsIFile* aFile)
+/* static */ already_AddRefed<File>
+File::CreateFromFile(nsISupports* aParent, const nsAString& aContentType,
+                     uint64_t aLength, nsIFile* aFile,
+                     indexedDB::FileInfo* aFileInfo)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(new DOMFileImplFile(aFile));
+  nsRefPtr<File> file = new File(aParent,
+    new FileImplFile(aContentType, aLength, aFile, aFileInfo));
   return file.forget();
 }
 
-/* static */ already_AddRefed<DOMFile>
-DOMFile::CreateFromFile(const nsAString& aContentType, uint64_t aLength,
-                        nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
+/* static */ already_AddRefed<File>
+File::CreateFromFile(nsISupports* aParent, const nsAString& aName,
+                     const nsAString& aContentType,
+                     uint64_t aLength, nsIFile* aFile,
+                     indexedDB::FileInfo* aFileInfo)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
-    new DOMFileImplFile(aContentType, aLength, aFile, 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<DOMFile>
-DOMFile::CreateFromFile(const nsAString& aName,
-                        const nsAString& aContentType,
-                        uint64_t aLength, nsIFile* aFile,
-                        indexedDB::FileInfo* aFileInfo)
+/* static */ already_AddRefed<File>
+File::CreateFromFile(nsISupports* aParent, nsIFile* aFile,
+                     const nsAString& aName, const nsAString& aContentType)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(
-    new DOMFileImplFile(aName, aContentType, aLength, aFile, aFileInfo));
+  nsRefPtr<File> file = new File(aParent,
+    new FileImplFile(aFile, aName, aContentType));
   return file.forget();
 }
 
-/* static */ already_AddRefed<DOMFile>
-DOMFile::CreateFromFile(nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
+File::File(nsISupports* aParent, FileImpl* aImpl)
+  : mImpl(aImpl)
+  , mParent(aParent)
 {
-  nsRefPtr<DOMFile> file = new DOMFile(new DOMFileImplFile(aFile, aFileInfo));
-  return file.forget();
+  MOZ_ASSERT(mImpl);
+
+#ifdef DEBUG
+  {
+    nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aParent);
+    if (win) {
+      MOZ_ASSERT(win->IsInnerWindow());
+    }
+  }
+#endif
 }
 
-/* static */ already_AddRefed<DOMFile>
-DOMFile::CreateFromFile(nsIFile* aFile, const nsAString& aName,
-                        const nsAString& aContentType)
-{
-  nsRefPtr<DOMFile> file = new DOMFile(
-    new DOMFileImplFile(aFile, aName, aContentType));
-  return file.forget();
-}
-
-const nsTArray<nsRefPtr<DOMFileImpl>>*
-DOMFile::GetSubBlobImpls() const
+const nsTArray<nsRefPtr<FileImpl>>*
+File::GetSubBlobImpls() const
 {
   return mImpl->GetSubBlobImpls();
 }
 
 bool
-DOMFile::IsSizeUnknown() const
+File::IsSizeUnknown() const
 {
   return mImpl->IsSizeUnknown();
 }
 
 bool
-DOMFile::IsDateUnknown() const
+File::IsDateUnknown() const
 {
   return mImpl->IsDateUnknown();
 }
 
 bool
-DOMFile::IsFile() const
+File::IsFile() const
 {
   return mImpl->IsFile();
 }
 
 void
-DOMFile::SetLazyData(const nsAString& aName, const nsAString& aContentType,
+File::SetLazyData(const nsAString& aName, const nsAString& aContentType,
                      uint64_t aLength, uint64_t aLastModifiedDate)
 {
   return mImpl->SetLazyData(aName, aContentType, aLength, aLastModifiedDate);
 }
 
-already_AddRefed<nsIDOMBlob>
-DOMFile::CreateSlice(uint64_t aStart, uint64_t aLength,
-                     const nsAString& aContentType)
+already_AddRefed<File>
+File::CreateSlice(uint64_t aStart, uint64_t aLength,
+                  const nsAString& aContentType,
+                  ErrorResult& aRv)
 {
-  nsRefPtr<DOMFileImpl> impl =
-    mImpl->CreateSlice(aStart, aLength, aContentType);
-  nsRefPtr<DOMFile> slice = new DOMFile(impl);
-  return slice.forget();
+  nsRefPtr<FileImpl> impl = mImpl->CreateSlice(aStart, aLength,
+                                               aContentType, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  nsRefPtr<File> file = new File(mParent, impl);
+  return file.forget();
 }
 
 NS_IMETHODIMP
-DOMFile::Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
-                    const JS::CallArgs& aArgs)
+File::GetName(nsAString& aFileName)
 {
-  return mImpl->Initialize(aOwner, aCx, aObj, aArgs);
+  mImpl->GetName(aFileName);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
-DOMFile::GetName(nsAString& aFileName)
-{
-  return mImpl->GetName(aFileName);
-}
-
-NS_IMETHODIMP
-DOMFile::GetPath(nsAString& aPath)
+File::GetPath(nsAString& aPath)
 {
   return mImpl->GetPath(aPath);
 }
 
 NS_IMETHODIMP
-DOMFile::GetLastModifiedDate(JSContext* aCx,
+File::GetLastModifiedDate(JSContext* aCx,
                              JS::MutableHandle<JS::Value> aDate)
 {
-  return mImpl->GetLastModifiedDate(aCx, aDate);
+  ErrorResult rv;
+  Date value = GetLastModifiedDate(rv);
+  if (rv.Failed()) {
+    return rv.ErrorCode();
+  }
+
+  if (!value.ToDateObject(aCx, aDate)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  return NS_OK;
 }
 
-NS_IMETHODIMP
-DOMFile::GetMozFullPath(nsAString &aFileName)
+Date
+File::GetLastModifiedDate(ErrorResult& aRv)
 {
-  return mImpl->GetMozFullPath(aFileName);
+  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
-DOMFile::GetMozFullPathInternal(nsAString &aFileName)
+File::GetMozFullPath(nsAString& aFileName)
+{
+  ErrorResult rv;
+  GetMozFullPath(aFileName, rv);
+  return rv.ErrorCode();
+}
+
+void
+File::GetMozFullPath(nsAString& aFilename, ErrorResult& aRv)
 {
-  return mImpl->GetMozFullPathInternal(aFileName);
+  mImpl->GetMozFullPath(aFilename, aRv);
+}
+
+NS_IMETHODIMP
+File::GetMozFullPathInternal(nsAString& aFileName)
+{
+  ErrorResult rv;
+  mImpl->GetMozFullPathInternal(aFileName, rv);
+  return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
-DOMFile::GetSize(uint64_t* aSize)
+File::GetSize(uint64_t* aSize)
 {
-  return mImpl->GetSize(aSize);
+  MOZ_ASSERT(aSize);
+
+  ErrorResult rv;
+  *aSize = GetSize(rv);
+  return rv.ErrorCode();
+}
+
+uint64_t
+File::GetSize(ErrorResult& aRv)
+{
+  return mImpl->GetSize(aRv);
 }
 
 NS_IMETHODIMP
-DOMFile::GetType(nsAString &aType)
+File::GetType(nsAString &aType)
 {
-  return mImpl->GetType(aType);
+  mImpl->GetType(aType);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
-DOMFile::GetMozLastModifiedDate(uint64_t* aDate)
+File::GetMozLastModifiedDate(uint64_t* aDate)
 {
-  return mImpl->GetMozLastModifiedDate(aDate);
+  MOZ_ASSERT(aDate);
+
+  ErrorResult rv;
+  *aDate = GetLastModified(rv);
+  return rv.ErrorCode();
 }
 
 // Makes sure that aStart and aEnd is less then or equal to aSize and greater
 // than 0
 static void
 ParseSize(int64_t aSize, int64_t& aStart, int64_t& aEnd)
 {
   CheckedInt64 newStartOffset = aStart;
@@ -394,224 +473,339 @@ ParseSize(int64_t aSize, int64_t& aStart
   }
   else {
     aStart = newStartOffset.value();
     aEnd = newEndOffset.value();
   }
 }
 
 NS_IMETHODIMP
-DOMFile::Slice(int64_t aStart, int64_t aEnd,
-               const nsAString& aContentType, uint8_t aArgc,
-               nsIDOMBlob **aBlob)
+File::Slice(int64_t aStart, int64_t aEnd,
+            const nsAString& aContentType, uint8_t aArgc,
+            nsIDOMBlob **aBlob)
 {
-  MOZ_ASSERT(mImpl);
-  nsRefPtr<DOMFileImpl> impl;
-  nsresult rv = mImpl->Slice(aStart, aEnd, aContentType, aArgc,
-                             getter_AddRefs(impl));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+  Optional<int64_t> start;
+  if (aArgc > 0) {
+    start.Construct(aStart);
   }
 
-  nsRefPtr<DOMFile> blob = new DOMFile(impl);
-  blob.forget(aBlob);
+  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.ErrorCode();
+  }
+
+  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
-DOMFile::GetInternalStream(nsIInputStream** aStream)
+File::GetInternalStream(nsIInputStream** aStream)
 {
- return mImpl->GetInternalStream(aStream);
+  return mImpl->GetInternalStream(aStream);
 }
 
 NS_IMETHODIMP_(int64_t)
-DOMFile::GetFileId()
+File::GetFileId()
 {
   return mImpl->GetFileId();
 }
 
 NS_IMETHODIMP_(void)
-DOMFile::AddFileInfo(indexedDB::FileInfo* aFileInfo)
+File::AddFileInfo(indexedDB::FileInfo* aFileInfo)
 {
   mImpl->AddFileInfo(aFileInfo);
 }
 
 indexedDB::FileInfo*
-DOMFile::GetFileInfo(indexedDB::FileManager* aFileManager)
+File::GetFileInfo(indexedDB::FileManager* aFileManager)
 {
   return mImpl->GetFileInfo(aFileManager);
 }
 
 NS_IMETHODIMP
-DOMFile::GetSendInfo(nsIInputStream** aBody,
-                     uint64_t* aContentLength,
-                     nsACString& aContentType,
-                     nsACString& aCharset)
+File::GetSendInfo(nsIInputStream** aBody,
+                  uint64_t* aContentLength,
+                  nsACString& aContentType,
+                  nsACString& aCharset)
 {
   return mImpl->GetSendInfo(aBody, aContentLength, aContentType, aCharset);
 }
 
 NS_IMETHODIMP
-DOMFile::GetMutable(bool* aMutable)
+File::GetMutable(bool* aMutable)
 {
   return mImpl->GetMutable(aMutable);
 }
 
 NS_IMETHODIMP
-DOMFile::SetMutable(bool aMutable)
+File::SetMutable(bool aMutable)
 {
   return mImpl->SetMutable(aMutable);
 }
 
 NS_IMETHODIMP_(bool)
-DOMFile::IsMemoryFile()
+File::IsMemoryFile()
 {
   return mImpl->IsMemoryFile();
 }
 
-////////////////////////////////////////////////////////////////////////////
-// mozilla::dom::DOMFileImpl implementation
+JSObject*
+File::WrapObject(JSContext* aCx)
+{
+  return IsFile() ? FileBinding::Wrap(aCx, this)
+                  : BlobBinding::Wrap(aCx, this);
+}
+
+/* static */ already_AddRefed<File>
+File::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl();
 
-nsresult
-DOMFileImpl::Slice(int64_t aStart, int64_t aEnd,
-                   const nsAString& aContentType, uint8_t aArgc,
-                   DOMFileImpl** aBlobImpl)
+  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)
 {
-  *aBlobImpl = nullptr;
+  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();
+}
 
-  // Truncate aStart and aEnd so that we stay within this file.
-  uint64_t thisLength;
-  nsresult rv = GetSize(&thisLength);
-  NS_ENSURE_SUCCESS(rv, rv);
+/* 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);
 
-  if (aArgc < 2) {
-    aEnd = (int64_t)thisLength;
+  impl->InitializeBlob(aGlobal.Context(), aData, aBag.mType, false, 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,
+                  File& aData,
+                  const ChromeFilePropertyBag& aBag,
+                  ErrorResult& aRv)
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  ParseSize((int64_t)thisLength, aStart, aEnd);
+  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl(EmptyString());
+  impl->InitializeChromeFile(aData, aBag, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+  MOZ_ASSERT(impl->IsFile());
 
-  nsRefPtr<DOMFileImpl> impl =
-    CreateSlice((uint64_t)aStart, (uint64_t)(aEnd - aStart), aContentType);
+  nsRefPtr<File> domFile = new File(aGlobal.GetAsSupports(), impl);
+  return domFile.forget();
+}
 
-  if (!impl) {
-    return NS_ERROR_UNEXPECTED;
+/* static */ already_AddRefed<File>
+File::Constructor(const GlobalObject& aGlobal,
+                  nsIFile* aData,
+                  const ChromeFilePropertyBag& aBag,
+                  ErrorResult& aRv)
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  impl.forget(aBlobImpl);
-  return NS_OK;
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+
+  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl(EmptyString());
+  impl->InitializeChromeFile(window, aData, aBag, true, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+  MOZ_ASSERT(impl->IsFile());
+
+  nsRefPtr<File> domFile = new File(aGlobal.GetAsSupports(), impl);
+  return domFile.forget();
+}
+
+/* static */ already_AddRefed<File>
+File::Constructor(const GlobalObject& aGlobal,
+                  const nsAString& aData,
+                  const ChromeFilePropertyBag& aBag,
+                  ErrorResult& aRv)
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+
+  nsRefPtr<MultipartFileImpl> impl = new MultipartFileImpl(EmptyString());
+  impl->InitializeChromeFile(window, aData, aBag, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+  MOZ_ASSERT(impl->IsFile());
+
+  nsRefPtr<File> domFile = new File(aGlobal.GetAsSupports(), impl);
+  return domFile.forget();
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// DOMFileImpl implementation
+// mozilla::dom::FileImpl implementation
 
-NS_IMPL_ISUPPORTS(DOMFileImpl, PIDOMFileImpl)
+already_AddRefed<FileImpl>
+FileImpl::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;
+  }
+
+  int64_t start = aStart.WasPassed() ? aStart.Value() : 0;
+  int64_t end = aEnd.WasPassed() ? aEnd.Value() : (int64_t)thisLength;
+
+  ParseSize((int64_t)thisLength, start, end);
+
+  return CreateSlice((uint64_t)start, (uint64_t)(end - start),
+                     aContentType, aRv);
+}
 
 ////////////////////////////////////////////////////////////////////////////
-// DOMFileImplFile implementation
+// FileImpl implementation
+
+NS_IMPL_ISUPPORTS(FileImpl, PIFileImpl)
 
-NS_IMPL_ISUPPORTS_INHERITED0(DOMFileImplFile, DOMFileImpl)
+////////////////////////////////////////////////////////////////////////////
+// FileImplFile implementation
 
-nsresult
-DOMFileImplBase::GetName(nsAString& aName)
+NS_IMPL_ISUPPORTS_INHERITED0(FileImplFile, FileImpl)
+
+void
+FileImplBase::GetName(nsAString& aName)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   aName = mName;
-  return NS_OK;
 }
 
 nsresult
-DOMFileImplBase::GetPath(nsAString& aPath)
+FileImplBase::GetPath(nsAString& aPath)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   aPath = mPath;
   return NS_OK;
 }
 
-nsresult
-DOMFileImplBase::GetLastModifiedDate(JSContext* aCx,
-                                     JS::MutableHandle<JS::Value> aDate)
-{
-  JS::Rooted<JSObject*> date(aCx, JS_NewDateObjectMsec(aCx, JS_Now() / PR_USEC_PER_MSEC));
-  if (!date) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  aDate.setObject(*date);
-  return NS_OK;
-}
-
-nsresult
-DOMFileImplBase::GetMozFullPath(nsAString &aFileName)
+void
+FileImplBase::GetMozFullPath(nsAString& aFileName, ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
 
-  // It is unsafe to call IsCallerChrome on a non-main thread. If
-  // you hit the following assertion you need to figure out some other way to
-  // determine privileges and call GetMozFullPathInternal.
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  aFileName.Truncate();
+
+  if (NS_IsMainThread()) {
+    if (nsContentUtils::IsCallerChrome()) {
+      GetMozFullPathInternal(aFileName, aRv);
+    }
 
-  if (nsContentUtils::IsCallerChrome()) {
-    return GetMozFullPathInternal(aFileName);
+    return;
   }
-  aFileName.Truncate();
-  return NS_OK;
+
+  workers::WorkerPrivate* workerPrivate =
+    workers::GetCurrentThreadWorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
+
+  if (workerPrivate->UsesSystemPrincipal()) {
+    GetMozFullPathInternal(aFileName, aRv);
+  }
 }
 
-nsresult
-DOMFileImplBase::GetMozFullPathInternal(nsAString& aFileName)
+void
+FileImplBase::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv)
 {
   if (!mIsFile) {
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
   }
 
   aFileName.Truncate();
-  return NS_OK;
-}
-
-nsresult
-DOMFileImplBase::GetSize(uint64_t* aSize)
-{
-  *aSize = mLength;
-  return NS_OK;
 }
 
-nsresult
-DOMFileImplBase::GetType(nsAString& aType)
+void
+FileImplBase::GetType(nsAString& aType)
 {
   aType = mContentType;
-  return NS_OK;
 }
 
-nsresult
-DOMFileImplBase::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
+int64_t
+FileImplBase::GetLastModified(ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   if (IsDateUnknown()) {
     mLastModificationDate = PR_Now();
   }
-  *aLastModifiedDate = mLastModificationDate;
-  return NS_OK;
-}
 
-already_AddRefed<DOMFileImpl>
-DOMFileImplBase::CreateSlice(uint64_t aStart, uint64_t aLength,
-                             const nsAString& aContentType)
-{
-  return nullptr;
-}
-
-nsresult
-DOMFileImplBase::GetInternalStream(nsIInputStream** aStream)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
+  return mLastModificationDate / PR_USEC_PER_MSEC;
 }
 
 int64_t
-DOMFileImplBase::GetFileId()
+FileImplBase::GetFileId()
 {
   int64_t id = -1;
 
   if (IsStoredFile() && IsWholeFile() && !IsSnapshot()) {
     if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
       indexedDB::IndexedDatabaseManager::FileMutex().Lock();
     }
 
@@ -627,17 +821,17 @@ DOMFileImplBase::GetFileId()
       indexedDB::IndexedDatabaseManager::FileMutex().Unlock();
     }
   }
 
   return id;
 }
 
 void
-DOMFileImplBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
+FileImplBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
 {
   if (indexedDB::IndexedDatabaseManager::IsClosed()) {
     NS_ERROR("Shouldn't be called after shutdown!");
     return;
   }
 
   nsRefPtr<indexedDB::FileInfo> fileInfo = aFileInfo;
 
@@ -646,17 +840,17 @@ DOMFileImplBase::AddFileInfo(indexedDB::
   NS_ASSERTION(!mFileInfos.Contains(aFileInfo),
                "Adding the same file info agan?!");
 
   nsRefPtr<indexedDB::FileInfo>* element = mFileInfos.AppendElement();
   element->swap(fileInfo);
 }
 
 indexedDB::FileInfo*
-DOMFileImplBase::GetFileInfo(indexedDB::FileManager* aFileManager)
+FileImplBase::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
@@ -678,263 +872,246 @@ DOMFileImplBase::GetFileInfo(indexedDB::
       return fileInfo;
     }
   }
 
   return nullptr;
 }
 
 nsresult
-DOMFileImplBase::GetSendInfo(nsIInputStream** aBody,
-                             uint64_t* aContentLength,
-                             nsACString& aContentType,
-                             nsACString& aCharset)
+FileImplBase::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
+                          nsACString& aContentType, nsACString& aCharset)
 {
+  MOZ_ASSERT(aContentLength);
+
   nsresult rv;
 
   nsCOMPtr<nsIInputStream> stream;
-  rv = this->GetInternalStream(getter_AddRefs(stream));
+  rv = GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = this->GetSize(aContentLength);
-  NS_ENSURE_SUCCESS(rv, rv);
+  ErrorResult error;
+  *aContentLength = GetSize(error);
+  if (NS_WARN_IF(error.Failed())) {
+    return error.ErrorCode();
+  }
 
-  nsString contentType;
-  rv = this->GetType(contentType);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsAutoString contentType;
+  GetType(contentType);
 
   CopyUTF16toUTF8(contentType, aContentType);
 
   aCharset.Truncate();
 
   stream.forget(aBody);
   return NS_OK;
 }
 
 nsresult
-DOMFileImplBase::GetMutable(bool* aMutable) const
+FileImplBase::GetMutable(bool* aMutable) const
 {
   *aMutable = !mImmutable;
   return NS_OK;
 }
 
 nsresult
-DOMFileImplBase::SetMutable(bool aMutable)
+FileImplBase::SetMutable(bool aMutable)
 {
   nsresult rv = NS_OK;
 
   NS_ENSURE_ARG(!mImmutable || !aMutable);
 
   if (!mImmutable && !aMutable) {
     // Force the content type and size to be cached
-    nsString dummyString;
-    rv = this->GetType(dummyString);
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsAutoString dummyString;
+    GetType(dummyString);
 
-    uint64_t dummyInt;
-    rv = this->GetSize(&dummyInt);
-    NS_ENSURE_SUCCESS(rv, rv);
+    ErrorResult error;
+    GetSize(error);
+    if (NS_WARN_IF(error.Failed())) {
+      return error.ErrorCode();
+    }
   }
 
   mImmutable = !aMutable;
   return rv;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// DOMFileImplFile implementation
+// FileImplFile implementation
 
-already_AddRefed<DOMFileImpl>
-DOMFileImplFile::CreateSlice(uint64_t aStart, uint64_t aLength,
-                             const nsAString& aContentType)
+already_AddRefed<FileImpl>
+FileImplFile::CreateSlice(uint64_t aStart, uint64_t aLength,
+                          const nsAString& aContentType,
+                          ErrorResult& aRv)
 {
-  nsRefPtr<DOMFileImpl> impl =
-    new DOMFileImplFile(this, aStart, aLength, aContentType);
+  nsRefPtr<FileImpl> impl =
+    new FileImplFile(this, aStart, aLength, aContentType);
   return impl.forget();
 }
 
-nsresult
-DOMFileImplFile::GetMozFullPathInternal(nsAString& aFilename)
-{
-  NS_ASSERTION(mIsFile, "Should only be called on files");
-  return mFile->GetPath(aFilename);
-}
-
-nsresult
-DOMFileImplFile::GetLastModifiedDate(JSContext* aCx,
-                                     JS::MutableHandle<JS::Value> aLastModifiedDate)
+void
+FileImplFile::GetMozFullPathInternal(nsAString& aFilename, ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
-
-  PRTime msecs;
-  if (IsDateUnknown()) {
-    nsresult rv = mFile->GetLastModifiedTime(&msecs);
-    NS_ENSURE_SUCCESS(rv, rv);
-    mLastModificationDate = msecs;
-  } else {
-    msecs = mLastModificationDate;
-  }
-
-  JSObject* date = JS_NewDateObjectMsec(aCx, msecs);
-  if (date) {
-    aLastModifiedDate.setObject(*date);
-  }
-  else {
-    date = JS_NewDateObjectMsec(aCx, JS_Now() / PR_USEC_PER_MSEC);
-    aLastModifiedDate.setObject(*date);
-  }
-
-  return NS_OK;
+  aRv = mFile->GetPath(aFilename);
 }
 
-nsresult
-DOMFileImplFile::GetSize(uint64_t* aFileSize)
+uint64_t
+FileImplFile::GetSize(ErrorResult& aRv)
 {
   if (IsSizeUnknown()) {
     NS_ASSERTION(mWholeFile,
                  "Should only use lazy size when using the whole file");
     int64_t fileSize;
-    nsresult rv = mFile->GetFileSize(&fileSize);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aRv = mFile->GetFileSize(&fileSize);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return 0;
+    }
 
     if (fileSize < 0) {
-      return NS_ERROR_FAILURE;
+      aRv.Throw(NS_ERROR_FAILURE);
+      return 0;
     }
 
     mLength = fileSize;
   }
 
-  *aFileSize = mLength;
-
-  return NS_OK;
+  return mLength;
 }
 
-nsresult
-DOMFileImplFile::GetType(nsAString& aType)
+void
+FileImplFile::GetType(nsAString& aType)
 {
   if (mContentType.IsVoid()) {
     NS_ASSERTION(mWholeFile,
                  "Should only use lazy ContentType when using the whole file");
     nsresult rv;
     nsCOMPtr<nsIMIMEService> mimeService =
       do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      aType.Truncate();
+      return;
+    }
 
     nsAutoCString mimeType;
     rv = mimeService->GetTypeFromFile(mFile, mimeType);
     if (NS_FAILED(rv)) {
       mimeType.Truncate();
     }
 
     AppendUTF8toUTF16(mimeType, mContentType);
     mContentType.SetIsVoid(false);
   }
 
   aType = mContentType;
-
-  return NS_OK;
 }
 
-nsresult
-DOMFileImplFile::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
+int64_t
+FileImplFile::GetLastModified(ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   if (IsDateUnknown()) {
     PRTime msecs;
-    nsresult rv = mFile->GetLastModifiedTime(&msecs);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aRv = mFile->GetLastModifiedTime(&msecs);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return 0;
+    }
+
     mLastModificationDate = msecs;
   }
-  *aLastModifiedDate = mLastModificationDate;
-  return NS_OK;
+
+  return mLastModificationDate;
 }
 
 const uint32_t sFileStreamFlags =
   nsIFileInputStream::CLOSE_ON_EOF |
   nsIFileInputStream::REOPEN_ON_REWIND |
   nsIFileInputStream::DEFER_OPEN |
   nsIFileInputStream::SHARE_DELETE;
 
 nsresult
-DOMFileImplFile::GetInternalStream(nsIInputStream** aStream)
+FileImplFile::GetInternalStream(nsIInputStream** aStream)
 {
   return mWholeFile ?
     NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags) :
     NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
                                       -1, -1, sFileStreamFlags);
 }
 
 void
-DOMFileImplFile::SetPath(const nsAString& aPath)
+FileImplFile::SetPath(const nsAString& aPath)
 {
   MOZ_ASSERT(aPath.IsEmpty() ||
              aPath[aPath.Length() - 1] == char16_t('/'),
              "Path must end with a path separator");
   mPath = aPath;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// DOMFileImplMemory implementation
+// FileImplMemory implementation
 
-NS_IMPL_ISUPPORTS_INHERITED0(DOMFileImplMemory, DOMFileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(FileImplMemory, FileImpl)
 
-already_AddRefed<DOMFileImpl>
-DOMFileImplMemory::CreateSlice(uint64_t aStart, uint64_t aLength,
-                               const nsAString& aContentType)
+already_AddRefed<FileImpl>
+FileImplMemory::CreateSlice(uint64_t aStart, uint64_t aLength,
+                            const nsAString& aContentType,
+                            ErrorResult& aRv)
 {
-  nsRefPtr<DOMFileImpl> impl =
-    new DOMFileImplMemory(this, aStart, aLength, aContentType);
+  nsRefPtr<FileImpl> impl =
+    new FileImplMemory(this, aStart, aLength, aContentType);
   return impl.forget();
 }
 
 nsresult
-DOMFileImplMemory::GetInternalStream(nsIInputStream** aStream)
+FileImplMemory::GetInternalStream(nsIInputStream** aStream)
 {
   if (mLength > INT32_MAX)
     return NS_ERROR_FAILURE;
 
   return DataOwnerAdapter::Create(mDataOwner, mStart, mLength, aStream);
 }
 
 /* static */ StaticMutex
-DOMFileImplMemory::DataOwner::sDataOwnerMutex;
+FileImplMemory::DataOwner::sDataOwnerMutex;
 
-/* static */ StaticAutoPtr<LinkedList<DOMFileImplMemory::DataOwner>>
-DOMFileImplMemory::DataOwner::sDataOwners;
+/* static */ StaticAutoPtr<LinkedList<FileImplMemory::DataOwner>>
+FileImplMemory::DataOwner::sDataOwners;
 
 /* static */ bool
-DOMFileImplMemory::DataOwner::sMemoryReporterRegistered = false;
+FileImplMemory::DataOwner::sMemoryReporterRegistered = false;
 
-MOZ_DEFINE_MALLOC_SIZE_OF(DOMMemoryFileDataOwnerMallocSizeOf)
+MOZ_DEFINE_MALLOC_SIZE_OF(MemoryFileDataOwnerMallocSizeOf)
 
-class DOMFileImplMemoryDataOwnerMemoryReporter MOZ_FINAL
+class FileImplMemoryDataOwnerMemoryReporter MOZ_FINAL
   : public nsIMemoryReporter
 {
-  ~DOMFileImplMemoryDataOwnerMemoryReporter() {}
+  ~FileImplMemoryDataOwnerMemoryReporter() {}
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCallback,
                             nsISupports *aClosure, bool aAnonymize)
   {
-    typedef DOMFileImplMemory::DataOwner DataOwner;
+    typedef FileImplMemory::DataOwner DataOwner;
 
     StaticMutexAutoLock lock(DataOwner::sDataOwnerMutex);
 
     if (!DataOwner::sDataOwners) {
       return NS_OK;
     }
 
     const size_t LARGE_OBJECT_MIN_SIZE = 8 * 1024;
     size_t smallObjectsTotal = 0;
 
     for (DataOwner *owner = DataOwner::sDataOwners->getFirst();
          owner; owner = owner->getNext()) {
 
-      size_t size = DOMMemoryFileDataOwnerMallocSizeOf(owner->mData);
+      size_t size = MemoryFileDataOwnerMallocSizeOf(owner->mData);
 
       if (size < LARGE_OBJECT_MIN_SIZE) {
         smallObjectsTotal += size;
       } else {
         SHA1Sum sha1;
         sha1.update(owner->mData, owner->mLength);
         uint8_t digest[SHA1Sum::kHashSize]; // SHA1 digests are 20 bytes long.
         sha1.finish(digest);
@@ -975,88 +1152,156 @@ public:
         aClosure);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return NS_OK;
   }
 };
 
-NS_IMPL_ISUPPORTS(DOMFileImplMemoryDataOwnerMemoryReporter, nsIMemoryReporter)
+NS_IMPL_ISUPPORTS(FileImplMemoryDataOwnerMemoryReporter, nsIMemoryReporter)
 
 /* static */ void
-DOMFileImplMemory::DataOwner::EnsureMemoryReporterRegistered()
+FileImplMemory::DataOwner::EnsureMemoryReporterRegistered()
 {
   sDataOwnerMutex.AssertCurrentThreadOwns();
   if (sMemoryReporterRegistered) {
     return;
   }
 
-  RegisterStrongMemoryReporter(new DOMFileImplMemoryDataOwnerMemoryReporter());
+  RegisterStrongMemoryReporter(new FileImplMemoryDataOwnerMemoryReporter());
 
   sMemoryReporterRegistered = true;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// DOMFileImplTemporaryFileBlob implementation
+// FileImplTemporaryFileBlob implementation
 
-NS_IMPL_ISUPPORTS_INHERITED0(DOMFileImplTemporaryFileBlob, DOMFileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(FileImplTemporaryFileBlob, FileImpl)
 
-already_AddRefed<DOMFileImpl>
-DOMFileImplTemporaryFileBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
-                                          const nsAString& aContentType)
+already_AddRefed<FileImpl>
+FileImplTemporaryFileBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
+                                       const nsAString& aContentType,
+                                       ErrorResult& aRv)
 {
-  if (aStart + aLength > mLength)
+  if (aStart + aLength > mLength) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
+  }
 
-  nsRefPtr<DOMFileImpl> impl =
-    new DOMFileImplTemporaryFileBlob(this, aStart + mStartPos, aLength,
-                                     aContentType);
+  nsRefPtr<FileImpl> impl =
+    new FileImplTemporaryFileBlob(this, aStart + mStartPos,
+                                  aLength, aContentType);
   return impl.forget();
 }
 
 nsresult
-DOMFileImplTemporaryFileBlob::GetInternalStream(nsIInputStream** aStream)
+FileImplTemporaryFileBlob::GetInternalStream(nsIInputStream** aStream)
 {
   nsCOMPtr<nsIInputStream> stream =
     new nsTemporaryFileInputStream(mFileDescOwner, mStartPos, mStartPos + mLength);
   stream.forget(aStream);
   return NS_OK;
 }
 
-} // dom namespace
-} // mozilla namespace
+////////////////////////////////////////////////////////////////////////////
+// FileList implementation
 
-////////////////////////////////////////////////////////////////////////////
-// nsDOMFileList implementation
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileList, mFiles)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsDOMFileList)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileList)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileList)
   NS_INTERFACE_MAP_ENTRY(nsIDOMFileList)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileList)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileList)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(FileList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(FileList)
 
 JSObject*
-nsDOMFileList::WrapObject(JSContext *cx)
+FileList::WrapObject(JSContext *cx)
 {
   return mozilla::dom::FileListBinding::Wrap(cx, this);
 }
 
 NS_IMETHODIMP
-nsDOMFileList::GetLength(uint32_t* aLength)
+FileList::GetLength(uint32_t* aLength)
 {
   *aLength = Length();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMFileList::Item(uint32_t aIndex, nsIDOMFile **aFile)
+FileList::Item(uint32_t aIndex, nsIDOMFile **aFile)
+{
+  nsRefPtr<File> file = Item(aIndex);
+  file.forget(aFile);
+  return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// BlobSet implementation
+
+already_AddRefed<File>
+BlobSet::GetBlobInternal(nsISupports* aParent, const nsACString& aContentType)
+{
+  nsRefPtr<File> blob = new File(aParent,
+    new MultipartFileImpl(GetBlobImpls(),
+                          NS_ConvertASCIItoUTF16(aContentType)));
+  return blob.forget();
+}
+
+nsresult
+BlobSet::AppendVoidPtr(const void* aData, uint32_t aLength)
 {
-  NS_IF_ADDREF(*aFile = Item(aIndex));
+  NS_ENSURE_ARG_POINTER(aData);
+
+  uint64_t offset = mDataLen;
+
+  if (!ExpandBufferSize(aLength))
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  memcpy((char*)mData + offset, aData, aLength);
+  return NS_OK;
+}
+
+nsresult
+BlobSet::AppendString(const nsAString& aString, bool nativeEOL, JSContext* aCx)
+{
+  nsCString utf8Str = NS_ConvertUTF16toUTF8(aString);
+
+  if (nativeEOL) {
+    if (utf8Str.FindChar('\r') != kNotFound) {
+      utf8Str.ReplaceSubstring("\r\n", "\n");
+      utf8Str.ReplaceSubstring("\r", "\n");
+    }
+#ifdef XP_WIN
+    utf8Str.ReplaceSubstring("\n", "\r\n");
+#endif
+  }
+
+  return AppendVoidPtr((void*)utf8Str.Data(),
+                       utf8Str.Length());
+}
+
+nsresult
+BlobSet::AppendBlobImpl(FileImpl* aBlobImpl)
+{
+  NS_ENSURE_ARG_POINTER(aBlobImpl);
+
+  Flush();
+  mBlobImpls.AppendElement(aBlobImpl);
 
   return NS_OK;
 }
+
+nsresult
+BlobSet::AppendBlobImpls(const nsTArray<nsRefPtr<FileImpl>>& aBlobImpls)
+{
+  Flush();
+  mBlobImpls.AppendElements(aBlobImpls);
+
+  return NS_OK;
+}
+
+} // dom namespace
+} // mozilla namespace
--- a/content/base/src/FileIOObject.cpp
+++ b/content/base/src/FileIOObject.cpp
@@ -1,20 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FileIOObject.h"
+#include "mozilla/dom/File.h"
+#include "mozilla/dom/ProgressEvent.h"
 #include "mozilla/EventDispatcher.h"
-#include "nsDOMFile.h"
+#include "nsComponentManagerUtils.h"
 #include "nsError.h"
 #include "nsIDOMEvent.h"
-#include "mozilla/dom/ProgressEvent.h"
-#include "nsComponentManagerUtils.h"
 
 #define ERROR_STR "error"
 #define ABORT_STR "abort"
 #define PROGRESS_STR "progress"
 
 namespace mozilla {
 namespace dom {
 
rename from content/base/src/nsDOMBlobBuilder.cpp
rename to content/base/src/MultipartFileImpl.cpp
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/MultipartFileImpl.cpp
@@ -1,520 +1,353 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsDOMBlobBuilder.h"
+#include "MultipartFileImpl.h"
 #include "jsfriendapi.h"
-#include "mozilla/dom/BlobBinding.h"
+#include "mozilla/dom/BlobSet.h"
 #include "mozilla/dom/FileBinding.h"
 #include "nsAutoPtr.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsStringStream.h"
 #include "nsTArray.h"
 #include "nsJSUtils.h"
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsIXPConnect.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_ISUPPORTS_INHERITED0(DOMMultipartFileImpl, DOMFileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(MultipartFileImpl, FileImpl)
 
 nsresult
-DOMMultipartFileImpl::GetSize(uint64_t* aLength)
-{
-  *aLength = mLength;
-  return NS_OK;
-}
-
-nsresult
-DOMMultipartFileImpl::GetInternalStream(nsIInputStream** aStream)
+MultipartFileImpl::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;
-    DOMFileImpl* blobImpl = mBlobImpls.ElementAt(i).get();
+    FileImpl* 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);
   }
 
   return CallQueryInterface(stream, aStream);
 }
 
-already_AddRefed<DOMFileImpl>
-DOMMultipartFileImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
-                                  const nsAString& aContentType)
+already_AddRefed<FileImpl>
+MultipartFileImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
+                               const nsAString& aContentType,
+                               ErrorResult& aRv)
 {
   // If we clamped to nothing we create an empty blob
-  nsTArray<nsRefPtr<DOMFileImpl>> blobImpls;
+  nsTArray<nsRefPtr<FileImpl>> blobImpls;
 
   uint64_t length = aLength;
   uint64_t skipStart = aStart;
 
   // Prune the list of blobs if we can
   uint32_t i;
   for (i = 0; length && skipStart && i < mBlobImpls.Length(); i++) {
-    DOMFileImpl* blobImpl = mBlobImpls[i].get();
+    FileImpl* blobImpl = mBlobImpls[i].get();
 
-    uint64_t l;
-    nsresult rv = blobImpl->GetSize(&l);
-    NS_ENSURE_SUCCESS(rv, nullptr);
+    uint64_t l = blobImpl->GetSize(aRv);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
+    }
 
     if (skipStart < l) {
       uint64_t upperBound = std::min<uint64_t>(l - skipStart, length);
 
-      nsRefPtr<DOMFileImpl> firstImpl;
-      rv = blobImpl->Slice(skipStart, skipStart + upperBound, aContentType, 3,
-                           getter_AddRefs(firstImpl));
-      NS_ENSURE_SUCCESS(rv, nullptr);
-
-      // Avoid wrapping a single blob inside an DOMMultipartFileImpl
-      if (length == upperBound) {
-        return firstImpl.forget();
+      nsRefPtr<FileImpl> firstBlobImpl =
+        blobImpl->CreateSlice(skipStart, upperBound,
+                              aContentType, aRv);
+      if (NS_WARN_IF(aRv.Failed())) {
+        return nullptr;
       }
 
-      blobImpls.AppendElement(firstImpl);
+      // Avoid wrapping a single blob inside an MultipartFileImpl
+      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++) {
-    DOMFileImpl* blobImpl = mBlobImpls[i].get();
+    FileImpl* blobImpl = mBlobImpls[i].get();
 
-    uint64_t l;
-    nsresult rv = blobImpl->GetSize(&l);
-    NS_ENSURE_SUCCESS(rv, nullptr);
+    uint64_t l = blobImpl->GetSize(aRv);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
+    }
 
     if (length < l) {
-      nsRefPtr<DOMFileImpl> lastBlob;
-      rv = blobImpl->Slice(0, length, aContentType, 3,
-                           getter_AddRefs(lastBlob));
-      NS_ENSURE_SUCCESS(rv, nullptr);
+      nsRefPtr<FileImpl> lastBlobImpl =
+        blobImpl->CreateSlice(0, length, aContentType, aRv);
+      if (NS_WARN_IF(aRv.Failed())) {
+        return nullptr;
+      }
 
-      blobImpls.AppendElement(lastBlob);
+      blobImpls.AppendElement(lastBlobImpl);
     } else {
       blobImpls.AppendElement(blobImpl);
     }
     length -= std::min<uint64_t>(l, length);
   }
 
   // we can create our blob now
-  nsRefPtr<DOMFileImpl> impl =
-    new DOMMultipartFileImpl(blobImpls, aContentType);
+  nsRefPtr<FileImpl> impl =
+    new MultipartFileImpl(blobImpls, aContentType);
   return impl.forget();
 }
 
-/* static */ nsresult
-DOMMultipartFileImpl::NewFile(const nsAString& aName, nsISupports** aNewObject)
+void
+MultipartFileImpl::InitializeBlob()
 {
-  nsCOMPtr<nsISupports> file =
-    do_QueryObject(new DOMFile(new DOMMultipartFileImpl(aName)));
-  file.forget(aNewObject);
-  return NS_OK;
-}
-
-/* static */ nsresult
-DOMMultipartFileImpl::NewBlob(nsISupports** aNewObject)
-{
-  nsCOMPtr<nsISupports> file =
-    do_QueryObject(new DOMFile(new DOMMultipartFileImpl()));
-  file.forget(aNewObject);
-  return NS_OK;
+  SetLengthAndModifiedDate();
 }
 
-static nsIDOMBlob*
-GetXPConnectNative(JSContext* aCx, JSObject* aObj) {
-  nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(
-    nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, aObj));
-  return blob;
-}
-
-nsresult
-DOMMultipartFileImpl::Initialize(nsISupports* aOwner,
-                                 JSContext* aCx,
-                                 JSObject* aObj,
-                                 const JS::CallArgs& aArgs)
+void
+MultipartFileImpl::InitializeBlob(
+       JSContext* aCx,
+       const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+       const nsAString& aContentType,
+       bool aNativeEOL,
+       ErrorResult& aRv)
 {
-  if (!mIsFile) {
-    return InitBlob(aCx, aArgs.length(), aArgs.array(), GetXPConnectNative);
-  }
+  mContentType = aContentType;
+  BlobSet blobSet;
+
+  for (uint32_t i = 0, len = aData.Length(); i < len; ++i) {
+    const OwningArrayBufferOrArrayBufferViewOrBlobOrString& data = aData[i];
 
-  if (!nsContentUtils::IsCallerChrome()) {
-    return InitFile(aCx, aArgs.length(), aArgs.array());
-  }
+    if (data.IsBlob()) {
+      nsRefPtr<File> file = data.GetAsBlob().get();
+      blobSet.AppendBlobImpl(file->Impl());
+    }
+
+    else if (data.IsString()) {
+      aRv = blobSet.AppendString(data.GetAsString(), aNativeEOL, aCx);
+      if (aRv.Failed()) {
+        return;
+      }
+    }
 
-  if (aArgs.length() > 0) {
-    JS::Value* argv = aArgs.array();
-    if (argv[0].isObject()) {
-      JS::Rooted<JSObject*> obj(aCx, &argv[0].toObject());
-      if (JS_IsArrayObject(aCx, obj)) {
-        return InitFile(aCx, aArgs.length(), aArgs.array());
+    else if (data.IsArrayBuffer()) {
+      const ArrayBuffer& buffer = data.GetAsArrayBuffer();
+      buffer.ComputeLengthAndData();
+      aRv = blobSet.AppendVoidPtr(buffer.Data(), buffer.Length());
+      if (aRv.Failed()) {
+        return;
       }
     }
+
+    else if (data.IsArrayBufferView()) {
+      const ArrayBufferView& buffer = data.GetAsArrayBufferView();
+      buffer.ComputeLengthAndData();
+      aRv = blobSet.AppendVoidPtr(buffer.Data(), buffer.Length());
+      if (aRv.Failed()) {
+        return;
+      }
+    }
+
+    else {
+      MOZ_CRASH("Impossible blob data type.");
+    }
   }
 
-  return InitChromeFile(aCx, aArgs.length(), aArgs.array());
-}
-
-nsresult
-DOMMultipartFileImpl::InitBlob(JSContext* aCx,
-                               uint32_t aArgc,
-                               JS::Value* aArgv,
-                               UnwrapFuncPtr aUnwrapFunc)
-{
-  bool nativeEOL = false;
-  if (aArgc > 1) {
-    BlobPropertyBag d;
-    if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]))) {
-      return NS_ERROR_TYPE_ERR;
-    }
-    mContentType = d.mType;
-    nativeEOL = d.mEndings == EndingTypes::Native;
-  }
-
-  if (aArgc > 0) {
-    return ParseBlobArrayArgument(aCx, aArgv[0], nativeEOL, aUnwrapFunc);
-  }
-
-  SetLengthAndModifiedDate();
-
-  return NS_OK;
-}
-
-nsresult
-DOMMultipartFileImpl::ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
-                                             bool aNativeEOL,
-                                             UnwrapFuncPtr aUnwrapFunc)
-{
-  if (!aValue.isObject()) {
-    return NS_ERROR_TYPE_ERR; // We're not interested
-  }
-
-  JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
-  if (!JS_IsArrayObject(aCx, obj)) {
-    return NS_ERROR_TYPE_ERR; // We're not interested
-  }
-
-  BlobSet blobSet;
-
-  uint32_t length;
-  MOZ_ALWAYS_TRUE(JS_GetArrayLength(aCx, obj, &length));
-  for (uint32_t i = 0; i < length; ++i) {
-    JS::Rooted<JS::Value> element(aCx);
-    if (!JS_GetElement(aCx, obj, i, &element))
-      return NS_ERROR_TYPE_ERR;
-
-    if (element.isObject()) {
-      JS::Rooted<JSObject*> obj(aCx, &element.toObject());
-      nsCOMPtr<nsIDOMBlob> blob = aUnwrapFunc(aCx, obj);
-      if (blob) {
-        nsRefPtr<DOMFileImpl> blobImpl =
-          static_cast<DOMFile*>(blob.get())->Impl();
-
-        // Flatten so that multipart blobs will never nest
-        const nsTArray<nsRefPtr<DOMFileImpl>>* subBlobImpls =
-          blobImpl->GetSubBlobImpls();
-        if (subBlobImpls) {
-          blobSet.AppendBlobImpls(*subBlobImpls);
-        } else {
-          blobSet.AppendBlobImpl(blobImpl);
-        }
-        continue;
-      }
-      if (JS_IsArrayBufferViewObject(obj)) {
-        nsresult rv = blobSet.AppendVoidPtr(
-                                          JS_GetArrayBufferViewData(obj),
-                                          JS_GetArrayBufferViewByteLength(obj));
-        NS_ENSURE_SUCCESS(rv, rv);
-        continue;
-      }
-      if (JS_IsArrayBufferObject(obj)) {
-        nsresult rv = blobSet.AppendArrayBuffer(obj);
-        NS_ENSURE_SUCCESS(rv, rv);
-        continue;
-      }
-    }
-
-    // coerce it to a string
-    JSString* str = JS::ToString(aCx, element);
-    NS_ENSURE_TRUE(str, NS_ERROR_TYPE_ERR);
-
-    nsresult rv = blobSet.AppendString(str, aNativeEOL, aCx);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
 
   mBlobImpls = blobSet.GetBlobImpls();
-
   SetLengthAndModifiedDate();
-
-  return NS_OK;
 }
 
 void
-DOMMultipartFileImpl::SetLengthAndModifiedDate()
+MultipartFileImpl::SetLengthAndModifiedDate()
 {
   MOZ_ASSERT(mLength == UINT64_MAX);
   MOZ_ASSERT(mLastModificationDate == UINT64_MAX);
 
   uint64_t totalLength = 0;
 
   for (uint32_t index = 0, count = mBlobImpls.Length(); index < count; index++) {
-    nsRefPtr<DOMFileImpl>& blob = mBlobImpls[index];
+    nsRefPtr<FileImpl>& blob = mBlobImpls[index];
 
 #ifdef DEBUG
     MOZ_ASSERT(!blob->IsSizeUnknown());
     MOZ_ASSERT(!blob->IsDateUnknown());
 #endif
 
-    uint64_t subBlobLength;
-    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetSize(&subBlobLength)));
+    ErrorResult error;
+    uint64_t subBlobLength = blob->GetSize(error);
+    MOZ_ALWAYS_TRUE(!error.Failed());
 
     MOZ_ASSERT(UINT64_MAX - subBlobLength >= totalLength);
     totalLength += subBlobLength;
   }
 
   mLength = totalLength;
 
   if (mIsFile) {
-    mLastModificationDate = PR_Now();
+    // We cannot use PR_Now() because bug 493756 and, for this reason:
+    //   var x = new Date(); var f = new File(...);
+    //   x.getTime() < f.dateModified.getTime()
+    // could fail.
+    mLastModificationDate = JS_Now();
   }
 }
 
-nsresult
-DOMMultipartFileImpl::GetMozFullPathInternal(nsAString& aFilename)
+void
+MultipartFileImpl::GetMozFullPathInternal(nsAString& aFilename,
+                                          ErrorResult& aRv)
 {
-  if (!mIsFromNsiFile || mBlobImpls.Length() == 0) {
-    return DOMFileImplBase::GetMozFullPathInternal(aFilename);
+  if (!mIsFromNsIFile || mBlobImpls.Length() == 0) {
+    FileImplBase::GetMozFullPathInternal(aFilename, aRv);
+    return;
   }
 
-  DOMFileImpl* blobImpl = mBlobImpls.ElementAt(0).get();
+  FileImpl* blobImpl = mBlobImpls.ElementAt(0).get();
   if (!blobImpl) {
-    return DOMFileImplBase::GetMozFullPathInternal(aFilename);
+    FileImplBase::GetMozFullPathInternal(aFilename, aRv);
+    return;
   }
 
-  return blobImpl->GetMozFullPathInternal(aFilename);
+  blobImpl->GetMozFullPathInternal(aFilename, aRv);
 }
 
-nsresult
-DOMMultipartFileImpl::InitChromeFile(JSContext* aCx,
-                                     uint32_t aArgc,
-                                     JS::Value* aArgv)
+void
+MultipartFileImpl::InitializeChromeFile(File& aBlob,
+                                        const ChromeFilePropertyBag& aBag,
+                                        ErrorResult& aRv)
 {
-  nsresult rv;
+  NS_ASSERTION(!mImmutable, "Something went wrong ...");
 
-  NS_ASSERTION(!mImmutable, "Something went wrong ...");
-  NS_ENSURE_TRUE(!mImmutable, NS_ERROR_UNEXPECTED);
+  if (mImmutable) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+
   MOZ_ASSERT(nsContentUtils::IsCallerChrome());
-  NS_ENSURE_TRUE(aArgc > 0, NS_ERROR_UNEXPECTED);
 
-  if (aArgc > 1) {
-    FilePropertyBag d;
-    if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]))) {
-      return NS_ERROR_TYPE_ERR;
-    }
-    mName = d.mName;
-    mContentType = d.mType;
+  mName = aBag.mName;
+  mContentType = aBag.mType;
+  mIsFromNsIFile = true;
+
+  // XXXkhuey this is terrible
+  if (mContentType.IsEmpty()) {
+    aBlob.GetType(mContentType);
   }
 
 
-  // We expect to get a path to represent as a File object or
-  // Blob object, an nsIFile, or an nsIDOMFile.
-  nsCOMPtr<nsIFile> file;
-  nsCOMPtr<nsIDOMBlob> blob;
-  if (!aArgv[0].isString()) {
-    // Lets see if it's an nsIFile
-    if (!aArgv[0].isObject()) {
-      return NS_ERROR_UNEXPECTED; // We're not interested
-    }
+  BlobSet blobSet;
+  blobSet.AppendBlobImpl(aBlob.Impl());
+  mBlobImpls = blobSet.GetBlobImpls();
 
-    JSObject* obj = &aArgv[0].toObject();
-
-    nsISupports* supports =
-      nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, obj);
-    if (!supports) {
-      return NS_ERROR_UNEXPECTED;
-    }
+  SetLengthAndModifiedDate();
+}
 
-    blob = do_QueryInterface(supports);
-    file = do_QueryInterface(supports);
-    if (!blob && !file) {
-      return NS_ERROR_UNEXPECTED;
-    }
+void
+MultipartFileImpl::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);
+    return;
+  }
 
-    mIsFromNsiFile = true;
-  } else {
-    // It's a string
-    JSString* str = JS::ToString(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[0]));
-    NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS);
+  MOZ_ASSERT(nsContentUtils::IsCallerChrome());
 
-    nsAutoJSString xpcomStr;
-    if (!xpcomStr.init(aCx, str)) {
-      return NS_ERROR_XPC_BAD_CONVERT_JS;
-    }
+  mName = aBag.mName;
+  mContentType = aBag.mType;
+  mIsFromNsIFile = aIsFromNsIFile;
 
-    rv = NS_NewLocalFile(xpcomStr, false, getter_AddRefs(file));
-    NS_ENSURE_SUCCESS(rv, rv);
+  bool exists;
+  aRv = aFile->Exists(&exists);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
   }
 
-  if (file) {
-    bool exists;
-    rv = file->Exists(&exists);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(exists, NS_ERROR_FILE_NOT_FOUND);
+  if (!exists) {
+    aRv.Throw(NS_ERROR_FILE_NOT_FOUND);
+    return;
+  }
 
-    bool isDir;
-    rv = file->IsDirectory(&isDir);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_FALSE(isDir, NS_ERROR_FILE_IS_DIRECTORY);
+  bool isDir;
+  aRv = aFile->IsDirectory(&isDir);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  if (isDir) {
+    aRv.Throw(NS_ERROR_FILE_IS_DIRECTORY);
+    return;
+  }
 
-    if (mName.IsEmpty()) {
-      file->GetLeafName(mName);
-    }
+  if (mName.IsEmpty()) {
+    aFile->GetLeafName(mName);
+  }
 
-    nsRefPtr<DOMFile> domFile = DOMFile::CreateFromFile(file);
+  nsRefPtr<File> blob = File::CreateFromFile(aWindow, aFile);
 
-    // Pre-cache size.
-    uint64_t unused;
-    rv = domFile->GetSize(&unused);
-    NS_ENSURE_SUCCESS(rv, rv);
+  // Pre-cache size.
+  uint64_t unused;
+  aRv = blob->GetSize(&unused);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
 
-    // Pre-cache modified date.
-    rv = domFile->GetMozLastModifiedDate(&unused);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    blob = domFile.forget();
+  // Pre-cache modified date.
+  aRv = blob->GetMozLastModifiedDate(&unused);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
   }
 
   // XXXkhuey this is terrible
   if (mContentType.IsEmpty()) {
     blob->GetType(mContentType);
   }
 
   BlobSet blobSet;
-  blobSet.AppendBlobImpl(static_cast<DOMFile*>(blob.get())->Impl());
+  blobSet.AppendBlobImpl(static_cast<File*>(blob.get())->Impl());
   mBlobImpls = blobSet.GetBlobImpls();
 
   SetLengthAndModifiedDate();
-
-  return NS_OK;
-}
-
-nsresult
-DOMMultipartFileImpl::InitFile(JSContext* aCx,
-                               uint32_t aArgc,
-                               JS::Value* aArgv)
-{
-  NS_ASSERTION(!mImmutable, "Something went wrong ...");
-  NS_ENSURE_TRUE(!mImmutable, NS_ERROR_UNEXPECTED);
-
-  if (aArgc < 2) {
-    return NS_ERROR_TYPE_ERR;
-  }
-
-  // File name
-  JSString* str = JS::ToString(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]));
-  NS_ENSURE_TRUE(str, NS_ERROR_XPC_BAD_CONVERT_JS);
-
-  nsAutoJSString xpcomStr;
-  if (!xpcomStr.init(aCx, str)) {
-    return NS_ERROR_XPC_BAD_CONVERT_JS;
-  }
-
-  mName = xpcomStr;
-
-  // Optional params
-  bool nativeEOL = false;
-  if (aArgc > 2) {
-    BlobPropertyBag d;
-    if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[2]))) {
-      return NS_ERROR_TYPE_ERR;
-    }
-    mContentType = d.mType;
-    nativeEOL = d.mEndings == EndingTypes::Native;
-  }
-
-  return ParseBlobArrayArgument(aCx, aArgv[0], nativeEOL, GetXPConnectNative);
 }
 
-nsresult
-BlobSet::AppendVoidPtr(const void* aData, uint32_t aLength)
+void
+MultipartFileImpl::InitializeChromeFile(nsPIDOMWindow* aWindow,
+                                        const nsAString& aData,
+                                        const ChromeFilePropertyBag& aBag,
+                                        ErrorResult& aRv)
 {
-  NS_ENSURE_ARG_POINTER(aData);
-
-  uint64_t offset = mDataLen;
-
-  if (!ExpandBufferSize(aLength))
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  memcpy((char*)mData + offset, aData, aLength);
-  return NS_OK;
-}
-
-nsresult
-BlobSet::AppendString(JSString* aString, bool nativeEOL, JSContext* aCx)
-{
-  nsAutoJSString xpcomStr;
-  if (!xpcomStr.init(aCx, aString)) {
-    return NS_ERROR_XPC_BAD_CONVERT_JS;
+  nsCOMPtr<nsIFile> file;
+  aRv = NS_NewLocalFile(aData, false, getter_AddRefs(file));
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
   }
 
-  nsCString utf8Str = NS_ConvertUTF16toUTF8(xpcomStr);
-
-  if (nativeEOL) {
-    if (utf8Str.FindChar('\r') != kNotFound) {
-      utf8Str.ReplaceSubstring("\r\n", "\n");
-      utf8Str.ReplaceSubstring("\r", "\n");
-    }
-#ifdef XP_WIN
-    utf8Str.ReplaceSubstring("\n", "\r\n");
-#endif
-  }
-
-  return AppendVoidPtr((void*)utf8Str.Data(),
-                       utf8Str.Length());
+  InitializeChromeFile(aWindow, file, aBag, false, aRv);
 }
-
-nsresult
-BlobSet::AppendBlobImpl(DOMFileImpl* aBlobImpl)
-{
-  NS_ENSURE_ARG_POINTER(aBlobImpl);
-
-  Flush();
-  mBlobImpls.AppendElement(aBlobImpl);
-
-  return NS_OK;
-}
-
-nsresult
-BlobSet::AppendBlobImpls(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls)
-{
-  Flush();
-  mBlobImpls.AppendElements(aBlobImpls);
-
-  return NS_OK;
-}
-
-nsresult
-BlobSet::AppendArrayBuffer(JSObject* aBuffer)
-{
-  return AppendVoidPtr(JS_GetArrayBufferData(aBuffer),
-                       JS_GetArrayBufferByteLength(aBuffer));
-}
rename from content/base/src/nsDOMBlobBuilder.h
rename to content/base/src/MultipartFileImpl.h
--- a/content/base/src/nsDOMBlobBuilder.h
+++ b/content/base/src/MultipartFileImpl.h
@@ -1,198 +1,123 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsDOMBlobBuilder_h
-#define nsDOMBlobBuilder_h
+#ifndef mozilla_dom_MultipartFileImpl_h
+#define mozilla_dom_MultipartFileImpl_h
 
-#include "nsDOMFile.h"
-
+#include "mozilla/Attributes.h"
 #include "mozilla/CheckedInt.h"
-#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/File.h"
+#include "mozilla/dom/BlobBinding.h"
+#include "mozilla/dom/FileBinding.h"
 #include <algorithm>
 
-#define NS_DOMMULTIPARTBLOB_CID { 0x47bf0b43, 0xf37e, 0x49ef, \
-  { 0x81, 0xa0, 0x18, 0xba, 0xc0, 0x57, 0xb5, 0xcc } }
-#define NS_DOMMULTIPARTBLOB_CONTRACTID "@mozilla.org/dom/multipart-blob;1"
-
-#define NS_DOMMULTIPARTFILE_CID { 0xc3361f77, 0x60d1, 0x4ea9, \
-  { 0x94, 0x96, 0xdf, 0x5d, 0x6f, 0xcd, 0xd7, 0x8f } }
-#define NS_DOMMULTIPARTFILE_CONTRACTID "@mozilla.org/dom/multipart-file;1"
-
+using namespace mozilla;
 using namespace mozilla::dom;
 
-class DOMMultipartFileImpl MOZ_FINAL : public DOMFileImplBase
+class MultipartFileImpl MOZ_FINAL : public FileImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // Create as a file
-  DOMMultipartFileImpl(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls,
-                       const nsAString& aName,
-                       const nsAString& aContentType)
-    : DOMFileImplBase(aName, aContentType, UINT64_MAX),
+  MultipartFileImpl(const nsTArray<nsRefPtr<FileImpl>>& aBlobImpls,
+                    const nsAString& aName,
+                    const nsAString& aContentType)
+    : FileImplBase(aName, aContentType, UINT64_MAX),
       mBlobImpls(aBlobImpls),
-      mIsFromNsiFile(false)
+      mIsFromNsIFile(false)
   {
     SetLengthAndModifiedDate();
   }
 
   // Create as a blob
-  DOMMultipartFileImpl(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls,
-                       const nsAString& aContentType)
-    : DOMFileImplBase(aContentType, UINT64_MAX),
+  MultipartFileImpl(const nsTArray<nsRefPtr<FileImpl>>& aBlobImpls,
+                    const nsAString& aContentType)
+    : FileImplBase(aContentType, UINT64_MAX),
       mBlobImpls(aBlobImpls),
-      mIsFromNsiFile(false)
+      mIsFromNsIFile(false)
   {
     SetLengthAndModifiedDate();
   }
 
   // Create as a file to be later initialized
-  explicit DOMMultipartFileImpl(const nsAString& aName)
-    : DOMFileImplBase(aName, EmptyString(), UINT64_MAX),
-      mIsFromNsiFile(false)
+  explicit MultipartFileImpl(const nsAString& aName)
+    : FileImplBase(aName, EmptyString(), UINT64_MAX),
+      mIsFromNsIFile(false)
   {
   }
 
   // Create as a blob to be later initialized
-  DOMMultipartFileImpl()
-    : DOMFileImplBase(EmptyString(), UINT64_MAX),
-      mIsFromNsiFile(false)
+  MultipartFileImpl()
+    : FileImplBase(EmptyString(), UINT64_MAX),
+      mIsFromNsIFile(false)
   {
   }
 
-  virtual nsresult
-  Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
-             const JS::CallArgs& aArgs) MOZ_OVERRIDE;
+  void InitializeBlob();
+
+  void InitializeBlob(
+       JSContext* aCx,
+       const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData,
+       const nsAString& aContentType,
+       bool aNativeEOL,
+       ErrorResult& aRv);
+
+  void InitializeChromeFile(File& aData,
+                            const ChromeFilePropertyBag& aBag,
+                            ErrorResult& aRv);
 
-  typedef nsIDOMBlob* (*UnwrapFuncPtr)(JSContext*, JSObject*);
-  nsresult InitBlob(JSContext* aCx,
-                    uint32_t aArgc,
-                    JS::Value* aArgv,
-                    UnwrapFuncPtr aUnwrapFunc);
-  nsresult InitFile(JSContext* aCx,
-                    uint32_t aArgc,
-                    JS::Value* aArgv);
-  nsresult InitChromeFile(JSContext* aCx,
-                          uint32_t aArgc,
-                          JS::Value* aArgv);
+  void InitializeChromeFile(nsPIDOMWindow* aWindow,
+                            const nsAString& aData,
+                            const ChromeFilePropertyBag& aBag,
+                            ErrorResult& aRv);
 
-  virtual already_AddRefed<DOMFileImpl>
+  void InitializeChromeFile(nsPIDOMWindow* aWindow,
+                            nsIFile* aData,
+                            const ChromeFilePropertyBag& aBag,
+                            bool aIsFromNsIFile,
+                            ErrorResult& aRv);
+
+  virtual already_AddRefed<FileImpl>
   CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType,
+              ErrorResult& aRv) MOZ_OVERRIDE;
 
-  virtual nsresult GetSize(uint64_t* aSize) MOZ_OVERRIDE;
+  virtual uint64_t GetSize(ErrorResult& aRv) MOZ_OVERRIDE
+  {
+    return mLength;
+  }
 
   virtual nsresult GetInternalStream(nsIInputStream** aInputStream) MOZ_OVERRIDE;
 
-  static nsresult NewFile(const nsAString& aName, nsISupports** aNewObject);
-
-  // DOMClassInfo constructor (for Blob([b1, "foo"], { type: "image/png" }))
-  static nsresult NewBlob(nsISupports* *aNewObject);
-
-  // DOMClassInfo constructor (for File([b1, "foo"], { type: "image/png",
-  //                                                   name: "foo.png" }))
-  inline static nsresult NewFile(nsISupports** aNewObject)
-  {
-    // Initialization will set the filename, so we can pass in an empty string
-    // for now.
-    return NewFile(EmptyString(), aNewObject);
-  }
-
-  virtual const nsTArray<nsRefPtr<DOMFileImpl>>* GetSubBlobImpls() const MOZ_OVERRIDE
+  virtual const nsTArray<nsRefPtr<FileImpl>>* GetSubBlobImpls() const MOZ_OVERRIDE
   {
     return &mBlobImpls;
   }
 
-  virtual nsresult GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
-
-protected:
-  virtual ~DOMMultipartFileImpl() {}
-
-  nsresult ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
-                                  bool aNativeEOL, UnwrapFuncPtr aUnwrapFunc);
-
-  void SetLengthAndModifiedDate();
+  virtual void GetMozFullPathInternal(nsAString& aFullPath,
+                                      ErrorResult& aRv) MOZ_OVERRIDE;
 
-  nsTArray<nsRefPtr<DOMFileImpl>> mBlobImpls;
-  bool mIsFromNsiFile;
-};
-
-class BlobSet {
-public:
-  BlobSet()
-    : mData(nullptr), mDataLen(0), mDataBufferLen(0)
-  {}
-
-  ~BlobSet()
+  void SetName(const nsAString& aName)
   {
-    moz_free(mData);
+    mName = aName;
   }
 
-  nsresult AppendVoidPtr(const void* aData, uint32_t aLength);
-  nsresult AppendString(JSString* aString, bool nativeEOL, JSContext* aCx);
-  nsresult AppendBlobImpl(DOMFileImpl* aBlobImpl);
-  nsresult AppendArrayBuffer(JSObject* aBuffer);
-  nsresult AppendBlobImpls(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls);
-
-  nsTArray<nsRefPtr<DOMFileImpl>>& GetBlobImpls() { Flush(); return mBlobImpls; }
-
-  already_AddRefed<nsIDOMBlob>
-  GetBlobInternal(const nsACString& aContentType)
+  void SetFromNsIFile(bool aValue)
   {
-    nsCOMPtr<nsIDOMBlob> blob = new DOMFile(
-      new DOMMultipartFileImpl(GetBlobImpls(), NS_ConvertASCIItoUTF16(aContentType)));
-    return blob.forget();
+    mIsFromNsIFile = aValue;
   }
 
 protected:
-  bool ExpandBufferSize(uint64_t aSize)
-  {
-    using mozilla::CheckedUint32;
-
-    if (mDataBufferLen >= mDataLen + aSize) {
-      mDataLen += aSize;
-      return true;
-    }
-
-    // Start at 1 or we'll loop forever.
-    CheckedUint32 bufferLen =
-      std::max<uint32_t>(static_cast<uint32_t>(mDataBufferLen), 1);
-    while (bufferLen.isValid() && bufferLen.value() < mDataLen + aSize)
-      bufferLen *= 2;
-
-    if (!bufferLen.isValid())
-      return false;
-
-    void* data = moz_realloc(mData, bufferLen.value());
-    if (!data)
-      return false;
+  virtual ~MultipartFileImpl() {}
 
-    mData = data;
-    mDataBufferLen = bufferLen.value();
-    mDataLen += aSize;
-    return true;
-  }
-
-  void Flush() {
-    if (mData) {
-      // If we have some data, create a blob for it
-      // and put it on the stack
+  void SetLengthAndModifiedDate();
 
-      nsRefPtr<DOMFileImpl> blobImpl =
-        new DOMFileImplMemory(mData, mDataLen, EmptyString());
-      mBlobImpls.AppendElement(blobImpl);
-      mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer
-      mDataLen = 0;
-      mDataBufferLen = 0;
-    }
-  }
-
-  nsTArray<nsRefPtr<DOMFileImpl>> mBlobImpls;
-  void* mData;
-  uint64_t mDataLen;
-  uint64_t mDataBufferLen;
+  nsTArray<nsRefPtr<FileImpl>> mBlobImpls;
+  bool mIsFromNsIFile;
 };
 
-#endif
+#endif // mozilla_dom_MultipartFileImpl_h
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -6,16 +6,17 @@
 
 #include "WebSocket.h"
 #include "mozilla/dom/WebSocketBinding.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/OldDebugAPI.h"
 #include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMWindow.h"
 #include "nsIDocument.h"
 #include "nsXPCOM.h"
 #include "nsIXPConnect.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
@@ -33,17 +34,16 @@
 #include "nsICryptoHash.h"
 #include "nsJSUtils.h"
 #include "nsIScriptError.h"
 #include "nsNetUtil.h"
 #include "nsILoadGroup.h"
 #include "mozilla/Preferences.h"
 #include "xpcpublic.h"
 #include "nsContentPolicyUtils.h"
-#include "nsDOMFile.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsIObserverService.h"
 #include "nsIWebSocketChannel.h"
 
 namespace mozilla {
 namespace dom {
 
 #define UTF_8_REPLACEMENT_CHAR    static_cast<char16_t>(0xFFFD)
@@ -893,17 +893,17 @@ WebSocket::CreateAndDispatchMessageEvent
     return NS_ERROR_FAILURE;
   }
   JSContext* cx = jsapi.cx();
 
   // Create appropriate JS object for message
   JS::Rooted<JS::Value> jsData(cx);
   if (isBinary) {
     if (mBinaryType == dom::BinaryType::Blob) {
-      rv = nsContentUtils::CreateBlobBuffer(cx, aData, &jsData);
+      rv = nsContentUtils::CreateBlobBuffer(cx, GetOwner(), aData, &jsData);
       NS_ENSURE_SUCCESS(rv, rv);
     } else if (mBinaryType == dom::BinaryType::Arraybuffer) {
       JS::Rooted<JSObject*> arrayBuf(cx);
       rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
       NS_ENSURE_SUCCESS(rv, rv);
       jsData = OBJECT_TO_JSVAL(arrayBuf);
     } else {
       NS_RUNTIMEABORT("Unknown binary type!");
@@ -1189,30 +1189,29 @@ WebSocket::Send(const nsAString& aData,
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   NS_ConvertUTF16toUTF8 msgString(aData);
   Send(nullptr, msgString, msgString.Length(), false, aRv);
 }
 
 void
-WebSocket::Send(nsIDOMBlob* aData,
-                ErrorResult& aRv)
+WebSocket::Send(File& aData, ErrorResult& aRv)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   nsCOMPtr<nsIInputStream> msgStream;
-  nsresult rv = aData->GetInternalStream(getter_AddRefs(msgStream));
+  nsresult rv = aData.GetInternalStream(getter_AddRefs(msgStream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   uint64_t msgLength;
-  rv = aData->GetSize(&msgLength);
+  rv = aData.GetSize(&msgLength);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   if (msgLength > UINT32_MAX) {
     aRv.Throw(NS_ERROR_FILE_TOO_BIG);
     return;
--- a/content/base/src/WebSocket.h
+++ b/content/base/src/WebSocket.h
@@ -27,16 +27,18 @@
 #include "nsWrapperCache.h"
 
 #define DEFAULT_WS_SCHEME_PORT  80
 #define DEFAULT_WSS_SCHEME_PORT 443
 
 namespace mozilla {
 namespace dom {
 
+class File;
+
 class WebSocket MOZ_FINAL : public DOMEventTargetHelper,
                             public nsIInterfaceRequestor,
                             public nsIWebSocketListener,
                             public nsIObserver,
                             public nsSupportsWeakReference,
                             public nsIRequest
 {
 friend class CallDispatchConnectionCloseEvents;
@@ -126,17 +128,17 @@ public: // WebIDL interface:
 
   // webIDL: attribute DOMString binaryType;
   dom::BinaryType BinaryType() const { return mBinaryType; }
   void SetBinaryType(dom::BinaryType aData) { mBinaryType = aData; }
 
   // webIDL: void send(DOMString|Blob|ArrayBufferView data);
   void Send(const nsAString& aData,
             ErrorResult& aRv);
-  void Send(nsIDOMBlob* aData,
+  void Send(File& aData,
             ErrorResult& aRv);
   void Send(const ArrayBuffer& aData,
             ErrorResult& aRv);
   void Send(const ArrayBufferView& aData,
             ErrorResult& aRv);
 
 private: // constructor && distructor
   explicit WebSocket(nsPIDOMWindow* aOwnerWindow);
--- a/content/base/src/moz.build
+++ b/content/base/src/moz.build
@@ -37,17 +37,17 @@ EXPORTS += [
     'nsTraversal.h',
 ]
 
 if CONFIG['MOZ_WEBRTC']:
     EXPORTS += [
         'nsDOMDataChannel.h',
         'nsDOMDataChannelDeclarations.h',
     ]
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'nsDOMDataChannel.cpp',
     ]
     LOCAL_INCLUDES += [
         '/netwerk/sctp/datachannel',
     ]
 
 # Are we targeting x86-32 or x86-64?  If so, we want to include SSE2 code for
 # nsTextFragment.cpp
@@ -94,20 +94,22 @@ UNIFIED_SOURCES += [
     'DOMMatrix.cpp',
     'DOMParser.cpp',
     'DOMPoint.cpp',
     'DOMQuad.cpp',
     'DOMRect.cpp',
     'DOMStringList.cpp',
     'Element.cpp',
     'EventSource.cpp',
+    'File.cpp',
     'FileIOObject.cpp',
     'FragmentOrElement.cpp',
     'ImportManager.cpp',
     'Link.cpp',
+    'MultipartFileImpl.cpp',
     'NodeIterator.cpp',
     'nsAtomListUtils.cpp',
     'nsAttrAndChildArray.cpp',
     'nsAttrValue.cpp',
     'nsAttrValueOrString.cpp',
     'nsCCUncollectableMarker.cpp',
     'nsChannelPolicy.cpp',
     'nsContentAreaDragDrop.cpp',
@@ -117,21 +119,20 @@ UNIFIED_SOURCES += [
     'nsContentSink.cpp',
     'nsCopySupport.cpp',
     'nsCrossSiteListenerProxy.cpp',
     'nsCSPContext.cpp',
     'nsCSPParser.cpp',
     'nsCSPService.cpp',
     'nsCSPUtils.cpp',
     'nsDataDocumentContentPolicy.cpp',
+    'nsDocument.cpp',
     'nsDocumentEncoder.cpp',
     'nsDOMAttributeMap.cpp',
-    'nsDOMBlobBuilder.cpp',
     'nsDOMCaretPosition.cpp',
-    'nsDOMFile.cpp',
     'nsDOMFileReader.cpp',
     'nsDOMMutationObserver.cpp',
     'nsDOMSerializer.cpp',
     'nsDOMSettableTokenList.cpp',
     'nsDOMTokenList.cpp',
     'nsElementFrameLoaderOwner.cpp',
     'nsFormData.cpp',
     'nsFrameLoader.cpp',
@@ -145,16 +146,17 @@ UNIFIED_SOURCES += [
     'nsINode.cpp',
     'nsInProcessTabChildGlobal.cpp',
     'nsLineBreaker.cpp',
     'nsMappedAttributeElement.cpp',
     'nsMappedAttributes.cpp',
     'nsMixedContentBlocker.cpp',
     'nsNameSpaceManager.cpp',
     'nsNoDataProtocolContentPolicy.cpp',
+    'nsNodeInfoManager.cpp',
     'nsNodeUtils.cpp',
     'nsPlainTextSerializer.cpp',
     'nsPropertyTable.cpp',
     'nsRange.cpp',
     'nsReferencedElement.cpp',
     'nsScriptElement.cpp',
     'nsScriptLoader.cpp',
     'nsStubDocumentObserver.cpp',
@@ -179,22 +181,16 @@ UNIFIED_SOURCES += [
     'TreeWalker.cpp',
     'WebSocket.cpp',
 ]
 
 SOURCES += [
     'nsImageLoadingContent.cpp',
 ]
 
-# These files cannot be built in unified mode because they use FORCE_PR_LOG
-SOURCES += [
-    'nsDocument.cpp',
-    'nsNodeInfoManager.cpp',
-]
-
 # These files cannot be built in unified mode because of OS X headers.
 SOURCES += [
     'nsContentUtils.cpp',
     'nsObjectLoadingContent.cpp',
 ]
 
 EXTRA_COMPONENTS += [
     'contentAreaDropListener.js',
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -85,16 +85,17 @@
 #include "nsGkAtoms.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsHtml5Module.h"
 #include "nsHtml5StringParser.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsICategoryManager.h"
 #include "nsIChannelEventSink.h"
 #include "nsIChannelPolicy.h"
+#include "nsICharsetDetectionObserver.h"
 #include "nsIChromeRegistry.h"
 #include "nsIConsoleService.h"
 #include "nsIContent.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIContentSink.h"
 #include "nsIContentViewer.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
@@ -5987,30 +5988,36 @@ nsContentUtils::CreateArrayBuffer(JSCont
 
   return NS_OK;
 }
 
 // Initial implementation: only stores to RAM, not file
 // TODO: bug 704447: large file support
 nsresult
 nsContentUtils::CreateBlobBuffer(JSContext* aCx,
+                                 nsISupports* aParent,
                                  const nsACString& aData,
                                  JS::MutableHandle<JS::Value> aBlob)
 {
   uint32_t blobLen = aData.Length();
   void* blobData = moz_malloc(blobLen);
-  nsCOMPtr<nsIDOMBlob> blob;
+  nsRefPtr<File> blob;
   if (blobData) {
     memcpy(blobData, aData.BeginReading(), blobLen);
-    blob = mozilla::dom::DOMFile::CreateMemoryFile(blobData, blobLen,
-                                                   EmptyString());
+    blob = mozilla::dom::File::CreateMemoryFile(aParent, blobData, blobLen,
+                                                EmptyString());
   } else {
     return NS_ERROR_OUT_OF_MEMORY;
   }
-  return nsContentUtils::WrapNative(aCx, blob, aBlob);
+
+  if (!WrapNewBindingObject(aCx, blob, aBlob)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
 }
 
 void
 nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr)
 {
   // In common cases where we don't have nulls in the
   // string we can simple simply bypass the checking code.
   int32_t firstNullPos = aInStr.FindChar('\0');
--- a/content/base/src/nsDOMDataChannel.cpp
+++ b/content/base/src/nsDOMDataChannel.cpp
@@ -1,45 +1,40 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et tw=80 : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsDOMDataChannel.h"
 
-#ifdef MOZ_LOGGING
-#define FORCE_PR_LOG
-#endif
-
 #include "base/basictypes.h"
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetDataChannelLog();
 #endif
 #undef LOG
 #define LOG(args) PR_LOG(GetDataChannelLog(), PR_LOG_DEBUG, args)
 
 
 #include "nsDOMDataChannelDeclarations.h"
 #include "nsDOMDataChannel.h"
-#include "nsIDOMFile.h"
 #include "nsIDOMDataChannel.h"
 #include "nsIDOMMessageEvent.h"
 #include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 #include "nsError.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsNetUtil.h"
-#include "nsDOMFile.h"
 
 #include "DataChannel.h"
 
 // Since we've moved the windows.h include down here, we have to explicitly
 // undef GetBinaryType, otherwise we'll get really odd conflicts
 #ifdef GetBinaryType
 #undef GetBinaryType
 #endif
@@ -267,29 +262,29 @@ nsDOMDataChannel::Close()
 void
 nsDOMDataChannel::Send(const nsAString& aData, ErrorResult& aRv)
 {
   NS_ConvertUTF16toUTF8 msgString(aData);
   Send(nullptr, msgString, msgString.Length(), false, aRv);
 }
 
 void
-nsDOMDataChannel::Send(nsIDOMBlob* aData, ErrorResult& aRv)
+nsDOMDataChannel::Send(File& aData, ErrorResult& aRv)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   nsCOMPtr<nsIInputStream> msgStream;
-  nsresult rv = aData->GetInternalStream(getter_AddRefs(msgStream));
+  nsresult rv = aData.GetInternalStream(getter_AddRefs(msgStream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   uint64_t msgLength;
-  rv = aData->GetSize(&msgLength);
+  rv = aData.GetSize(&msgLength);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   if (msgLength > UINT32_MAX) {
     aRv.Throw(NS_ERROR_FILE_TOO_BIG);
     return;
@@ -388,17 +383,17 @@ nsDOMDataChannel::DoOnMessageAvailable(c
     return NS_ERROR_FAILURE;
   }
   JSContext* cx = jsapi.cx();
 
   JS::Rooted<JS::Value> jsData(cx);
 
   if (aBinary) {
     if (mBinaryType == DC_BINARY_TYPE_BLOB) {
-      rv = nsContentUtils::CreateBlobBuffer(cx, aData, &jsData);
+      rv = nsContentUtils::CreateBlobBuffer(cx, GetOwner(), aData, &jsData);
       NS_ENSURE_SUCCESS(rv, rv);
     } else if (mBinaryType == DC_BINARY_TYPE_ARRAYBUFFER) {
       JS::Rooted<JSObject*> arrayBuf(cx);
       rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
       NS_ENSURE_SUCCESS(rv, rv);
       jsData = OBJECT_TO_JSVAL(arrayBuf);
     } else {
       NS_RUNTIMEABORT("Unknown binary type!");
--- a/content/base/src/nsDOMDataChannel.h
+++ b/content/base/src/nsDOMDataChannel.h
@@ -12,16 +12,20 @@
 #include "mozilla/dom/DataChannelBinding.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/net/DataChannelListener.h"
 #include "nsIDOMDataChannel.h"
 #include "nsIInputStream.h"
 
 
 namespace mozilla {
+namespace dom {
+class File;
+}
+
 class DataChannel;
 };
 
 class nsDOMDataChannel : public mozilla::DOMEventTargetHelper,
                          public nsIDOMDataChannel,
                          public mozilla::DataChannelListener
 {
 public:
@@ -61,17 +65,17 @@ public:
       static_cast<int>(mBinaryType));
   }
   void SetBinaryType(mozilla::dom::RTCDataChannelType aType)
   {
     mBinaryType = static_cast<DataChannelBinaryType>(
       static_cast<int>(aType));
   }
   void Send(const nsAString& aData, mozilla::ErrorResult& aRv);
-  void Send(nsIDOMBlob* aData, mozilla::ErrorResult& aRv);
+  void Send(mozilla::dom::File& aData, mozilla::ErrorResult& aRv);
   void Send(const mozilla::dom::ArrayBuffer& aData, mozilla::ErrorResult& aRv);
   void Send(const mozilla::dom::ArrayBufferView& aData,
             mozilla::ErrorResult& aRv);
 
   // Uses XPIDL GetProtocol.
   bool Ordered() const;
   uint16_t Id() const;
   uint16_t Stream() const; // deprecated
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -3,28 +3,28 @@
  * 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 "nsDOMFileReader.h"
 
 #include "nsContentCID.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
-#include "nsDOMFile.h"
 #include "nsError.h"
 #include "nsIFile.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 
 #include "nsXPCOM.h"
 #include "nsIDOMEventListener.h"
 #include "nsJSEnvironment.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Base64.h"
 #include "mozilla/dom/EncodingUtils.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/FileReaderBinding.h"
 #include "xpcpublic.h"
 #include "nsDOMJSUtils.h"
 
 #include "jsfriendapi.h"
 
 #include "nsITransport.h"
 #include "nsIStreamTransportService.h"
@@ -181,45 +181,49 @@ nsDOMFileReader::GetError(nsISupports** 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::ReadAsArrayBuffer(nsIDOMBlob* aFile, JSContext* aCx)
 {
   NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  ReadAsArrayBuffer(aCx, aFile, rv);
+  nsRefPtr<File> file = static_cast<File*>(aFile);
+  ReadAsArrayBuffer(aCx, *file, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::ReadAsBinaryString(nsIDOMBlob* aFile)
 {
   NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  ReadAsBinaryString(aFile, rv);
+  nsRefPtr<File> file = static_cast<File*>(aFile);
+  ReadAsBinaryString(*file, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::ReadAsText(nsIDOMBlob* aFile,
                             const nsAString &aCharset)
 {
   NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  ReadAsText(aFile, aCharset, rv);
+  nsRefPtr<File> file = static_cast<File*>(aFile);
+  ReadAsText(*file, aCharset, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::ReadAsDataURL(nsIDOMBlob* aFile)
 {
   NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   ErrorResult rv;
-  ReadAsDataURL(aFile, rv);
+  nsRefPtr<File> file = static_cast<File*>(aFile);
+  ReadAsDataURL(*file, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::Abort()
 {
   ErrorResult rv;
   FileIOObject::Abort(rv);
@@ -361,33 +365,31 @@ nsDOMFileReader::DoReadData(nsIAsyncInpu
   mDataLen += aCount;
   return NS_OK;
 }
 
 // Helper methods
 
 void
 nsDOMFileReader::ReadFileContent(JSContext* aCx,
-                                 nsIDOMBlob* aFile,
+                                 File& aFile,
                                  const nsAString &aCharset,
                                  eDataFormat aDataFormat,
                                  ErrorResult& aRv)
 {
-  MOZ_ASSERT(aFile);
-
   //Implicit abort to clear any other activity going on
   Abort();
   mError = nullptr;
   SetDOMStringToNull(mResult);
   mTransferred = 0;
   mTotal = 0;
   mReadyState = nsIDOMFileReader::EMPTY;
   FreeFileData();
 
-  mFile = aFile;
+  mFile = &aFile;
   mDataFormat = aDataFormat;
   CopyUTF16toUTF8(aCharset, mCharset);
 
   nsresult rv;
 
   nsCOMPtr<nsIStreamTransportService> sts =
     do_GetService(kStreamTransportServiceCID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/content/base/src/nsDOMFileReader.h
+++ b/content/base/src/nsDOMFileReader.h
@@ -14,30 +14,36 @@
 #include "nsIInterfaceRequestor.h"
 #include "nsJSUtils.h"
 #include "nsTArray.h"
 #include "nsIJSNativeInitializer.h"
 #include "prtime.h"
 #include "nsITimer.h"
 #include "nsIAsyncInputStream.h"
 
-#include "nsIDOMFile.h"
 #include "nsIDOMFileReader.h"
 #include "nsIDOMFileList.h"
 #include "nsCOMPtr.h"
 
 #include "FileIOObject.h"
 
+namespace mozilla {
+namespace dom {
+class File;
+}
+}
+
 class nsDOMFileReader : public mozilla::dom::FileIOObject,
                         public nsIDOMFileReader,
                         public nsIInterfaceRequestor,
                         public nsSupportsWeakReference
 {
   typedef mozilla::ErrorResult ErrorResult;
   typedef mozilla::dom::GlobalObject GlobalObject;
+  typedef mozilla::dom::File File;
 public:
   nsDOMFileReader();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMFILEREADER
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(mozilla::DOMEventTargetHelper)
@@ -57,31 +63,28 @@ public:
   {
     return GetOwner();
   }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   // WebIDL
   static already_AddRefed<nsDOMFileReader>
   Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
-  void ReadAsArrayBuffer(JSContext* aCx, nsIDOMBlob* aBlob, ErrorResult& aRv)
+  void ReadAsArrayBuffer(JSContext* aCx, File& aBlob, ErrorResult& aRv)
   {
-    MOZ_ASSERT(aBlob);
     ReadFileContent(aCx, aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
   }
 
-  void ReadAsText(nsIDOMBlob* aBlob, const nsAString& aLabel, ErrorResult& aRv)
+  void ReadAsText(File& aBlob, const nsAString& aLabel, ErrorResult& aRv)
   {
-    MOZ_ASSERT(aBlob);
     ReadFileContent(nullptr, aBlob, aLabel, FILE_AS_TEXT, aRv);
   }
 
-  void ReadAsDataURL(nsIDOMBlob* aBlob, ErrorResult& aRv)
+  void ReadAsDataURL(File& aBlob, ErrorResult& aRv)
   {
-    MOZ_ASSERT(aBlob);
     ReadFileContent(nullptr, aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
   }
 
   using FileIOObject::Abort;
 
   // Inherited ReadyState().
 
   void GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
@@ -94,19 +97,18 @@ public:
   using FileIOObject::SetOnprogress;
   IMPL_EVENT_HANDLER(load)
   using FileIOObject::GetOnabort;
   using FileIOObject::SetOnabort;
   using FileIOObject::GetOnerror;
   using FileIOObject::SetOnerror;
   IMPL_EVENT_HANDLER(loadend)
 
-  void ReadAsBinaryString(nsIDOMBlob* aBlob, ErrorResult& aRv)
+  void ReadAsBinaryString(File& aBlob, ErrorResult& aRv)
   {
-    MOZ_ASSERT(aBlob);
     ReadFileContent(nullptr, aBlob, EmptyString(), FILE_AS_BINARY, aRv);
   }
 
 
   nsresult Init();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsDOMFileReader,
                                                          FileIOObject)
@@ -117,17 +119,17 @@ protected:
 
   enum eDataFormat {
     FILE_AS_ARRAYBUFFER,
     FILE_AS_BINARY,
     FILE_AS_TEXT,
     FILE_AS_DATAURL
   };
 
-  void ReadFileContent(JSContext* aCx, nsIDOMBlob* aBlob,
+  void ReadFileContent(JSContext* aCx, File& aBlob,
                        const nsAString &aCharset, eDataFormat aDataFormat,
                        ErrorResult& aRv);
   nsresult GetAsText(nsIDOMBlob *aFile, const nsACString &aCharset,
                      const char *aFileData, uint32_t aDataLen, nsAString &aResult);
   nsresult GetAsDataURL(nsIDOMBlob *aFile, const char *aFileData, uint32_t aDataLen, nsAString &aResult);
 
   void FreeFileData() {
     moz_free(mFileData);
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -13,20 +13,16 @@
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/BinarySearch.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Likely.h"
 #include <algorithm>
 
-#ifdef MOZ_LOGGING
-// so we can get logging even in release builds
-#define FORCE_PR_LOG 1
-#endif
 #include "prlog.h"
 #include "plstr.h"
 #include "prprf.h"
 
 #include "mozilla/Telemetry.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsILoadContext.h"
--- a/content/base/src/nsFormData.cpp
+++ b/content/base/src/nsFormData.cpp
@@ -1,34 +1,60 @@
 /* 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 "nsFormData.h"
 #include "nsIVariant.h"
 #include "nsIInputStream.h"
-#include "nsIDOMFile.h"
+#include "mozilla/dom/File.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/HTMLFormElement.h"
 #include "mozilla/dom/FormDataBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsFormData::nsFormData(nsISupports* aOwner)
   : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr)
   , mOwner(aOwner)
 {
 }
 
 // -------------------------------------------------------------------------
 // nsISupports
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsFormData, mOwner)
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsFormData)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormData)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
+
+  for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
+    ImplCycleCollectionUnlink(tmp->mFormData[i].fileValue);
+  }
+
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFormData)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
+
+  for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) {
+   ImplCycleCollectionTraverse(cb,tmp->mFormData[i].fileValue,
+                               "mFormData[i].fileValue", 0);
+  }
+
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsFormData)
+
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFormData)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFormData)
+
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFormData)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsIDOMFormData)
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFormData)
 NS_INTERFACE_MAP_END
 
 // -------------------------------------------------------------------------
@@ -43,26 +69,26 @@ nsFormData::GetEncodedSubmission(nsIURI*
 
 void
 nsFormData::Append(const nsAString& aName, const nsAString& aValue)
 {
   AddNameValuePair(aName, aValue);
 }
 
 void
-nsFormData::Append(const nsAString& aName, nsIDOMBlob* aBlob,
+nsFormData::Append(const nsAString& aName, File& aBlob,
                    const Optional<nsAString>& aFilename)
 {
   nsString filename;
   if (aFilename.WasPassed()) {
     filename = aFilename.Value();
   } else {
     filename.SetIsVoid(true);
   }
-  AddNameFilePair(aName, aBlob, filename);
+  AddNameFilePair(aName, &aBlob, filename);
 }
 
 // -------------------------------------------------------------------------
 // nsIDOMFormData
 
 NS_IMETHODIMP
 nsFormData::Append(const nsAString& aName, nsIVariant* aValue)
 {
@@ -75,19 +101,20 @@ nsFormData::Append(const nsAString& aNam
     nsCOMPtr<nsISupports> supports;
     nsID *iid;
     rv = aValue->GetAsInterface(&iid, getter_AddRefs(supports));
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsMemory::Free(iid);
 
     nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(supports);
+    nsRefPtr<File> blob = static_cast<File*>(domBlob.get());
     if (domBlob) {
       Optional<nsAString> temp;
-      Append(aName, domBlob, temp);
+      Append(aName, *blob, temp);
       return NS_OK;
     }
   }
 
   char16_t* stringData = nullptr;
   uint32_t stringLen = 0;
   rv = aValue->GetAsWStringWithSize(&stringLen, &stringData);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/content/base/src/nsFormData.h
+++ b/content/base/src/nsFormData.h
@@ -1,31 +1,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsFormData_h__
 #define nsFormData_h__
 
 #include "mozilla/Attributes.h"
-#include "nsIDOMFile.h"
 #include "nsIDOMFormData.h"
 #include "nsIXMLHttpRequest.h"
 #include "nsFormSubmission.h"
 #include "nsWrapperCache.h"
 #include "nsTArray.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 
-class nsIDOMFile;
-
 namespace mozilla {
 class ErrorResult;
 
 namespace dom {
+class File;
 class HTMLFormElement;
 class GlobalObject;
 } // namespace dom
 } // namespace mozilla
 
 class nsFormData MOZ_FINAL : public nsIDOMFormData,
                              public nsIXHRSendable,
                              public nsFormSubmission,
@@ -52,17 +50,17 @@ public:
   {
     return mOwner;
   }
   static already_AddRefed<nsFormData>
   Constructor(const mozilla::dom::GlobalObject& aGlobal,
               const mozilla::dom::Optional<mozilla::dom::NonNull<mozilla::dom::HTMLFormElement> >& aFormElement,
               mozilla::ErrorResult& aRv);
   void Append(const nsAString& aName, const nsAString& aValue);
-  void Append(const nsAString& aName, nsIDOMBlob* aBlob,
+  void Append(const nsAString& aName, mozilla::dom::File& aBlob,
               const mozilla::dom::Optional<nsAString>& aFilename);
 
   // nsFormSubmission
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream) MOZ_OVERRIDE;
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) MOZ_OVERRIDE
   {
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -22,20 +22,20 @@
 #include "nsIXULRuntime.h"
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 #include "nsIMemoryReporter.h"
 #include "nsIProtocolHandler.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIDOMClassInfo.h"
-#include "nsIDOMFile.h"
 #include "xpcpublic.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/nsIContentParent.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/StructuredCloneUtils.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "JavaScriptChild.h"
 #include "JavaScriptParent.h"
@@ -199,17 +199,17 @@ template<ActorFlavorEnum Flavor>
 static bool
 BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType* aManager,
                        const StructuredCloneData& aData,
                        ClonedMessageData& aClonedData)
 {
   SerializedStructuredCloneBuffer& buffer = aClonedData.data();
   buffer.data = aData.mData;
   buffer.dataLength = aData.mDataLength;
-  const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
+  const nsTArray<nsRefPtr<File>>& blobs = aData.mClosure.mBlobs;
   if (!blobs.IsEmpty()) {
     typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
     InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
     uint32_t length = blobs.Length();
     blobList.SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       typename BlobTraits<Flavor>::BlobType* protocolActor =
         aManager->GetOrCreateActorForBlob(blobs[i]);
@@ -250,18 +250,23 @@ UnpackClonedMessageData(const ClonedMess
   cloneData.mDataLength = buffer.dataLength;
   if (!blobs.IsEmpty()) {
     uint32_t length = blobs.Length();
     cloneData.mClosure.mBlobs.SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       auto* blob =
         static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
       MOZ_ASSERT(blob);
-      nsCOMPtr<nsIDOMBlob> domBlob = blob->GetBlob();
-      MOZ_ASSERT(domBlob);
+
+      nsRefPtr<FileImpl> blobImpl = blob->GetBlobImpl();
+      MOZ_ASSERT(blobImpl);
+
+      // This object will be duplicated with a correct parent before being
+      // exposed to JS.
+      nsRefPtr<File> domBlob = new File(nullptr, blobImpl);
       cloneData.mClosure.mBlobs.AppendElement(domBlob);
     }
   }
   return cloneData;
 }
 
 StructuredCloneData
 mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aData)
--- a/content/base/src/nsHostObjectProtocolHandler.cpp
+++ b/content/base/src/nsHostObjectProtocolHandler.cpp
@@ -5,24 +5,25 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsHostObjectProtocolHandler.h"
 #include "nsHostObjectURI.h"
 #include "nsError.h"
 #include "nsClassHashtable.h"
 #include "nsNetUtil.h"
 #include "nsIPrincipal.h"
-#include "nsDOMFile.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::DOMFileImpl;
+using mozilla::dom::FileImpl;
+using mozilla::ErrorResult;
 using mozilla::LoadInfo;
 
 // -----------------------------------------------------------------------
 // Hash table
 struct DataInfo
 {
   // mObject is expected to be an nsIDOMBlob, DOMMediaStream, or MediaSource
   nsCOMPtr<nsISupports> mObject;
@@ -491,55 +492,55 @@ nsHostObjectProtocolHandler::NewChannel(
   uri->GetSpec(spec);
 
   DataInfo* info = GetDataInfo(spec);
 
   if (!info) {
     return NS_ERROR_DOM_BAD_URI;
   }
 
-  nsCOMPtr<PIDOMFileImpl> blobImpl = do_QueryInterface(info->mObject);
+  nsCOMPtr<PIFileImpl> blobImpl = do_QueryInterface(info->mObject);
   if (!blobImpl) {
     return NS_ERROR_DOM_BAD_URI;
   }
 
 #ifdef DEBUG
   {
     nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(uri);
     nsCOMPtr<nsIPrincipal> principal;
     uriPrinc->GetPrincipal(getter_AddRefs(principal));
     NS_ASSERTION(info->mPrincipal == principal, "Wrong principal!");
   }
 #endif
 
-  DOMFileImpl* blob = static_cast<DOMFileImpl*>(blobImpl.get());
+  FileImpl* blob = static_cast<FileImpl*>(blobImpl.get());
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = blob->GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
                                 uri,
                                 stream);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsString type;
-  rv = blob->GetType(type);
-  NS_ENSURE_SUCCESS(rv, rv);
+  blob->GetType(type);
 
   if (blob->IsFile()) {
     nsString filename;
-    rv = blob->GetName(filename);
-    NS_ENSURE_SUCCESS(rv, rv);
+    blob->GetName(filename);
     channel->SetContentDispositionFilename(filename);
   }
 
-  uint64_t size;
-  rv = blob->GetSize(&size);
-  NS_ENSURE_SUCCESS(rv, rv);
+  ErrorResult error;
+  uint64_t size = blob->GetSize(error);
+  if (NS_WARN_IF(error.Failed())) {
+    return error.ErrorCode();
+  }
 
   nsCOMPtr<nsILoadInfo> loadInfo =
     new mozilla::LoadInfo(info->mPrincipal,
                           nullptr,
                           nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
                           nsIContentPolicy::TYPE_OTHER);
   channel->SetLoadInfo(loadInfo);
   channel->SetOriginalURI(uri);
@@ -590,22 +591,22 @@ nsFontTableProtocolHandler::GetScheme(ns
 
 nsresult
 NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream)
 {
   NS_ASSERTION(IsBlobURI(aURI), "Only call this with blob URIs");
 
   *aStream = nullptr;
 
-  nsCOMPtr<PIDOMFileImpl> blobImpl = do_QueryInterface(GetDataObject(aURI));
+  nsCOMPtr<PIFileImpl> blobImpl = do_QueryInterface(GetDataObject(aURI));
   if (!blobImpl) {
     return NS_ERROR_DOM_BAD_URI;
   }
 
-  DOMFileImpl* blob = static_cast<DOMFileImpl*>(blobImpl.get());
+  FileImpl* blob = static_cast<FileImpl*>(blobImpl.get());
   return blob->GetInternalStream(aStream);
 }
 
 nsresult
 NS_GetStreamForMediaStreamURI(nsIURI* aURI, mozilla::DOMMediaStream** aStream)
 {
   NS_ASSERTION(IsMediaStreamURI(aURI), "Only call this with mediastream URIs");
 
--- a/content/base/src/nsNodeInfoManager.cpp
+++ b/content/base/src/nsNodeInfoManager.cpp
@@ -27,20 +27,16 @@
 #include "nsBindingManager.h"
 #include "nsHashKeys.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsNameSpaceManager.h"
 
 using namespace mozilla;
 using mozilla::dom::NodeInfo;
 
-#ifdef MOZ_LOGGING
-// so we can get logging even in release builds
-#define FORCE_PR_LOG 1
-#endif
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gNodeInfoManagerLeakPRLog;
 #endif
 
 PLHashNumber
 nsNodeInfoManager::GetNodeInfoInnerHashValue(const void *key)
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -5,22 +5,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsXMLHttpRequest.h"
 
 #ifndef XP_WIN
 #include <unistd.h>
 #endif
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/dom/BlobSet.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/XMLHttpRequestUploadBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/MemoryReporting.h"
-#include "nsDOMBlobBuilder.h"
 #include "nsIDOMDocument.h"
 #include "mozilla/dom/ProgressEvent.h"
 #include "nsIJARChannel.h"
 #include "nsIJARURI.h"
 #include "nsLayoutCID.h"
 #include "nsReadableUtils.h"
 
 #include "nsIURI.h"
@@ -51,17 +52,16 @@
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
 #include "nsIConsoleService.h"
 #include "nsIChannelPolicy.h"
 #include "nsChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "nsStringBuffer.h"
-#include "nsDOMFile.h"
 #include "nsIFileChannel.h"
 #include "mozilla/Telemetry.h"
 #include "jsfriendapi.h"
 #include "GeckoProfiler.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "nsIUnicodeDecoder.h"
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "mozilla/Attributes.h"
@@ -779,33 +779,34 @@ nsXMLHttpRequest::CreatePartialBlob()
 {
   if (mDOMFile) {
     // Use progress info to determine whether load is complete, but use
     // mDataAvailable to ensure a slice is created based on the uncompressed
     // data count.
     if (mLoadTotal == mLoadTransferred) {
       mResponseBlob = mDOMFile;
     } else {
-      mResponseBlob =
-        mDOMFile->CreateSlice(0, mDataAvailable, EmptyString());
+      ErrorResult rv;
+      mResponseBlob = mDOMFile->CreateSlice(0, mDataAvailable,
+                                            EmptyString(), rv);
     }
     return;
   }
 
   // mBlobSet can be null if the request has been canceled
   if (!mBlobSet) {
     return;
   }
 
   nsAutoCString contentType;
   if (mLoadTotal == mLoadTransferred) {
     mChannel->GetContentType(contentType);
   }
 
-  mResponseBlob = mBlobSet->GetBlobInternal(contentType);
+  mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType);
 }
 
 /* attribute AString responseType; */
 NS_IMETHODIMP nsXMLHttpRequest::GetResponseType(nsAString& aResponseType)
 {
   switch (mResponseType) {
   case XML_HTTP_RESPONSE_TYPE_DEFAULT:
     aResponseType.Truncate();
@@ -1002,17 +1003,17 @@ nsXMLHttpRequest::GetResponse(JSContext*
       }
     }
 
     if (!mResponseBlob) {
       aResponse.setNull();
       return;
     }
 
-    aRv = nsContentUtils::WrapNative(aCx, mResponseBlob, aResponse);
+    WrapNewBindingObject(aCx, mResponseBlob, aResponse);
     return;
   }
   case XML_HTTP_RESPONSE_TYPE_DOCUMENT:
   {
     if (!(mState & XML_HTTP_REQUEST_DONE) || !mResponseXML) {
       aResponse.setNull();
       return;
     }
@@ -1892,19 +1893,18 @@ bool nsXMLHttpRequest::CreateDOMFile(nsI
   }
 
   if (!file)
     return false;
 
   nsAutoCString contentType;
   mChannel->GetContentType(contentType);
 
-  mDOMFile =
-    DOMFile::CreateFromFile(file, EmptyString(),
-                            NS_ConvertASCIItoUTF16(contentType));
+  mDOMFile = File::CreateFromFile(GetOwner(), file, EmptyString(),
+                                  NS_ConvertASCIItoUTF16(contentType));
 
   mBlobSet = nullptr;
   NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
   return true;
 }
 
 NS_IMETHODIMP
 nsXMLHttpRequest::OnDataAvailable(nsIRequest *request,
@@ -2238,17 +2238,17 @@ nsXMLHttpRequest::OnStopRequest(nsIReque
       // and if the response length is zero.
       if (!mBlobSet) {
         mBlobSet = new BlobSet();
       }
       // Smaller files may be written in cache map instead of separate files.
       // Also, no-store response cannot be written in persistent cache.
       nsAutoCString contentType;
       mChannel->GetContentType(contentType);
-      mResponseBlob = mBlobSet->GetBlobInternal(contentType);
+      mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType);
       mBlobSet = nullptr;
     }
     NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
     NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty");
   } else if (NS_SUCCEEDED(status) &&
              ((mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER &&
                !mIsMappedArrayBuffer) ||
               mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER)) {
@@ -2613,17 +2613,18 @@ nsXMLHttpRequest::GetRequestBody(nsIVari
       const ArrayBufferView* view = value.mArrayBufferView;
       view->ComputeLengthAndData();
       return ::GetRequestBody(view->Data(), view->Length(), aResult,
                               aContentLength, aContentType, aCharset);
     }
     case nsXMLHttpRequest::RequestBody::Blob:
     {
       nsresult rv;
-      nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(value.mBlob, &rv);
+      nsCOMPtr<nsIDOMBlob> blob = value.mBlob;
+      nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(blob, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
 
       return ::GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
     }
     case nsXMLHttpRequest::RequestBody::Document:
     {
       nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(value.mDocument);
       return ::GetRequestBody(document, aResult, aContentLength, aContentType, aCharset);
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -36,28 +36,27 @@
 
 #ifdef Status
 /* Xlib headers insist on this for some reason... Nuke it because
    it'll override our member name */
 #undef Status
 #endif
 
 class AsyncVerifyRedirectCallbackForwarder;
-class BlobSet;
-class nsDOMFile;
 class nsFormData;
 class nsIJARChannel;
 class nsILoadGroup;
 class nsIUnicodeDecoder;
 class nsIJSID;
 
 namespace mozilla {
 
 namespace dom {
-class DOMFile;
+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
@@ -345,19 +344,19 @@ private:
     explicit RequestBody(const mozilla::dom::ArrayBuffer* aArrayBuffer) : mType(ArrayBuffer)
     {
       mValue.mArrayBuffer = aArrayBuffer;
     }
     explicit RequestBody(const mozilla::dom::ArrayBufferView* aArrayBufferView) : mType(ArrayBufferView)
     {
       mValue.mArrayBufferView = aArrayBufferView;
     }
-    explicit RequestBody(nsIDOMBlob* aBlob) : mType(Blob)
+    explicit RequestBody(mozilla::dom::File& aBlob) : mType(Blob)
     {
-      mValue.mBlob = aBlob;
+      mValue.mBlob = &aBlob;
     }
     explicit RequestBody(nsIDocument* aDocument) : mType(Document)
     {
       mValue.mDocument = aDocument;
     }
     explicit RequestBody(const nsAString& aString) : mType(DOMString)
     {
       mValue.mString = &aString;
@@ -379,17 +378,17 @@ private:
       Document,
       DOMString,
       FormData,
       InputStream
     };
     union Value {
       const mozilla::dom::ArrayBuffer* mArrayBuffer;
       const mozilla::dom::ArrayBufferView* mArrayBufferView;
-      nsIDOMBlob* mBlob;
+      mozilla::dom::File* mBlob;
       nsIDocument* mDocument;
       const nsAString* mString;
       nsFormData* mFormData;
       nsIInputStream* mStream;
     };
 
     Type GetType() const
     {
@@ -435,19 +434,18 @@ public:
   {
     aRv = Send(RequestBody(&aArrayBuffer));
   }
   void Send(const mozilla::dom::ArrayBufferView& aArrayBufferView,
             ErrorResult& aRv)
   {
     aRv = Send(RequestBody(&aArrayBufferView));
   }
-  void Send(nsIDOMBlob* aBlob, ErrorResult& aRv)
+  void Send(mozilla::dom::File& aBlob, ErrorResult& aRv)
   {
-    NS_ASSERTION(aBlob, "Null should go to string version");
     aRv = Send(RequestBody(aBlob));
   }
   void Send(nsIDocument& aDoc, ErrorResult& aRv)
   {
     aRv = Send(RequestBody(&aDoc));
   }
   void Send(const nsAString& aString, ErrorResult& aRv)
   {
@@ -667,23 +665,23 @@ protected:
   };
 
   void SetResponseType(nsXMLHttpRequest::ResponseTypeEnum aType, ErrorResult& aRv);
 
   ResponseTypeEnum mResponseType;
 
   // It is either a cached blob-response from the last call to GetResponse,
   // but is also explicitly set in OnStopRequest.
-  nsCOMPtr<nsIDOMBlob> mResponseBlob;
+  nsRefPtr<mozilla::dom::File> mResponseBlob;
   // Non-null only when we are able to get a os-file representation of the
   // response, i.e. when loading from a file.
-  nsRefPtr<mozilla::dom::DOMFile> mDOMFile;
+  nsRefPtr<mozilla::dom::File> mDOMFile;
   // We stream data to mBlobSet when response type is "blob" or "moz-blob"
   // and mDOMFile is null.
-  nsAutoPtr<BlobSet> mBlobSet;
+  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.
    */
   nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
--- a/content/base/test/chrome/test_bug914381.html
+++ b/content/base/test/chrome/test_bug914381.html
@@ -28,21 +28,21 @@ function createFileWithData(fileData) {
   outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
                  0666, 0);
   outStream.write(fileData, fileData.length);
   outStream.close();
 
   return testFile;
 }
 
-/** Test for Bug 914381. DOMFile's created in JS using an nsIFile should allow mozGetFullPathInternal calls to succeed **/
+/** Test for Bug 914381. File's created in JS using an nsIFile should allow mozGetFullPathInternal calls to succeed **/
 var file = createFileWithData("Test bug 914381");
-var f = File(file);
+var f = new File(file);
 is(f.mozFullPathInternal, undefined, "mozFullPathInternal is undefined from js");
 is(f.mozFullPath, file.path, "mozFullPath returns path if created with nsIFile");
 
-f = File(file.path);
+f = new File(file.path);
 is(f.mozFullPathInternal, undefined, "mozFullPathInternal is undefined from js");
 is(f.mozFullPath, "", "mozFullPath returns blank if created with a string");
 </script>
 </pre>
 </body>
 </html>
--- a/content/base/test/test_blobconstructor.html
+++ b/content/base/test/test_blobconstructor.html
@@ -15,75 +15,75 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript;version=1.7">
 "use strict";
 /** Test for Bug 721569 **/
-var blob = Blob();
+var blob = new Blob();
 ok(blob, "Blob should exist");
 
 ok(blob.size !== undefined, "Blob should have a size property");
 ok(blob.type !== undefined, "Blob should have a type property");
 ok(blob.slice, "Blob should have a slice method");
 
-blob = Blob([], {type: null});
+blob = new Blob([], {type: null});
 ok(blob, "Blob should exist");
 is(blob.type, "null", "Blob type should be stringified");
 
-blob = Blob([], {type: undefined});
+blob = new Blob([], {type: undefined});
 ok(blob, "Blob should exist");
 is(blob.type, "", "Blob type should be treated as missing");
 
 try {
-blob = Blob([]);
+blob = new Blob([]);
 ok(true, "an empty blobParts argument should not throw");
 } catch(e) {
 ok(false, "NOT REACHED");
 }
 
 try {
-blob = Blob(null);
+blob = new Blob(null);
 ok(false, "NOT REACHED");
 } catch(e) {
 ok(true, "a null blobParts member should throw");
 }
 
 try {
-blob = Blob([], null);
+blob = new Blob([], null);
 ok(true, "a null options member should not throw");
 } catch(e) {
 ok(false, "NOT REACHED");
 }
 
 try {
-blob = Blob([], undefined);
+blob = new Blob([], undefined);
 ok(true, "an undefined options member should not throw");
 } catch(e) {
 ok(false, "NOT REACHED");
 }
 
 try {
-blob = Blob([], false);
+blob = new Blob([], false);
 ok(false, "NOT REACHED");
 } catch(e) {
 ok(true, "a boolean options member should throw");
 }
 
 try {
-blob = Blob([], 0);
+blob = new Blob([], 0);
 ok(false, "NOT REACHED");
 } catch(e) {
 ok(true, "a numeric options member should throw");
 }
 
 try {
-blob = Blob([], "");
+blob = new Blob([], "");
 ok(false, "NOT REACHED");
 } catch(e) {
 ok(true, "a string options member should throw");
 }
 
 /** Test for dictionary initialization order **/
 (function() {
   var o = {};
@@ -95,23 +95,23 @@ ok(true, "a string options member should
   }
   ["type", "endings"].forEach(function(n) {
     Object.defineProperty(o, n, { get: add_to_called.bind(null, n) });
   });
   var b = new Blob([], o);
   is(JSON.stringify(called), JSON.stringify(["endings", "type"]), "dictionary members should be get in lexicographical order");
 })();
 
-let blob1 = Blob(["squiggle"]);
+let blob1 = new Blob(["squiggle"]);
 ok(blob1 instanceof Blob, "Blob constructor should produce Blobs");
 ok(!(blob1 instanceof File), "Blob constructor should not produce Files");
 is(blob1.type, "", "Blob constructor with no options should return Blob with empty type");
 is(blob1.size, 8, "Blob constructor should return Blob with correct size");
 
-let blob2 = Blob(["steak"], {type: "content/type"});
+let blob2 = new Blob(["steak"], {type: "content/type"});
 ok(blob2 instanceof Blob, "Blob constructor should produce Blobs");
 ok(!(blob2 instanceof File), "Blob constructor should not produce Files");
 is(blob2.type, "content/type", "Blob constructor with a type option should return Blob with the type");
 is(blob2.size, 5, "Blob constructor should return Blob with correct size");
 
 
 let aB = new ArrayBuffer(16);
 var int8View = new Int8Array(aB);
--- a/content/base/test/test_bug403852.html
+++ b/content/base/test/test_bug403852.html
@@ -8,17 +8,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=403852">Mozilla Bug 403852</a>
 <p id="display">
   <input id="fileList" type="file"></input>
-  <canvas id="canvas"></canvas>
 </p>
 <div id="content" style="display: none">
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 var testFile = SpecialPowers.Services.dirsvc.get("ProfD", SpecialPowers.Ci.nsIFile);
@@ -32,19 +31,23 @@ var domFile = fileList.files[0];
 
 is(domFile.name, "prefs.js", "fileName should be prefs.js");
 
 ok("lastModifiedDate" in domFile, "lastModifiedDate must be present");
 
 var d = new Date(testFile.lastModifiedTime);
 ok(d.getTime() == domFile.lastModifiedDate.getTime(), "lastModifiedDate should be the same.");
 
-var cf = document.getElementById("canvas").mozGetAsFile("canvFile");
+var x = new Date();
 
-var x = new Date();
-var y = cf.lastModifiedDate;
+// In our implementation of File object, lastModifiedDate is unknown only for new objects.
+// Using canvas or input[type=file] elements, we 'often' have a valid lastModifiedDate values.
+// For canvas we use memory files and the lastModifiedDate is now().
+var f = new File([new Blob(['test'], {type: 'text/plain'})], "test-name");
+
+var y = f.lastModifiedDate;
 var z = new Date();
 
 ok((x.getTime() <= y.getTime()) && (y.getTime() <= z.getTime()), "lastModifiedDate of file which does not have last modified date should be current time");
 
 </script>
 </pre>
 </body> </html>
--- a/content/html/content/public/HTMLCanvasElement.h
+++ b/content/html/content/public/HTMLCanvasElement.h
@@ -11,31 +11,31 @@
 #include "nsGenericHTMLElement.h"
 #include "nsGkAtoms.h"
 #include "nsSize.h"
 #include "nsError.h"
 
 #include "mozilla/gfx/Rect.h"
 
 class nsICanvasRenderingContextInternal;
-class nsIDOMFile;
 class nsITimerCallback;
 
 namespace mozilla {
 
 namespace layers {
 class CanvasLayer;
 class LayerManager;
 }
 namespace gfx {
 class SourceSurface;
 }
 
 namespace dom {
 
+class File;
 class FileCallback;
 class HTMLCanvasPrintState;
 class PrintCallback;
 
 class HTMLCanvasElement MOZ_FINAL : public nsGenericHTMLElement,
                                     public nsIDOMHTMLCanvasElement
 {
   enum {
@@ -97,19 +97,19 @@ public:
   bool MozOpaque() const
   {
     return GetBoolAttr(nsGkAtoms::moz_opaque);
   }
   void SetMozOpaque(bool aValue, ErrorResult& aRv)
   {
     SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv);
   }
-  already_AddRefed<nsIDOMFile> MozGetAsFile(const nsAString& aName,
-                                            const nsAString& aType,
-                                            ErrorResult& aRv);
+  already_AddRefed<File> MozGetAsFile(const nsAString& aName,
+                                      const nsAString& aType,
+                                      ErrorResult& aRv);
   already_AddRefed<nsISupports> MozGetIPCContext(const nsAString& aContextId,
                                                  ErrorResult& aRv)
   {
     nsCOMPtr<nsISupports> context;
     aRv = MozGetIPCContext(aContextId, getter_AddRefs(context));
     return context.forget();
   }
   void MozFetchAsStream(nsIInputStreamCallback* aCallback,
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -7,28 +7,28 @@
 
 #include "ImageEncoder.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "Layers.h"
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/CanvasRenderingContext2D.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/HTMLCanvasElementBinding.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/MouseEvent.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "nsAttrValueInlines.h"
 #include "nsContentUtils.h"
 #include "nsDisplayList.h"
-#include "nsDOMFile.h"
 #include "nsDOMJSUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsITimer.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsIXPConnect.h"
 #include "nsJSUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsMathUtils.h"
@@ -544,29 +544,31 @@ 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<DOMFile> aBlob)
+    nsresult ReceiveBlob(already_AddRefed<File> aBlob)
     {
-      nsRefPtr<DOMFile> blob = aBlob;
+      nsRefPtr<File> blob = aBlob;
       uint64_t size;
       nsresult rv = blob->GetSize(&size);
       if (NS_SUCCEEDED(rv)) {
         AutoJSAPI jsapi;
         jsapi.Init(mGlobal);
         JS_updateMallocCounter(jsapi.cx(), size);
       }
 
+      nsRefPtr<File> newBlob = new File(mGlobal, blob->Impl());
+
       mozilla::ErrorResult error;
-      mFileCallback->Call(blob, error);
+      mFileCallback->Call(*newBlob, error);
 
       mGlobal = nullptr;
       mFileCallback = nullptr;
 
       return error.ErrorCode();
     }
 
     nsCOMPtr<nsIGlobalObject> mGlobal;
@@ -580,24 +582,25 @@ HTMLCanvasElement::ToBlob(JSContext* aCx
                                        params,
                                        usingCustomParseOptions,
                                        imageBuffer,
                                        format,
                                        GetSize(),
                                        callback);
 }
 
-already_AddRefed<nsIDOMFile>
+already_AddRefed<File>
 HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
                                 const nsAString& aType,
                                 ErrorResult& aRv)
 {
   nsCOMPtr<nsIDOMFile> file;
   aRv = MozGetAsFile(aName, aType, getter_AddRefs(file));
-  return file.forget();
+  nsRefPtr<File> tmp = static_cast<File*>(file.get());
+  return tmp.forget();
 }
 
 NS_IMETHODIMP
 HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
                                 const nsAString& aType,
                                 nsIDOMFile** aResult)
 {
   OwnerDoc()->WarnOnceAbout(nsIDocument::eMozGetAsFile);
@@ -630,20 +633,22 @@ HTMLCanvasElement::MozGetAsFileImpl(cons
   rv = NS_ReadInputStreamToBuffer(stream, &imgData, (uint32_t)imgSize);
   NS_ENSURE_SUCCESS(rv, rv);
 
   JSContext* cx = nsContentUtils::GetCurrentJSContext();
   if (cx) {
     JS_updateMallocCounter(cx, imgSize);
   }
 
-  // The DOMFile takes ownership of the buffer
-  nsRefPtr<DOMFile> file =
-    DOMFile::CreateMemoryFile(imgData, (uint32_t)imgSize, aName, type,
-                              PR_Now());
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(OwnerDoc()->GetScopeObject());
+
+  // The File takes ownership of the buffer
+  nsRefPtr<File> file =
+    File::CreateMemoryFile(win, imgData, (uint32_t)imgSize, aName, type,
+                           PR_Now());
 
   file.forget(aResult);
   return NS_OK;
 }
 
 nsresult
 HTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
                                     nsICanvasRenderingContextInternal **aContext)
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -68,19 +68,19 @@
 
 #include "nsRuleData.h"
 #include <algorithm>
 
 // input type=radio
 #include "nsIRadioGroupContainer.h"
 
 // input type=file
+#include "mozilla/dom/File.h"
 #include "nsIFile.h"
 #include "nsNetUtil.h"
-#include "nsDOMFile.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIContentPrefService.h"
 #include "nsIMIMEService.h"
 #include "nsIObserverService.h"
 #include "nsIPopupWindowManager.h"
 #include "nsGlobalWindow.h"
 
 // input type=image
@@ -231,36 +231,36 @@ class HTMLInputElementState MOZ_FINAL : 
     const nsString& GetValue() {
       return mValue;
     }
 
     void SetValue(const nsAString& aValue) {
       mValue = aValue;
     }
 
-    const nsTArray<nsCOMPtr<nsIDOMFile> >& GetFiles() {
+    const nsTArray<nsRefPtr<File>>& GetFiles() {
       return mFiles;
     }
 
-    void SetFiles(const nsTArray<nsCOMPtr<nsIDOMFile> >& aFiles) {
+    void SetFiles(const nsTArray<nsRefPtr<File>>& aFiles) {
       mFiles.Clear();
       mFiles.AppendElements(aFiles);
     }
 
     HTMLInputElementState()
       : mValue()
       , mChecked(false)
       , mCheckedSet(false)
     {};
 
   protected:
     ~HTMLInputElementState() {}
 
     nsString mValue;
-    nsTArray<nsCOMPtr<nsIDOMFile> > mFiles;
+    nsTArray<nsRefPtr<File>> mFiles;
     bool mChecked;
     bool mCheckedSet;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(HTMLInputElementState, NS_INPUT_ELEMENT_STATE_IID)
 
 NS_IMPL_ISUPPORTS(HTMLInputElementState, HTMLInputElementState)
 
@@ -311,17 +311,17 @@ UploadLastDir::ContentPrefCallback::Hand
   // HandleCompletion is always called (even with HandleError was called),
   // so we don't need to do anything special here.
   return NS_OK;
 }
 
 namespace {
 
 /**
- * This enumerator returns nsDOMFileFile objects after wrapping a single
+ * This enumerator returns File objects after wrapping a single
  * nsIFile representing a directory. It enumerates the files under that
  * directory and its subdirectories as a flat list of files, ignoring/skipping
  * over symbolic links.
  *
  * The enumeration involves I/O, so this class must NOT be used on the main
  * thread or else the main thread could be blocked for a very long time.
  *
  * This enumerator does not walk the directory tree breadth-first, but it also
@@ -369,31 +369,32 @@ public:
   {
     MOZ_ASSERT(!NS_IsMainThread(),
                "Walking the directory tree involves I/O, so using this "
                "enumerator can block a thread for a long time!");
 
     if (!mNextFile) {
       return NS_ERROR_FAILURE;
     }
-    nsRefPtr<DOMFile> domFile = DOMFile::CreateFromFile(mNextFile);
+
+    // The parent for this object will be set on the main thread.
+    nsRefPtr<File> domFile = File::CreateFromFile(nullptr, mNextFile);
     nsCString relDescriptor;
     nsresult rv =
       mNextFile->GetRelativeDescriptor(mTopDirsParent, relDescriptor);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ConvertUTF8toUTF16 path(relDescriptor);
     nsAutoString leafName;
     mNextFile->GetLeafName(leafName);
     MOZ_ASSERT(leafName.Length() <= path.Length());
     int32_t length = path.Length() - leafName.Length();
     MOZ_ASSERT(length >= 0);
     if (length > 0) {
       // Note that we leave the trailing "/" on the path.
-      DOMFileImplFile* fileImpl =
-        static_cast<DOMFileImplFile*>(domFile->Impl());
+      FileImplFile* fileImpl = static_cast<FileImplFile*>(domFile->Impl());
       MOZ_ASSERT(fileImpl);
       fileImpl->SetPath(Substring(path, 0, uint32_t(length)));
     }
     *aResult = domFile.forget().downcast<nsIDOMFile>().take();
     LookupAndCacheNext();
     return NS_OK;
   }
 
@@ -507,26 +508,26 @@ public:
     , mInput(aInput)
     , mTopDir(aTopDir)
     , mFileListLength(0)
     , mCanceled(false)
   {}
 
   NS_IMETHOD Run() {
     if (!NS_IsMainThread()) {
-      // Build up list of nsDOMFileFile objects on this dedicated thread:
+      // Build up list of File objects on this dedicated thread:
       nsCOMPtr<nsISimpleEnumerator> iter =
         new DirPickerRecursiveFileEnumerator(mTopDir);
       bool hasMore = true;
       nsCOMPtr<nsISupports> tmp;
       while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
         iter->GetNext(getter_AddRefs(tmp));
         nsCOMPtr<nsIDOMFile> domFile = do_QueryInterface(tmp);
         MOZ_ASSERT(domFile);
-        mFileList.AppendElement(domFile);
+        mFileList.AppendElement(static_cast<File*>(domFile.get()));
         mFileListLength = mFileList.Length();
         if (mCanceled) {
           MOZ_ASSERT(!mInput, "This is bad - how did this happen?");
           // There's no point dispatching to the main thread (that doesn't
           // guarantee that we'll be destroyed there).
           return NS_OK;
         }
       }
@@ -546,16 +547,23 @@ public:
 
     mInput->MaybeDispatchProgressEvent(true);        // Last progress event.
     mInput->mDirPickerFileListBuilderTask = nullptr; // Now null out.
 
     if (mCanceled) { // The last progress event may have canceled us
       return NS_OK;
     }
 
+    // Recreate 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());
+    }
+
     // The text control frame (if there is one) isn't going to send a change
     // event because it will think this is done by a script.
     // So, we can safely send one by ourself.
     mInput->SetFiles(mFileList, true);
     nsresult rv =
       nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
                                            static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
                                            NS_LITERAL_STRING("change"), true,
@@ -589,17 +597,17 @@ public:
    * we don't increase the size of HTMLInputElement for something that's rarely
    * used.
    */
   uint32_t mPreviousFileListLength;
 
 private:
   nsRefPtr<HTMLInputElement> mInput;
   nsCOMPtr<nsIFile> mTopDir;
-  nsTArray<nsCOMPtr<nsIDOMFile> > mFileList;
+  nsTArray<nsRefPtr<File>> mFileList;
 
   // We access the list length on both threads, so we need the indirection of
   // this atomic member to make the access thread safe:
   mozilla::Atomic<uint32_t> mFileListLength;
 
   mozilla::Atomic<bool> mCanceled;
 };
 
@@ -615,17 +623,17 @@ HTMLInputElement::nsFilePickerShownCallb
 
   mInput->CancelDirectoryPickerScanIfRunning();
 
   int16_t mode;
   mFilePicker->GetMode(&mode);
 
   if (mode == static_cast<int16_t>(nsIFilePicker::modeGetFolder)) {
     // Directory picking is different, since we still need to do more I/O to
-    // build up the list of nsDOMFileFile objects. Since this may block for a
+    // build up the list of File objects. Since this may block for a
     // long time, we need to build the list off on another dedicated thread to
     // avoid blocking any other activities that the browser is carrying out.
 
     // The user selected this directory, so we always save this dir, even if
     // no files are found under it.
     nsCOMPtr<nsIFile> pickedDir;
     mFilePicker->GetFile(getter_AddRefs(pickedDir));
 
@@ -650,42 +658,42 @@ HTMLInputElement::nsFilePickerShownCallb
     // dispatching the "change" event.
     mInput->mDirPickerFileListBuilderTask =
       new DirPickerFileListBuilderTask(mInput.get(), pickedDir.get());
     return target->Dispatch(mInput->mDirPickerFileListBuilderTask,
                             NS_DISPATCH_NORMAL);
   }
 
   // Collect new selected filenames
-  nsTArray<nsCOMPtr<nsIDOMFile> > newFiles;
+  nsTArray<nsRefPtr<File>> newFiles;
   if (mode == static_cast<int16_t>(nsIFilePicker::modeOpenMultiple)) {
     nsCOMPtr<nsISimpleEnumerator> iter;
     nsresult rv = mFilePicker->GetDomfiles(getter_AddRefs(iter));
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!iter) {
       return NS_OK;
     }
 
     nsCOMPtr<nsISupports> tmp;
     bool hasMore = true;
 
     while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
       iter->GetNext(getter_AddRefs(tmp));
       nsCOMPtr<nsIDOMFile> domFile = do_QueryInterface(tmp);
       MOZ_ASSERT(domFile);
-      newFiles.AppendElement(domFile);
+      newFiles.AppendElement(static_cast<File*>(domFile.get()));
     }
   } else {
     MOZ_ASSERT(mode == static_cast<int16_t>(nsIFilePicker::modeOpen));
     nsCOMPtr<nsIDOMFile> domFile;
     nsresult rv = mFilePicker->GetDomfile(getter_AddRefs(domFile));
     NS_ENSURE_SUCCESS(rv, rv);
     if (domFile) {
-      newFiles.AppendElement(domFile);
+      newFiles.AppendElement(static_cast<File*>(domFile.get()));
     }
   }
 
   if (newFiles.IsEmpty()) {
     return NS_OK;
   }
 
   // Store the last used directory using the content pref service:
@@ -931,17 +939,17 @@ HTMLInputElement::InitFilePicker(FilePic
     SetFilePickerFiltersFromAccept(filePicker);
   } else {
     filePicker->AppendFilters(nsIFilePicker::filterAll);
   }
 
   // Set default directry and filename
   nsAutoString defaultName;
 
-  const nsTArray<nsCOMPtr<nsIDOMFile> >& oldFiles = GetFilesInternal();
+  const nsTArray<nsRefPtr<File>>& oldFiles = GetFilesInternal();
 
   nsCOMPtr<nsIFilePickerShownCallback> callback =
     new HTMLInputElement::nsFilePickerShownCallback(this, filePicker);
 
   if (!oldFiles.IsEmpty() &&
       aType != FILE_PICKER_DIRECTORY) {
     nsString path;
 
@@ -1711,17 +1719,17 @@ HTMLInputElement::IsValueEmpty() const
   GetValueInternal(value);
 
   return value.IsEmpty();
 }
 
 void
 HTMLInputElement::ClearFiles(bool aSetValueChanged)
 {
-  nsTArray<nsCOMPtr<nsIDOMFile> > files;
+  nsTArray<nsRefPtr<File>> files;
   SetFiles(files, aSetValueChanged);
 }
 
 /* static */ Decimal
 HTMLInputElement::StringToDecimal(const nsAString& aValue)
 {
   if (!IsASCII(aValue)) {
     return Decimal::nan();
@@ -2305,17 +2313,17 @@ HTMLInputElement::MozGetFileNameArray(ui
   *aFileNames = ret;
 
   return NS_OK;
 }
 
 void
 HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames)
 {
-  nsTArray<nsCOMPtr<nsIDOMFile> > files;
+  nsTArray<nsRefPtr<File>> files;
   for (uint32_t i = 0; i < aFileNames.Length(); ++i) {
     nsCOMPtr<nsIFile> file;
 
     if (StringBeginsWith(aFileNames[i], NS_LITERAL_STRING("file:"),
                          nsASCIICaseInsensitiveStringComparator())) {
       // Converts the URL string into the corresponding nsIFile if possible
       // A local file will be created if the URL string begins with file://
       NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(aFileNames[i]),
@@ -2323,17 +2331,18 @@ HTMLInputElement::MozSetFileNameArray(co
     }
 
     if (!file) {
       // this is no "file://", try as local file
       NS_NewLocalFile(aFileNames[i], false, getter_AddRefs(file));
     }
 
     if (file) {
-      nsCOMPtr<nsIDOMFile> domFile = DOMFile::CreateFromFile(file);
+      nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
+      nsRefPtr<File> domFile = File::CreateFromFile(global, file);
       files.AppendElement(domFile);
     } else {
       continue; // Not much we can do if the file doesn't exist
     }
 
   }
 
   SetFiles(files, true);
@@ -2559,37 +2568,37 @@ HTMLInputElement::GetDisplayFileName(nsA
     nsContentUtils::FormatLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
                                           "XFilesSelected", params, value);
   }
 
   aValue = value;
 }
 
 void
-HTMLInputElement::SetFiles(const nsTArray<nsCOMPtr<nsIDOMFile> >& aFiles,
+HTMLInputElement::SetFiles(const nsTArray<nsRefPtr<File>>& aFiles,
                            bool aSetValueChanged)
 {
   mFiles.Clear();
   mFiles.AppendElements(aFiles);
 
   AfterSetFiles(aSetValueChanged);
 }
 
 void
 HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
                            bool aSetValueChanged)
 {
+  nsRefPtr<FileList> files = static_cast<FileList*>(aFiles);
   mFiles.Clear();
 
   if (aFiles) {
     uint32_t listLength;
     aFiles->GetLength(&listLength);
     for (uint32_t i = 0; i < listLength; i++) {
-      nsCOMPtr<nsIDOMFile> file;
-      aFiles->Item(i, getter_AddRefs(file));
+      nsRefPtr<File> file = files->Item(i);
       mFiles.AppendElement(file);
     }
   }
 
   AfterSetFiles(aSetValueChanged);
 }
 
 void
@@ -2627,25 +2636,25 @@ HTMLInputElement::FireChangeEventIfNeede
   // Dispatch the change event.
   mFocusedValue = value;
   nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
                                        static_cast<nsIContent*>(this),
                                        NS_LITERAL_STRING("change"), true,
                                        false);
 }
 
-nsDOMFileList*
+FileList*
 HTMLInputElement::GetFiles()
 {
   if (mType != NS_FORM_INPUT_FILE) {
     return nullptr;
   }
 
   if (!mFileList) {
-    mFileList = new nsDOMFileList(static_cast<nsIContent*>(this));
+    mFileList = new FileList(static_cast<nsIContent*>(this));
     UpdateFileList();
   }
 
   return mFileList;
 }
 
 void
 HTMLInputElement::OpenDirectoryPicker(ErrorResult& aRv)
@@ -2779,17 +2788,17 @@ HTMLInputElement::DispatchProgressEvent(
 }
 
 nsresult
 HTMLInputElement::UpdateFileList()
 {
   if (mFileList) {
     mFileList->Clear();
 
-    const nsTArray<nsCOMPtr<nsIDOMFile> >& files = GetFilesInternal();
+    const nsTArray<nsRefPtr<File>>& files = GetFilesInternal();
     for (uint32_t i = 0; i < files.Length(); ++i) {
       if (!mFileList->Append(files[i])) {
         return NS_ERROR_FAILURE;
       }
     }
   }
 
   return NS_OK;
@@ -5362,17 +5371,17 @@ HTMLInputElement::SetSelectionEnd(int32_
   ErrorResult rv;
   SetSelectionEnd(aSelectionEnd, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLInputElement::GetFiles(nsIDOMFileList** aFileList)
 {
-  nsRefPtr<nsDOMFileList> list = GetFiles();
+  nsRefPtr<FileList> list = GetFiles();
   list.forget(aFileList);
   return NS_OK;
 }
 
 nsresult
 HTMLInputElement::GetSelectionRange(int32_t* aSelectionStart,
                                     int32_t* aSelectionEnd)
 {
@@ -5629,17 +5638,17 @@ HTMLInputElement::SubmitNamesValues(nsFo
   }
 
   //
   // Submit file if its input type=file and this encoding method accepts files
   //
   if (mType == NS_FORM_INPUT_FILE) {
     // Submit files
 
-    const nsTArray<nsCOMPtr<nsIDOMFile> >& files = GetFilesInternal();
+    const nsTArray<nsRefPtr<File>>& files = GetFilesInternal();
 
     for (uint32_t i = 0; i < files.Length(); ++i) {
       aFormSubmission->AddNameFilePair(name, files[i], NullString());
     }
 
     if (files.IsEmpty()) {
       // If no file was selected, pretend we had an empty file with an
       // empty filename.
@@ -5877,17 +5886,17 @@ HTMLInputElement::RestoreState(nsPresSta
       case VALUE_MODE_DEFAULT_ON:
         if (inputState->IsCheckedSet()) {
           restoredCheckedState = true;
           DoSetChecked(inputState->GetChecked(), true, true);
         }
         break;
       case VALUE_MODE_FILENAME:
         {
-          const nsTArray<nsCOMPtr<nsIDOMFile> >& files = inputState->GetFiles();
+          const nsTArray<nsRefPtr<File>>& files = inputState->GetFiles();
           SetFiles(files, true);
         }
         break;
       case VALUE_MODE_VALUE:
       case VALUE_MODE_DEFAULT:
         if (GetValueMode() == VALUE_MODE_DEFAULT &&
             mType != NS_FORM_INPUT_HIDDEN) {
           break;
@@ -6387,17 +6396,17 @@ HTMLInputElement::IsValueMissing() const
     return false;
   }
 
   switch (GetValueMode()) {
     case VALUE_MODE_VALUE:
       return IsValueEmpty();
     case VALUE_MODE_FILENAME:
     {
-      const nsTArray<nsCOMPtr<nsIDOMFile> >& files = GetFilesInternal();
+      const nsTArray<nsRefPtr<File>>& files = GetFilesInternal();
       return files.IsEmpty();
     }
     case VALUE_MODE_DEFAULT_ON:
       // This should not be used for type radio.
       // See the MOZ_ASSERT at the beginning of the method.
       return !mChecked;
     case VALUE_MODE_DEFAULT:
     default:
--- a/content/html/content/src/HTMLInputElement.h
+++ b/content/html/content/src/HTMLInputElement.h
@@ -19,30 +19,31 @@
 #include "mozilla/dom/HTMLFormElement.h" // for HasEverTriedInvalidSubmit()
 #include "mozilla/dom/HTMLInputElementBinding.h"
 #include "nsIFilePicker.h"
 #include "nsIContentPrefService2.h"
 #include "mozilla/Decimal.h"
 #include "nsContentUtils.h"
 #include "nsTextEditorState.h"
 
-class nsDOMFileList;
 class nsIRadioGroupContainer;
 class nsIRadioGroupVisitor;
 class nsIRadioVisitor;
 
 namespace mozilla {
 
 class EventChainPostVisitor;
 class EventChainPreVisitor;
 
 namespace dom {
 
 class Date;
 class DirPickerFileListBuilderTask;
+class File;
+class FileList;
 
 class UploadLastDir MOZ_FINAL : public nsIObserver, public nsSupportsWeakReference {
 
   ~UploadLastDir() {}
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
@@ -205,22 +206,22 @@ public:
   NS_IMETHOD_(void) UpdatePlaceholderVisibility(bool aNotify) MOZ_OVERRIDE;
   NS_IMETHOD_(bool) GetPlaceholderVisibility() MOZ_OVERRIDE;
   NS_IMETHOD_(void) InitializeKeyboardEventListeners() MOZ_OVERRIDE;
   NS_IMETHOD_(void) OnValueChanged(bool aNotify) MOZ_OVERRIDE;
   NS_IMETHOD_(bool) HasCachedSelection() MOZ_OVERRIDE;
 
   void GetDisplayFileName(nsAString& aFileName) const;
 
-  const nsTArray<nsCOMPtr<nsIDOMFile> >& GetFilesInternal() const
+  const nsTArray<nsRefPtr<File>>& GetFilesInternal() const
   {
     return mFiles;
   }
 
-  void SetFiles(const nsTArray<nsCOMPtr<nsIDOMFile> >& aFiles, bool aSetValueChanged);
+  void SetFiles(const nsTArray<nsRefPtr<File>>& aFiles, bool aSetValueChanged);
   void SetFiles(nsIDOMFileList* aFiles, bool aSetValueChanged);
 
   // Called when a nsIFilePicker or a nsIColorPicker terminate.
   void PickerClosed();
 
   void SetCheckedChangedInternal(bool aCheckedChanged);
   bool GetCheckedChanged() const {
     return mCheckedChanged;
@@ -427,17 +428,17 @@ public:
 
   void SetDisabled(bool aValue,ErrorResult& aRv)
   {
     SetHTMLBoolAttr(nsGkAtoms::disabled, aValue, aRv);
   }
 
   // XPCOM GetForm() is OK
 
-  nsDOMFileList* GetFiles();
+  FileList* GetFiles();
 
   void OpenDirectoryPicker(ErrorResult& aRv);
   void CancelDirectoryPickerScanIfRunning();
 
   void StartProgressEventTimer();
   void MaybeDispatchProgressEvent(bool aFinalProgress);
   void DispatchProgressEvent(const nsAString& aType,
                              bool aLengthComputable,
@@ -1246,19 +1247,19 @@ protected:
    * used when uploading a file. It is vital that this is kept separate from
    * mValue so that it won't be possible to 'leak' the value from a text-input
    * to a file-input. Additionally, the logic for this value is kept as simple
    * as possible to avoid accidental errors where the wrong filename is used.
    * Therefor the list of filenames is always owned by this member, never by
    * the frame. Whenever the frame wants to change the filename it has to call
    * SetFileNames to update this member.
    */
-  nsTArray<nsCOMPtr<nsIDOMFile> >   mFiles;
+  nsTArray<nsRefPtr<File>> mFiles;
 
-  nsRefPtr<nsDOMFileList>  mFileList;
+  nsRefPtr<FileList>  mFileList;
 
   nsRefPtr<DirPickerFileListBuilderTask> mDirPickerFileListBuilderTask;
 
   nsString mStaticDocFileList;
   
   /** 
    * The value of the input element when first initialized and it is updated
    * when the element is either changed through a script, focused or dispatches   
--- a/content/html/content/test/test_formData.html
+++ b/content/html/content/test/test_formData.html
@@ -47,22 +47,22 @@ function runTest() {
     }
 
     var file, blob = new Blob(['hey'], {type: 'text/plain'});
 
     var fd = new FormData();
     fd.append("empty", blob);
     fd.append("explicit", blob, "explicit-file-name");
     fd.append("explicit-empty", blob, "");
-    file = SpecialPowers.unwrap(SpecialPowers.wrap(window).File(blob, {name: 'testname'}));
+    file = new File([blob], 'testname',  {type: 'text/plain'});
     fd.append("file-name", file);
-    file = SpecialPowers.unwrap(SpecialPowers.wrap(window).File(blob, {name: ''}));
+    file = new File([blob], '',  {type: 'text/plain'});
     fd.append("empty-file-name", file);
-    file = SpecialPowers.unwrap(SpecialPowers.wrap(window).File(blob, {name: 'testname'}));
+    file = new File([blob], 'testname',  {type: 'text/plain'});
     fd.append("file-name-overwrite", file, "overwrite");
     xhr.responseType = 'json';
     xhr.send(fd);
 }
 
 runTest()
 </script>
 </body>
-</html>
\ No newline at end of file
+</html>
--- a/content/media/EncodedBufferCache.cpp
+++ b/content/media/EncodedBufferCache.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "EncodedBufferCache.h"
+#include "mozilla/dom/File.h"
 #include "nsAnonymousTemporaryFile.h"
-#include "nsDOMFile.h"
 #include "prio.h"
 
 namespace mozilla {
 
 void
 EncodedBufferCache::AppendBuffer(nsTArray<uint8_t> & aBuf)
 {
   MutexAutoLock lock(mMutex);
@@ -34,40 +34,42 @@ EncodedBufferCache::AppendBuffer(nsTArra
         NS_WARNING("Failed to write media cache block!");
       }
     }
     mEncodedBuffers.Clear();
   }
 
 }
 
-already_AddRefed<nsIDOMBlob>
-EncodedBufferCache::ExtractBlob(const nsAString &aContentType)
+already_AddRefed<dom::File>
+EncodedBufferCache::ExtractBlob(nsISupports* aParent,
+                                const nsAString &aContentType)
 {
   MutexAutoLock lock(mMutex);
-  nsCOMPtr<nsIDOMBlob> blob;
+  nsRefPtr<dom::File> blob;
   if (mTempFileEnabled) {
     // generate new temporary file to write
-    blob = dom::DOMFile::CreateTemporaryFileBlob(mFD, 0, mDataSize,
-                                                 aContentType);
+    blob = dom::File::CreateTemporaryFileBlob(aParent, mFD, 0, mDataSize,
+                                              aContentType);
     // fallback to memory blob
     mTempFileEnabled = false;
     mDataSize = 0;
     mFD = nullptr;
   } else {
     void* blobData = moz_malloc(mDataSize);
     NS_ASSERTION(blobData, "out of memory!!");
 
     if (blobData) {
       for (uint32_t i = 0, offset = 0; i < mEncodedBuffers.Length(); i++) {
         memcpy((uint8_t*)blobData + offset, mEncodedBuffers.ElementAt(i).Elements(),
                mEncodedBuffers.ElementAt(i).Length());
         offset += mEncodedBuffers.ElementAt(i).Length();
       }
-      blob = dom::DOMFile::CreateMemoryFile(blobData, mDataSize, aContentType);
+      blob = dom::File::CreateMemoryFile(aParent, blobData, mDataSize,
+                                         aContentType);
       mEncodedBuffers.Clear();
     } else
       return nullptr;
   }
   mDataSize = 0;
   return blob.forget();
 }
 
--- a/content/media/EncodedBufferCache.h
+++ b/content/media/EncodedBufferCache.h
@@ -11,16 +11,20 @@
 #include "nsTArray.h"
 #include "mozilla/Mutex.h"
 
 struct PRFileDesc;
 class nsIDOMBlob;
 
 namespace mozilla {
 
+namespace dom {
+class File;
+}
+
 class ReentrantMonitor;
 /**
  * Data is moved into a temporary file when it grows beyond
  * the maximal size passed in the Init function.
  * The AppendBuffer and ExtractBlob methods are thread-safe and can be called on
  * different threads at the same time.
  */
 class EncodedBufferCache
@@ -34,17 +38,17 @@ public:
     mTempFileEnabled(false) { }
   ~EncodedBufferCache()
   {
   }
   // Append buffers in cache, check if the queue is too large then switch to write buffer to file system
   // aBuf will append to mEncodedBuffers or temporary File, aBuf also be cleared
   void AppendBuffer(nsTArray<uint8_t> & aBuf);
   // Read all buffer from memory or file System, also Remove the temporary file or clean the buffers in memory.
-  already_AddRefed<nsIDOMBlob> ExtractBlob(const nsAString &aContentType);
+  already_AddRefed<dom::File> ExtractBlob(nsISupports* aParent, const nsAString &aContentType);
 
 private:
   //array for storing the encoded data.
   nsTArray<nsTArray<uint8_t> > mEncodedBuffers;
   // File handle for the temporary file
   PRFileDesc* mFD;
   // Used to protect the mEncodedBuffer for avoiding AppendBuffer/Consume on different thread at the same time.
   Mutex mMutex;
--- a/content/media/Latency.cpp
+++ b/content/media/Latency.cpp
@@ -1,17 +1,14 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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/. */
 
-// We want this available in opt builds
-#define FORCE_PR_LOG
-
 #include "Latency.h"
 #include "nsThreadUtils.h"
 #include "prlog.h"
 #include <cmath>
 #include <algorithm>
 
 #include <mozilla/Services.h>
 #include <mozilla/StaticPtr.h>
--- a/content/media/MediaRecorder.cpp
+++ b/content/media/MediaRecorder.cpp
@@ -10,21 +10,21 @@
 #include "DOMMediaStream.h"
 #include "EncodedBufferCache.h"
 #include "MediaEncoder.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/AudioStreamTrack.h"
 #include "mozilla/dom/BlobEvent.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/RecordErrorEvent.h"
 #include "mozilla/dom/VideoStreamTrack.h"
 #include "nsError.h"
 #include "nsIDocument.h"
-#include "nsIDOMFile.h"
 #include "nsIPrincipal.h"
 #include "nsMimeTypes.h"
 #include "nsProxyRelease.h"
 #include "nsTArray.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gMediaRecorderLog;
 #define LOG(type, msg) PR_LOG(gMediaRecorderLog, type, msg)
@@ -384,17 +384,18 @@ public:
     mTrackUnionStream->ChangeExplicitBlockerCount(-1);
 
     return NS_OK;
   }
 
   already_AddRefed<nsIDOMBlob> GetEncodedData()
   {
     MOZ_ASSERT(NS_IsMainThread());
-    return mEncodedBufferCache->ExtractBlob(mMimeType);
+    return mEncodedBufferCache->ExtractBlob(mRecorder->GetParentObject(),
+                                            mMimeType);
   }
 
   bool IsEncoderError()
   {
     if (mEncoder && mEncoder->HasError()) {
       return true;
     }
     return false;
@@ -915,17 +916,20 @@ MediaRecorder::CreateAndDispatchBlobEven
   if (!CheckPrincipal()) {
     // Media is not same-origin, don't allow the data out.
     nsRefPtr<nsIDOMBlob> blob = aBlob;
     return NS_ERROR_DOM_SECURITY_ERR;
   }
   BlobEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
-  init.mData = aBlob;
+
+  nsCOMPtr<nsIDOMBlob> blob = aBlob;
+  init.mData = static_cast<File*>(blob.get());
+
   nsRefPtr<BlobEvent> event =
     BlobEvent::Constructor(this,
                            NS_LITERAL_STRING("dataavailable"),
                            init);
   event->SetTrusted(true);
   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
--- a/content/media/fmp4/MP4Reader.cpp
+++ b/content/media/fmp4/MP4Reader.cpp
@@ -305,17 +305,19 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
     bool ok = mDemuxer->Init();
     NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 
     {
       MonitorAutoLock mon(mIndexMonitor);
       mIndexReady = true;
     }
 
-    mInfo.mVideo.mHasVideo = mVideo.mActive = mDemuxer->HasValidVideo();
+    // To decode, we need valid video and a place to put it.
+    mInfo.mVideo.mHasVideo = mVideo.mActive = mDemuxer->HasValidVideo() &&
+                                              mDecoder->GetImageContainer();
     const VideoDecoderConfig& video = mDemuxer->VideoConfig();
     // If we have video, we *only* allow H.264 to be decoded.
     if (mInfo.mVideo.mHasVideo && strcmp(video.mime_type, "video/avc")) {
       return NS_ERROR_FAILURE;
     }
 
     mInfo.mAudio.mHasAudio = mAudio.mActive = mDemuxer->HasValidAudio();
 
--- a/content/media/imagecapture/CaptureTask.cpp
+++ b/content/media/imagecapture/CaptureTask.cpp
@@ -10,24 +10,30 @@
 #include "mozilla/dom/ImageEncoder.h"
 #include "mozilla/dom/VideoStreamTrack.h"
 #include "gfxUtils.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 
 nsresult
-CaptureTask::TaskComplete(already_AddRefed<dom::DOMFile> aBlob, nsresult aRv)
+CaptureTask::TaskComplete(already_AddRefed<dom::File> aBlob, nsresult aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   DetachStream();
 
   nsresult rv;
-  nsRefPtr<dom::DOMFile> blob(aBlob);
+  nsRefPtr<dom::File> blob(aBlob);
+
+  // We have to set the parent because the blob has been generated with a valid one.
+  if (blob) {
+    blob = new dom::File(mImageCapture->GetParentObject(), blob->Impl());
+  }
+
   if (mPrincipalChanged) {
     aRv = NS_ERROR_DOM_SECURITY_ERR;
     IC_LOG("MediaStream principal should not change during TakePhoto().");
   }
 
   if (NS_SUCCEEDED(aRv)) {
     rv = mImageCapture->PostBlobEvent(blob);
   } else {
@@ -93,19 +99,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::DOMFile> aBlob) MOZ_OVERRIDE
+    nsresult ReceiveBlob(already_AddRefed<dom::File> aBlob) MOZ_OVERRIDE
     {
-      nsRefPtr<dom::DOMFile> blob(aBlob);
+      nsRefPtr<dom::File> blob(aBlob);
       mTask->TaskComplete(blob.forget(), NS_OK);
       mTask = nullptr;
       return NS_OK;
     }
 
   protected:
     nsRefPtr<CaptureTask> mTask;
   };
--- a/content/media/imagecapture/CaptureTask.h
+++ b/content/media/imagecapture/CaptureTask.h
@@ -8,18 +8,18 @@
 #define CAPTURETASK_H
 
 #include "DOMMediaStream.h"
 #include "MediaStreamGraph.h"
 
 namespace mozilla {
 
 namespace dom {
+class File;
 class ImageCapture;
-class DOMFile;
 }
 
 /**
  * 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
  * blob will be sent out via encoder callback in main thread.
@@ -46,17 +46,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::DOMFile> aBlob, nsresult aRv);
+  nsresult TaskComplete(already_AddRefed<dom::File> aBlob, nsresult aRv);
 
   // Add listeners into MediaStream and PrincipalChangeObserver. It should be on
   // main thread only.
   void AttachStream();
 
   // Remove listeners from MediaStream and PrincipalChangeObserver. It should be
   // on main thread only.
   void DetachStream();
--- a/content/media/imagecapture/ImageCapture.cpp
+++ b/content/media/imagecapture/ImageCapture.cpp
@@ -2,21 +2,21 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "ImageCapture.h"
 #include "mozilla/dom/BlobEvent.h"
 #include "mozilla/dom/DOMException.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/ImageCaptureError.h"
 #include "mozilla/dom/ImageCaptureErrorEvent.h"
 #include "mozilla/dom/ImageCaptureErrorEventBinding.h"
 #include "mozilla/dom/VideoStreamTrack.h"
-#include "nsDOMFile.h"
 #include "nsIDocument.h"
 #include "CaptureTask.h"
 #include "MediaEngine.h"
 
 namespace mozilla {
 
 #ifdef PR_LOGGING
 
@@ -97,19 +97,19 @@ ImageCapture::TakePhotoByMediaEngine()
       mStream->AddPrincipalChangeObserver(this);
     }
 
     void PrincipalChanged(DOMMediaStream* aMediaStream) MOZ_OVERRIDE
     {
       mPrincipalChanged = true;
     }
 
-    nsresult PhotoComplete(already_AddRefed<DOMFile> aBlob) MOZ_OVERRIDE
+    nsresult PhotoComplete(already_AddRefed<File> aBlob) MOZ_OVERRIDE
     {
-      nsRefPtr<DOMFile> blob = aBlob;
+      nsRefPtr<File> blob = aBlob;
 
       if (mPrincipalChanged) {
         return PhotoError(NS_ERROR_DOM_SECURITY_ERR);
       }
       return mImageCapture->PostBlobEvent(blob);
     }
 
     nsresult PhotoError(nsresult aRv) MOZ_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(nsIDOMBlob* aBlob)
+ImageCapture::PostBlobEvent(File* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!CheckPrincipal()) {
     // Media is not same-origin, don't allow the data out.
     return PostErrorEvent(ImageCaptureError::PHOTO_ERROR, NS_ERROR_DOM_SECURITY_ERR);
   }
 
   BlobEventInit init;
--- a/content/media/imagecapture/ImageCapture.h
+++ b/content/media/imagecapture/ImageCapture.h
@@ -27,16 +27,17 @@ PRLogModuleInfo* GetICLog();
 #ifndef IC_LOG
 #define IC_LOG(...)
 #endif
 
 #endif // PR_LOGGING
 
 namespace dom {
 
+class File;
 class VideoStreamTrack;
 
 /**
  *  Implementation of https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-
  *  capture/ImageCapture.html.
  *  The ImageCapture accepts a VideoStreamTrack as input source. The image will
  *  be sent back as a JPG format via Blob event.
  *
@@ -74,17 +75,17 @@ public:
 
   static already_AddRefed<ImageCapture> Constructor(const GlobalObject& aGlobal,
                                                     VideoStreamTrack& aTrack,
                                                     ErrorResult& aRv);
 
   ImageCapture(VideoStreamTrack* aVideoStreamTrack, nsPIDOMWindow* aOwnerWindow);
 
   // Post a Blob event to script.
-  nsresult PostBlobEvent(nsIDOMBlob* aBlob);
+  nsresult PostBlobEvent(File* aBlob);
 
   // Post an error event to script.
   // aErrorCode should be one of error codes defined in ImageCaptureError.h.
   // aReason is the nsresult which maps to a error string in dom/base/domerr.msg.
   nsresult PostErrorEvent(uint16_t aErrorCode, nsresult aReason = NS_OK);
 
   bool CheckPrincipal();
 
--- a/content/media/moz.build
+++ b/content/media/moz.build
@@ -135,16 +135,17 @@ UNIFIED_SOURCES += [
     'AudioStreamTrack.cpp',
     'AudioTrack.cpp',
     'AudioTrackList.cpp',
     'CubebUtils.cpp',
     'DOMMediaStream.cpp',
     'EncodedBufferCache.cpp',
     'FileBlockCache.cpp',
     "GraphDriver.cpp",
+    'Latency.cpp',
     'MediaCache.cpp',
     'MediaData.cpp',
     'MediaDecoder.cpp',
     'MediaDecoderReader.cpp',
     'MediaDecoderStateMachine.cpp',
     'MediaDecoderStateMachineScheduler.cpp',
     'MediaRecorder.cpp',
     'MediaResource.cpp',
@@ -172,20 +173,18 @@ UNIFIED_SOURCES += [
     'VideoUtils.cpp',
     'WebVTTListener.cpp',
 ]
 
 if CONFIG['OS_TARGET'] == 'WINNT':
   SOURCES += [ 'ThreadPoolCOMListener.cpp' ]
 
 # DecoderTraits.cpp needs to be built separately because of Mac OS X headers.
-# Latency.cpp needs to be built separately because it forces NSPR logging.
 SOURCES += [
     'DecoderTraits.cpp',
-    'Latency.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/content/media/webrtc/MediaEngine.h
+++ b/content/media/webrtc/MediaEngine.h
@@ -10,17 +10,17 @@
 #include "DOMMediaStream.h"
 #include "MediaStreamGraph.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/dom/VideoStreamTrack.h"
 
 namespace mozilla {
 
 namespace dom {
-class DOMFile;
+class File;
 }
 
 struct VideoTrackConstraintsN;
 struct AudioTrackConstraintsN;
 
 /**
  * Abstract interface for managing audio and video devices. Each platform
  * must implement a concrete class that will map these classes and methods
@@ -145,17 +145,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::DOMFile> aBlob) = 0;
+    virtual nsresult PhotoComplete(already_AddRefed<dom::File> aBlob) = 0;
 
     // It is called on main thread. aRv is the error code.
     virtual nsresult PhotoError(nsresult aRv) = 0;
 
   protected:
     virtual ~PhotoCallback() {}
   };
 
--- a/content/media/webrtc/MediaEngineDefault.cpp
+++ b/content/media/webrtc/MediaEngineDefault.cpp
@@ -1,16 +1,16 @@
 /* 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 "MediaEngineDefault.h"
 
 #include "nsCOMPtr.h"
-#include "nsDOMFile.h"
+#include "mozilla/dom/File.h"
 #include "nsILocalFile.h"
 #include "Layers.h"
 #include "ImageContainer.h"
 #include "ImageTypes.h"
 #include "prmem.h"
 #include "nsContentUtils.h"
 
 #include "nsIFilePicker.h"
@@ -203,17 +203,17 @@ MediaEngineDefaultVideoSource::Snapshot(
   nsCOMPtr<nsIFile> localFile;
   filePicker->GetFile(getter_AddRefs(localFile));
 
   if (!localFile) {
     *aFile = nullptr;
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMFile> domFile = dom::DOMFile::CreateFromFile(localFile);
+  nsCOMPtr<nsIDOMFile> domFile = dom::File::CreateFromFile(nullptr, localFile);
   domFile.forget(aFile);
   return NS_OK;
 #endif
 }
 
 NS_IMETHODIMP
 MediaEngineDefaultVideoSource::Notify(nsITimer* aTimer)
 {
--- a/content/media/webrtc/MediaEngineWebRTC.cpp
+++ b/content/media/webrtc/MediaEngineWebRTC.cpp
@@ -1,20 +1,12 @@
 /* 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/. */
 
-#ifdef MOZ_LOGGING
-#define FORCE_PR_LOG
-#endif
-
-#if defined(PR_LOG)
-#error "This file must be #included before any IPDL-generated files or other files that #include prlog.h"
-#endif
-
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 
 #include "CSFLog.h"
 #include "prenv.h"
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo*
--- a/content/media/webrtc/MediaEngineWebRTC.h
+++ b/content/media/webrtc/MediaEngineWebRTC.h
@@ -5,20 +5,20 @@
 #ifndef MEDIAENGINEWEBRTC_H_
 #define MEDIAENGINEWEBRTC_H_
 
 #include "prcvar.h"
 #include "prthread.h"
 #include "nsIThread.h"
 #include "nsIRunnable.h"
 
+#include "mozilla/dom/File.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Monitor.h"
 #include "nsCOMPtr.h"
-#include "nsDOMFile.h"
 #include "nsThreadUtils.h"
 #include "DOMMediaStream.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsComponentManagerUtils.h"
 #include "nsRefPtrHashtable.h"
 
 #include "VideoUtils.h"
 #include "MediaEngine.h"
--- a/content/media/webrtc/MediaEngineWebRTCVideo.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCVideo.cpp
@@ -938,21 +938,21 @@ MediaEngineWebRTCVideoSource::OnTakePict
     {
       mCallbacks.SwapElements(aCallbacks);
       mPhoto.AppendElements(aData, aLength);
       mMimeType = aMimeType;
     }
 
     NS_IMETHOD Run()
     {
-      nsRefPtr<dom::DOMFile> blob =
-        dom::DOMFile::CreateMemoryFile(mPhoto.Elements(), mPhoto.Length(), mMimeType);
+      nsRefPtr<dom::File> blob =
+        dom::File::CreateMemoryFile(nullptr, mPhoto.Elements(), mPhoto.Length(), mMimeType);
       uint32_t callbackCounts = mCallbacks.Length();
       for (uint8_t i = 0; i < callbackCounts; i++) {
-        nsRefPtr<dom::DOMFile> tempBlob = blob;
+        nsRefPtr<dom::File> tempBlob = blob;
         mCallbacks[i]->PhotoComplete(tempBlob.forget());
       }
       // PhotoCallback needs to dereference on main thread.
       mCallbacks.Clear();
       return NS_OK;
     }
 
     nsTArray<nsRefPtr<PhotoCallback>> mCallbacks;
--- a/docshell/base/moz.build
+++ b/docshell/base/moz.build
@@ -48,31 +48,27 @@ EXPORTS.mozilla += [
     'LoadInfo.h',
 ]
 
 UNIFIED_SOURCES += [
     'LoadContext.cpp',
     'LoadInfo.cpp',
     'nsAboutRedirector.cpp',
     'nsDefaultURIFixup.cpp',
+    'nsDocShell.cpp',
     'nsDocShellEditorData.cpp',
     'nsDocShellEnumerator.cpp',
     'nsDocShellLoadInfo.cpp',
     'nsDocShellTransferableHooks.cpp',
     'nsDownloadHistory.cpp',
     'nsDSURIContentListener.cpp',
     'nsWebNavigationInfo.cpp',
     'SerializedLoadContext.cpp',
 ]
 
-# nsDocShell.cpp cannot be built in unified mode because it forces NSPR logging.
-SOURCES += [
-    'nsDocShell.cpp',
-]
-
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -21,21 +21,16 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/StartupTimeline.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/unused.h"
 #include "mozilla/VisualEventTracer.h"
 #include "URIUtils.h"
 
-#ifdef MOZ_LOGGING
-// so we can get logging even in release builds (but only for some things)
-#define FORCE_PR_LOG 1
-#endif
-
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMStorage.h"
 #include "nsIContentViewer.h"
 #include "nsIDocumentLoaderFactory.h"
--- a/dom/archivereader/ArchiveEvent.cpp
+++ b/dom/archivereader/ArchiveEvent.cpp
@@ -125,17 +125,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 nsDOMFile:
+      // This is a File:
       nsRefPtr<nsIDOMFile> file = item->File(mArchiveReader);
       if (file) {
         fileList.AppendElement(file);
       }
     }
   }
 
   mArchiveReader->Ready(fileList, mStatus);
--- a/dom/archivereader/ArchiveEvent.h
+++ b/dom/archivereader/ArchiveEvent.h
@@ -4,19 +4,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_archivereader_domarchiveevent_h__
 #define mozilla_dom_archivereader_domarchiveevent_h__
 
 #include "ArchiveReader.h"
 
+#include "mozilla/dom/File.h"
 #include "nsISeekableStream.h"
 #include "nsIMIMEService.h"
-#include "nsDOMFile.h"
 
 #include "ArchiveReaderCommon.h"
 
 BEGIN_ARCHIVEREADER_NAMESPACE
 
 /**
  * This class contains all the info needed for a single item
  * It must contain the implementation of the File() method.
@@ -30,17 +30,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 DOMFile
+  // Generate a File
   virtual nsIDOMFile* File(ArchiveReader* aArchiveReader) = 0;
 
 protected:
   virtual ~ArchiveItem();
 
   nsCString mType;
 };
 
--- a/dom/archivereader/ArchiveReader.cpp
+++ b/dom/archivereader/ArchiveReader.cpp
@@ -9,31 +9,30 @@
 #include "ArchiveEvent.h"
 #include "ArchiveZipEvent.h"
 
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 
 #include "mozilla/dom/ArchiveReaderBinding.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/File.h"
+#include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/dom/EncodingUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 USING_ARCHIVEREADER_NAMESPACE
 
 /* static */ already_AddRefed<ArchiveReader>
 ArchiveReader::Constructor(const GlobalObject& aGlobal,
-                           nsIDOMBlob* aBlob,
+                           File& aBlob,
                            const ArchiveReaderOptions& aOptions,
                            ErrorResult& aError)
 {
-  MOZ_ASSERT(aBlob);
-
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aError.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsAutoCString encoding;
   if (!EncodingUtils::FindEncodingForLabelNoReplacement(aOptions.mEncoding,
@@ -42,24 +41,23 @@ ArchiveReader::Constructor(const GlobalO
     return nullptr;
   }
 
   nsRefPtr<ArchiveReader> reader =
     new ArchiveReader(aBlob, window, encoding);
   return reader.forget();
 }
 
-ArchiveReader::ArchiveReader(nsIDOMBlob* aBlob, nsPIDOMWindow* aWindow,
+ArchiveReader::ArchiveReader(File& aBlob, nsPIDOMWindow* aWindow,
                              const nsACString& aEncoding)
-  : mBlob(aBlob)
+  : mBlob(&aBlob)
   , mWindow(aWindow)
   , mStatus(NOT_STARTED)
   , mEncoding(aEncoding)
 {
-  MOZ_ASSERT(aBlob);
   MOZ_ASSERT(aWindow);
 }
 
 ArchiveReader::~ArchiveReader()
 {
 }
 
 /* virtual */ JSObject*
--- a/dom/archivereader/ArchiveReader.h
+++ b/dom/archivereader/ArchiveReader.h
@@ -14,16 +14,17 @@
 #include "nsCOMArray.h"
 #include "nsIChannel.h"
 #include "nsIDOMFile.h"
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
 namespace dom {
 struct ArchiveReaderOptions;
+class File;
 class GlobalObject;
 } // namespace dom
 } // namespace mozilla
 
 BEGIN_ARCHIVEREADER_NAMESPACE
 
 class ArchiveRequest;
 
@@ -33,20 +34,20 @@ class ArchiveRequest;
 class ArchiveReader MOZ_FINAL : public nsISupports,
                                 public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ArchiveReader)
 
   static already_AddRefed<ArchiveReader>
-  Constructor(const GlobalObject& aGlobal, nsIDOMBlob* aBlob,
+  Constructor(const GlobalObject& aGlobal, File& aBlob,
               const ArchiveReaderOptions& aOptions, ErrorResult& aError);
 
-  ArchiveReader(nsIDOMBlob* aBlob, nsPIDOMWindow* aWindow,
+  ArchiveReader(File& aBlob, nsPIDOMWindow* aWindow,
                 const nsACString& aEncoding);
 
   nsIDOMWindow* GetParentObject() const
   {
     return mWindow;
   }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
@@ -70,17 +71,17 @@ private:
   already_AddRefed<ArchiveRequest> GenerateArchiveRequest();
 
   nsresult OpenArchive();
 
   void RequestReady(ArchiveRequest* aRequest);
 
 protected:
   // The archive blob/file
-  nsCOMPtr<nsIDOMBlob> mBlob;
+  nsRefPtr<File> mBlob;
 
   // The window is needed by the requests
   nsCOMPtr<nsPIDOMWindow> mWindow;
 
   // Are we ready to return data?
   enum {
     NOT_STARTED = 0,
     WORKING,
--- a/dom/archivereader/ArchiveZipEvent.cpp
+++ b/dom/archivereader/ArchiveZipEvent.cpp
@@ -69,27 +69,27 @@ ArchiveZipItem::GetFilename(nsString& aF
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   aFilename = mFilenameU;
   return NS_OK;
 }
 
-// From zipItem to DOMFile:
+// From zipItem to File:
 nsIDOMFile*
 ArchiveZipItem::File(ArchiveReader* aArchiveReader)
 {
   nsString filename;
 
   if (NS_FAILED(GetFilename(filename))) {
     return nullptr;
   }
 
-  return new DOMFile(
+  return new dom::File(aArchiveReader,
     new ArchiveZipFileImpl(filename,
                            NS_ConvertUTF8toUTF16(GetType()),
                            StrToInt32(mCentralStruct.orglen),
                            mCentralStruct, aArchiveReader));
 }
 
 uint32_t
 ArchiveZipItem::StrToInt32(const uint8_t* aStr)
--- a/dom/archivereader/ArchiveZipEvent.h
+++ b/dom/archivereader/ArchiveZipEvent.h
@@ -25,17 +25,17 @@ public:
                  const ZipCentral& aCentralStruct,
                  const nsACString& aEncoding);
 protected:
   virtual ~ArchiveZipItem();
 
 public:
   nsresult GetFilename(nsString& aFilename) MOZ_OVERRIDE;
 
-  // From zipItem to DOMFile:
+  // From zipItem to File:
   virtual nsIDOMFile* File(ArchiveReader* aArchiveReader) MOZ_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
@@ -5,17 +5,19 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ArchiveZipFile.h"
 #include "ArchiveZipEvent.h"
 
 #include "nsIInputStream.h"
 #include "zlib.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/File.h"
 
+using namespace mozilla::dom;
 USING_ARCHIVEREADER_NAMESPACE
 
 #define ZIP_CHUNK 16384
 
 /**
  * Input stream object for zip files
  */
 class ArchiveInputStream MOZ_FINAL : public nsIInputStream,
@@ -391,20 +393,21 @@ ArchiveZipFileImpl::Unlink()
 
 void
 ArchiveZipFileImpl::Traverse(nsCycleCollectionTraversalCallback &cb)
 {
   ArchiveZipFileImpl* tmp = this;
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArchiveReader);
 }
 
-already_AddRefed<mozilla::dom::DOMFileImpl>
+already_AddRefed<mozilla::dom::FileImpl>
 ArchiveZipFileImpl::CreateSlice(uint64_t aStart,
                                 uint64_t aLength,
-                                const nsAString& aContentType)
+                                const nsAString& aContentType,
+                                mozilla::ErrorResult& aRv)
 {
-  nsRefPtr<DOMFileImpl> impl =
+  nsRefPtr<FileImpl> impl =
     new ArchiveZipFileImpl(mFilename, mContentType, aStart, mLength, mCentral,
                            mArchiveReader);
   return impl.forget();
 }
 
-NS_IMPL_ISUPPORTS_INHERITED0(ArchiveZipFileImpl, DOMFileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(ArchiveZipFileImpl, FileImpl)
--- a/dom/archivereader/ArchiveZipFile.h
+++ b/dom/archivereader/ArchiveZipFile.h
@@ -3,54 +3,55 @@
 /* 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_archivereader_domarchivefile_h__
 #define mozilla_dom_archivereader_domarchivefile_h__
 
 #include "mozilla/Attributes.h"
-#include "nsDOMFile.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/File.h"
 
 #include "ArchiveReader.h"
 
 #include "ArchiveReaderCommon.h"
 #include "zipstruct.h"
 
 BEGIN_ARCHIVEREADER_NAMESPACE
 
 /**
- * ArchiveZipFileImpl to DOMFileImpl
+ * ArchiveZipFileImpl to FileImpl
  */
-class ArchiveZipFileImpl : public DOMFileImplBase
+class ArchiveZipFileImpl : public FileImplBase
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   ArchiveZipFileImpl(const nsAString& aName,
                      const nsAString& aContentType,
                      uint64_t aLength,
                      ZipCentral& aCentral,
                      ArchiveReader* aReader)
-  : DOMFileImplBase(aName, aContentType, aLength),
+  : FileImplBase(aName, aContentType, aLength),
     mCentral(aCentral),
     mArchiveReader(aReader),
     mFilename(aName)
   {
     NS_ASSERTION(mArchiveReader, "must have a reader");
     MOZ_COUNT_CTOR(ArchiveZipFileImpl);
   }
 
   ArchiveZipFileImpl(const nsAString& aName,
                      const nsAString& aContentType,
                      uint64_t aStart,
                      uint64_t aLength,
                      ZipCentral& aCentral,
                      ArchiveReader* aReader)
-  : DOMFileImplBase(aContentType, aStart, aLength),
+  : FileImplBase(aContentType, aStart, aLength),
     mCentral(aCentral),
     mArchiveReader(aReader),
     mFilename(aName)
   {
     NS_ASSERTION(mArchiveReader, "must have a reader");
     MOZ_COUNT_CTOR(ArchiveZipFileImpl);
   }
 
@@ -66,19 +67,19 @@ public:
   }
 
 protected:
   virtual ~ArchiveZipFileImpl()
   {
     MOZ_COUNT_DTOR(ArchiveZipFileImpl);
   }
 
-  virtual already_AddRefed<DOMFileImpl> CreateSlice(uint64_t aStart,
-                                                    uint64_t aLength,
-                                                    const nsAString& aContentType) MOZ_OVERRIDE;
+  virtual already_AddRefed<FileImpl>
+  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
+              mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
 
 private: // Data
   ZipCentral mCentral;
   nsRefPtr<ArchiveReader> mArchiveReader;
 
   nsString mFilename;
 };
 
--- a/dom/base/ImageEncoder.cpp
+++ b/dom/base/ImageEncoder.cpp
@@ -83,18 +83,20 @@ public:
   {}
 
   NS_IMETHOD Run()
   {
     nsresult rv = NS_OK;
     MOZ_ASSERT(NS_IsMainThread());
 
     if (!mFailed) {
-      nsRefPtr<DOMFile> blob =
-        DOMFile::CreateMemoryFile(mImgData, mImgSize, mType);
+      // The correct parentObject has to be set by the mEncodeCompleteCallback.
+      nsRefPtr<File> blob =
+        File::CreateMemoryFile(nullptr, mImgData, mImgSize, mType);
+      MOZ_ASSERT(blob);
 
       rv = mEncodeCompleteCallback->ReceiveBlob(blob.forget());
     }
 
     mEncodeCompleteCallback = nullptr;
 
     mEncoderThread->Shutdown();
     return rv;
--- a/dom/base/ImageEncoder.h
+++ b/dom/base/ImageEncoder.h
@@ -2,18 +2,18 @@
 /* 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 ImageEncoder_h
 #define ImageEncoder_h
 
 #include "imgIEncoder.h"
-#include "nsDOMFile.h"
 #include "nsError.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/HTMLCanvasElementBinding.h"
 #include "nsLayoutUtils.h"
 #include "nsNetUtil.h"
 #include "nsSize.h"
 
 class nsICanvasRenderingContextInternal;
 
 namespace mozilla {
@@ -46,27 +46,31 @@ public:
   // fall back to a PNG encoder. aOptions are the options to be passed to the
   // encoder and aUsingCustomOptions specifies whether custom parse options were
   // used (i.e. by using -moz-parse-options). If there are any unrecognized
   // custom parse options, we fall back to the default values for the encoder
   // without any options at all. A return value of NS_OK only implies
   // successful dispatching of the extraction step to the encoding thread.
   // aEncodeCallback will be called on main thread when encoding process is
   // success.
+  // Note: The callback has to set a valid parent for content for the generated
+  // Blob object.
   static nsresult ExtractDataAsync(nsAString& aType,
                                    const nsAString& aOptions,
                                    bool aUsingCustomOptions,
                                    uint8_t* aImageBuffer,
                                    int32_t aFormat,
                                    const nsIntSize aSize,
                                    EncodeCompleteCallback* aEncodeCallback);
 
   // Extract an Image asynchronously. Its function is same as ExtractDataAsync
   // except for the parameters. aImage is the uncompressed data. aEncodeCallback
   // will be called on main thread when encoding process is success.
+  // Note: The callback has to set a valid parent for content for the generated
+  // Blob object.
   static nsresult ExtractDataFromLayersImageAsync(nsAString& aType,
                                                   const nsAString& aOptions,
                                                   bool aUsingCustomOptions,
                                                   layers::Image* aImage,
                                                   EncodeCompleteCallback* aEncodeCallback);
 
   // Gives you a stream containing the image represented by aImageBuffer.
   // The format is given in aFormat, for example
@@ -106,17 +110,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<DOMFile> aBlob) = 0;
+  virtual nsresult ReceiveBlob(already_AddRefed<File> aBlob) = 0;
 
 protected:
   virtual ~EncodeCompleteCallback() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/base/MessagePort.cpp
+++ b/dom/base/MessagePort.cpp
@@ -1,27 +1,28 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MessagePort.h"
 #include "MessageEvent.h"
+#include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/Event.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/MessageChannel.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/MessagePortList.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsPresContext.h"
 #include "ScriptSettings.h"
 
 #include "nsIDocument.h"
-#include "nsIDOMFile.h"
 #include "nsIDOMFileList.h"
 #include "nsIPresShell.h"
 
 namespace mozilla {
 namespace dom {
 
 class DispatchEventRunnable : public nsRunnable
 {
@@ -98,17 +99,47 @@ struct StructuredCloneInfo
 
 static JSObject*
 PostMessageReadStructuredClone(JSContext* cx,
                                JSStructuredCloneReader* reader,
                                uint32_t tag,
                                uint32_t data,
                                void* closure)
 {
-  if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
+  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
+  NS_ASSERTION(scInfo, "Must have scInfo!");
+
+  if (tag == SCTAG_DOM_BLOB) {
+    NS_ASSERTION(!data, "Data should be empty");
+
+    // What we get back from the reader is a FileImpl.
+    // From that we create a new File.
+    FileImpl* 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 (!WrapNewBindingObject(cx, blob, &val)) {
+          return nullptr;
+        }
+      }
+
+      return &val.toObject();
+    }
+  }
+
+  if (tag == SCTAG_DOM_FILELIST) {
     NS_ASSERTION(!data, "Data should be empty");
 
     nsISupports* supports;
     if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
       JS::Rooted<JS::Value> val(cx);
       if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) {
         return val.toObjectOrNull();
       }
@@ -129,28 +160,36 @@ static bool
 PostMessageWriteStructuredClone(JSContext* cx,
                                 JSStructuredCloneWriter* writer,
                                 JS::Handle<JSObject*> obj,
                                 void *closure)
 {
   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
   NS_ASSERTION(scInfo, "Must have scInfo!");
 
+  // See if this is a File/Blob object.
+  {
+    File* blob = nullptr;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
+      FileImpl* blobImpl = blob->Impl();
+      if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
+          JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
+        scInfo->mEvent->StoreISupports(blobImpl);
+        return true;
+      }
+    }
+  }
+
   nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
   nsContentUtils::XPConnect()->
     GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
   if (wrappedNative) {
     uint32_t scTag = 0;
     nsISupports* supports = wrappedNative->Native();
 
-    nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
-    if (blob) {
-      scTag = SCTAG_DOM_BLOB;
-    }
-
     nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
     if (list) {
       scTag = SCTAG_DOM_FILELIST;
     }
 
     if (scTag) {
       return JS_WriteUint32Pair(writer, scTag, 0) &&
              JS_WriteBytes(writer, &supports, sizeof(supports)) &&
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -8,16 +8,17 @@
 #include "base/basictypes.h"
 
 #include "Navigator.h"
 #include "nsIXULAppInfo.h"
 #include "nsPluginArray.h"
 #include "nsMimeTypeArray.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/DesktopNotification.h"
+#include "mozilla/dom/File.h"
 #include "nsGeolocation.h"
 #include "nsIHttpProtocolHandler.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsISupportsPriority.h"
 #include "nsICachingChannel.h"
@@ -366,16 +367,18 @@ Navigator::GetAppName(nsAString& aAppNam
  *
  * An empty array will be returned if there is no valid languages.
  */
 /* static */ void
 Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  aLanguages.Clear();
+
   // E.g. "de-de, en-us,en".
   const nsAdoptingString& acceptLang =
     Preferences::GetLocalizedString("intl.accept_languages");
 
   // Split values on commas.
   nsCharSeparatedTokenizer langTokenizer(acceptLang, ',');
   while (langTokenizer.hasMoreTokens()) {
     nsDependentSubstring lang = langTokenizer.nextToken();
@@ -1150,24 +1153,24 @@ Navigator::SendBeacon(const nsAString& a
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       mimeType.AssignLiteral("application/octet-stream");
       in = strStream;
 
     } else if (aData.Value().IsBlob()) {
-      nsCOMPtr<nsIDOMBlob> blob = aData.Value().GetAsBlob();
-      rv = blob->GetInternalStream(getter_AddRefs(in));
+      File& blob = aData.Value().GetAsBlob();
+      rv = blob.GetInternalStream(getter_AddRefs(in));
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       nsAutoString type;
-      rv = blob->GetType(type);
+      rv = blob.GetType(type);
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       mimeType = NS_ConvertUTF16toUTF8(type);
 
     } else if (aData.Value().IsFormData()) {
       nsFormData& form = aData.Value().GetAsFormData();
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -20,17 +20,16 @@
 #include "nsTArray.h"
 
 class nsPluginArray;
 class nsMimeTypeArray;
 class nsPIDOMWindow;
 class nsIDOMNavigatorSystemMessages;
 class nsDOMCameraManager;
 class nsDOMDeviceStorage;
-class nsIDOMBlob;
 class nsIPrincipal;
 class nsIURI;
 
 namespace mozilla {
 namespace dom {
 class Geolocation;
 class systemMessageCallback;
 struct MediaStreamConstraints;
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -1,18 +1,18 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "URL.h"
 
 #include "nsGlobalWindow.h"
-#include "nsDOMFile.h"
 #include "DOMMediaStream.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/MediaSource.h"
 #include "mozilla/dom/URLBinding.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIIOService.h"
 #include "nsEscape.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
@@ -106,25 +106,22 @@ URL::Constructor(const GlobalObject& aGl
   }
 
   nsRefPtr<URL> url = new URL(uri);
   return url.forget();
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal,
-                     nsIDOMBlob* aBlob,
+                     File& aBlob,
                      const objectURLOptions& aOptions,
                      nsString& aResult,
                      ErrorResult& aError)
 {
-  DOMFile* blob = static_cast<DOMFile*>(aBlob);
-  MOZ_ASSERT(blob);
-
-  CreateObjectURLInternal(aGlobal, blob->Impl(),
+  CreateObjectURLInternal(aGlobal, aBlob.Impl(),
                           NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult,
                           aError);
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
                      const mozilla::dom::objectURLOptions& aOptions,
                      nsString& aResult,
--- a/dom/base/URL.h
+++ b/dom/base/URL.h
@@ -18,16 +18,17 @@ class nsIURI;
 
 namespace mozilla {
 
 class ErrorResult;
 class DOMMediaStream;
 
 namespace dom {
 
+class File;
 class MediaSource;
 class GlobalObject;
 struct objectURLOptions;
 
 namespace workers {
 class URLProxy;
 }
 
@@ -48,17 +49,17 @@ public:
   static already_AddRefed<URL>
   Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
               URL& aBase, ErrorResult& aRv);
   static already_AddRefed<URL>
   Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
               const nsAString& aBase, ErrorResult& aRv);
 
   static void CreateObjectURL(const GlobalObject& aGlobal,
-                              nsIDOMBlob* aBlob,
+                              File& aBlob,
                               const objectURLOptions& aOptions,
                               nsString& aResult,
                               ErrorResult& aError);
   static void CreateObjectURL(const GlobalObject& aGlobal,
                               DOMMediaStream& aStream,
                               const objectURLOptions& aOptions,
                               nsString& aResult,
                               ErrorResult& aError);
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -230,17 +230,17 @@ ResolveWindowNamedProperty(JSContext* aC
 }
 
 static bool
 EnumerateWindowNamedProperties(JSContext* aCx, JS::Handle<JSObject*> aWrapper,
                                JS::Handle<JSObject*> aObj,
                                JS::AutoIdVector& aProps)
 {
   JSAutoCompartment ac(aCx, aObj);
-  return js::GetProxyHandler(aObj)->getOwnPropertyNames(aCx, aObj, aProps);
+  return js::GetProxyHandler(aObj)->ownPropertyKeys(aCx, aObj, aProps);
 }
 
 const NativePropertyHooks sWindowNamedPropertiesNativePropertyHooks[] = { {
   ResolveWindowNamedProperty,
   EnumerateWindowNamedProperties,
   { nullptr, nullptr },
   prototypes::id::_ID_Count,
   constructors::id::_ID_Count,
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -89,16 +89,17 @@ UNIFIED_SOURCES += [
     'nsDOMClassInfo.cpp',
     'nsDOMNavigationTiming.cpp',
     'nsDOMScriptObjectFactory.cpp',
     'nsDOMWindowList.cpp',
     'nsFocusManager.cpp',
     'nsGlobalWindowCommands.cpp',
     'nsHistory.cpp',
     'nsIGlobalObject.cpp',
+    'nsJSEnvironment.cpp',
     'nsJSTimeoutHandler.cpp',
     'nsJSUtils.cpp',
     'nsLocation.cpp',
     'nsMimeTypeArray.cpp',
     'nsPerformance.cpp',
     'nsQueryContentEventResult.cpp',
     'nsScreen.cpp',
     'nsScriptNameSpaceManager.cpp',
@@ -118,18 +119,16 @@ UNIFIED_SOURCES += [
 # these files couldn't be in UNIFIED_SOURCES for now for reasons given below:
 SOURCES += [
     # this file doesn't like windows.h
     'MessagePort.cpp',
     # this file doesn't like windows.h
     'nsDOMWindowUtils.cpp',
     # This file has a #error "Never include windows.h in this file!"
     'nsGlobalWindow.cpp',
-    # This file forces NSPR logging.
-    'nsJSEnvironment.cpp',
     # nsPluginArray.cpp includes npapi.h indirectly, and that includes a lot of system headers
     'nsPluginArray.cpp',
 ]
 
 EXTRA_COMPONENTS += [
     'ConsoleAPI.manifest',
     'ConsoleAPIStorage.js',
     'SiteSpecificUserAgent.js',
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -30,17 +30,16 @@
 #include "nsCRTGlue.h"
 #include "nsICategoryManager.h"
 #include "nsIComponentRegistrar.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIXPConnect.h"
 #include "xptcall.h"
 #include "nsTArray.h"
-#include "nsDOMBlobBuilder.h"
 
 // General helper includes
 #include "nsGlobalWindow.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMEventListener.h"
@@ -96,20 +95,16 @@
 #include "nsITreeSelection.h"
 #include "nsITreeContentView.h"
 #include "nsITreeView.h"
 #include "nsIXULTemplateBuilder.h"
 #include "nsITreeColumns.h"
 #endif
 #include "nsIDOMXPathNSResolver.h"
 
-// Drag and drop
-#include "nsIDOMFile.h"
-#include "nsDOMBlobBuilder.h" // nsDOMMultipartFile
-
 #include "nsIEventListenerService.h"
 #include "nsIMessageManager.h"
 
 #include "mozilla/dom/TouchEvent.h"
 
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 
@@ -289,21 +284,16 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(XSLTProcessor, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(XPathNSResolver, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(Blob, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(File, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
   NS_DEFINE_CLASSINFO_DATA(MozSmsMessage, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MozMmsMessage, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MozMobileMessageThread, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -367,18 +357,16 @@ struct nsConstructorFuncMapData
   nsDOMConstructorFunc mConstructorFunc;
 };
 
 #define NS_DEFINE_CONSTRUCTOR_FUNC_DATA(_class, _func)                        \
   { eDOMClassInfo_##_class##_id, _func },
 
 static const nsConstructorFuncMapData kConstructorFuncMap[] =
 {
-  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Blob, DOMMultipartFileImpl::NewBlob)
-  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, DOMMultipartFileImpl::NewFile)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XSLTProcessor, XSLTProcessorCtor)
 };
 #undef NS_DEFINE_CONSTRUCTOR_FUNC_DATA
 
 nsIXPConnect *nsDOMClassInfo::sXPConnect = nullptr;
 bool nsDOMClassInfo::sIsInitialized = false;
 
 
@@ -790,25 +778,16 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessor)
     DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessorPrivate)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(XPathNSResolver, nsIDOMXPathNSResolver)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathNSResolver)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(Blob, nsIDOMBlob)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBlob)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(File, nsIDOMFile)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBlob)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMFile)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(MozSmsMessage, nsIDOMMozSmsMessage)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsMessage)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozMmsMessage, nsIDOMMozMmsMessage)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozMmsMessage)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -38,19 +38,16 @@ DOMCI_CLASS(CSSMozDocumentRule)
 DOMCI_CLASS(CSSSupportsRule)
 
 // XSLTProcessor
 DOMCI_CLASS(XSLTProcessor)
 
 // DOM Level 3 XPath objects
 DOMCI_CLASS(XPathNSResolver)
 
-DOMCI_CLASS(Blob)
-DOMCI_CLASS(File)
-
 DOMCI_CLASS(MozSmsMessage)
 DOMCI_CLASS(MozMmsMessage)
 DOMCI_CLASS(MozMobileMessageThread)
 
 // @font-face in CSS
 DOMCI_CLASS(CSSFontFaceRule)
 
 DOMCI_CLASS(ContentFrameMessageManager)
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -43,21 +43,21 @@
 
 #include "nsViewManager.h"
 
 #include "nsIDOMHTMLCanvasElement.h"
 #include "nsLayoutUtils.h"
 #include "nsComputedDOMStyle.h"
 #include "nsIPresShell.h"
 #include "nsCSSProps.h"
-#include "nsDOMFile.h"
 #include "nsTArrayHelpers.h"
 #include "nsIDocShell.h"
 #include "nsIContentViewer.h"
 #include "mozilla/StyleAnimationValue.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/DOMRect.h"
 #include <algorithm>
 
 #if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK)
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #endif
 
@@ -69,17 +69,16 @@
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/IDBFactoryBinding.h"
 #include "mozilla/dom/IDBMutableFileBinding.h"
 #include "mozilla/dom/indexedDB/IDBMutableFile.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/quota/PersistenceType.h"
 #include "mozilla/dom/quota/QuotaManager.h"
-#include "nsDOMBlobBuilder.h"
 #include "nsPrintfCString.h"
 #include "nsViewportInfo.h"
 #include "nsIFormControl.h"
 #include "nsIScriptError.h"
 #include "nsIAppShell.h"
 #include "nsWidgetsCID.h"
 #include "FrameLayerBuilder.h"
 #include "nsDisplayList.h"
@@ -2848,17 +2847,25 @@ nsDOMWindowUtils::WrapDOMFile(nsIFile *a
                               nsIDOMFile **aDOMFile)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   if (!aFile) {
     return NS_ERROR_FAILURE;
   }
 
-  nsRefPtr<DOMFile> file = DOMFile::CreateFromFile(aFile);
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+  NS_ENSURE_STATE(window);
+
+  nsPIDOMWindow* innerWindow = window->GetCurrentInnerWindow();
+  if (!innerWindow) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<File> file = File::CreateFromFile(innerWindow, aFile);
   file.forget(aDOMFile);
   return NS_OK;
 }
 
 #ifdef DEBUG
 static bool
 CheckLeafLayers(Layer* aLayer, const nsIntPoint& aOffset, nsIntRegion* aCoveredRegion)
 {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -117,17 +117,16 @@
 #include "nsIContentViewer.h"
 #include "nsIScriptError.h"
 #include "nsIControllers.h"
 #include "nsIControllerContext.h"
 #include "nsGlobalWindowCommands.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsCSSProps.h"
-#include "nsIDOMFile.h"
 #include "nsIDOMFileList.h"
 #include "nsIURIFixup.h"
 #ifndef DEBUG
 #include "nsIAppStartup.h"
 #include "nsToolkitCompsCID.h"
 #endif
 #include "nsCDefaultURIFixup.h"
 #include "mozilla/EventDispatcher.h"
@@ -170,20 +169,16 @@
 
 #include "nsIDragService.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Selection.h"
 #include "nsFrameLoader.h"
 #include "nsISupportsPrimitives.h"
 #include "nsXPCOMCID.h"
 #include "mozIThirdPartyUtil.h"
-#ifdef MOZ_LOGGING
-// so we can get logging even in release builds
-#define FORCE_PR_LOG 1
-#endif
 #include "prlog.h"
 #include "prenv.h"
 #include "prprf.h"
 
 #include "mozilla/dom/MessageChannel.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/indexedDB/IDBFactory.h"
@@ -624,19 +619,19 @@ public:
                                         JS::Handle<jsid> id,
                                         JS::MutableHandle<JSPropertyDescriptor> desc)
                                         const MOZ_OVERRIDE;
   virtual bool defineProperty(JSContext* cx,
                               JS::Handle<JSObject*> proxy,
                               JS::Handle<jsid> id,
                               JS::MutableHandle<JSPropertyDescriptor> desc)
                               const MOZ_OVERRIDE;
-  virtual bool getOwnPropertyNames(JSContext *cx,
-                                   JS::Handle<JSObject*> proxy,
-                                   JS::AutoIdVector &props) const MOZ_OVERRIDE;
+  virtual bool ownPropertyKeys(JSContext *cx,
+                               JS::Handle<JSObject*> proxy,
+                               JS::AutoIdVector &props) const MOZ_OVERRIDE;
   virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id,
                        bool *bp) const MOZ_OVERRIDE;
   virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
                          JS::AutoIdVector &props) const MOZ_OVERRIDE;
 
   virtual bool watch(JSContext *cx, JS::Handle<JSObject*> proxy,
                      JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const MOZ_OVERRIDE;
@@ -810,27 +805,27 @@ nsOuterWindowProxy::defineProperty(JSCon
     // non-strict mode.
     return true;
   }
 
   return js::Wrapper::defineProperty(cx, proxy, id, desc);
 }
 
 bool
-nsOuterWindowProxy::getOwnPropertyNames(JSContext *cx,
-                                        JS::Handle<JSObject*> proxy,
-                                        JS::AutoIdVector &props) const
+nsOuterWindowProxy::ownPropertyKeys(JSContext *cx,
+                                    JS::Handle<JSObject*> proxy,
+                                    JS::AutoIdVector &props) const
 {
   // Just our indexed stuff followed by our "normal" own property names.
   if (!AppendIndexedPropertyNames(cx, proxy, props)) {
     return false;
   }
 
   JS::AutoIdVector innerProps(cx);
-  if (!js::Wrapper::getOwnPropertyNames(cx, proxy, innerProps)) {
+  if (!js::Wrapper::ownPropertyKeys(cx, proxy, innerProps)) {
     return false;
   }
   return js::AppendUnique(cx, props, innerProps);
 }
 
 bool
 nsOuterWindowProxy::delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
                             JS::Handle<jsid> id, bool *bp) const
@@ -935,17 +930,17 @@ nsOuterWindowProxy::set(JSContext *cx, J
   return js::Wrapper::set(cx, proxy, receiver, id, strict, vp);
 }
 
 bool
 nsOuterWindowProxy::keys(JSContext *cx, JS::Handle<JSObject*> proxy,
                          JS::AutoIdVector &props) const
 {
   // BaseProxyHandler::keys seems to do what we want here: call
-  // getOwnPropertyNames and then filter out the non-enumerable properties.
+  // ownPropertyKeys and then filter out the non-enumerable properties.
   return js::BaseProxyHandler::keys(cx, proxy, props);
 }
 
 bool
 nsOuterWindowProxy::iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
                             unsigned flags, JS::MutableHandle<JS::Value> vp) const
 {
   // BaseProxyHandler::iterate seems to do what we want here: fall
@@ -7873,28 +7868,42 @@ struct StructuredCloneInfo {
 
 static JSObject*
 PostMessageReadStructuredClone(JSContext* cx,
                                JSStructuredCloneReader* reader,
                                uint32_t tag,
                                uint32_t data,
                                void* closure)
 {
+  StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
+  NS_ASSERTION(scInfo, "Must have scInfo!");
+
   if (tag == SCTAG_DOM_BLOB) {
     NS_ASSERTION(!data, "Data should be empty");
 
-    // What we get back from the reader is a DOMFileImpl.
-    // From that we create a new DOMFile.
-    nsISupports* supports;
-    if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
-      nsCOMPtr<nsIDOMBlob> file = new DOMFile(static_cast<DOMFileImpl*>(supports));
+    // What we get back from the reader is a FileImpl.
+    // From that we create a new File.
+    FileImpl* 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);
-      if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, file, &val))) {
-        return val.toObjectOrNull();
-      }
+      {
+        nsRefPtr<File> blob = new File(scInfo->window, blobImpl);
+        if (!WrapNewBindingObject(cx, blob, &val)) {
+          return nullptr;
+        }
+      }
+
+      return &val.toObject();
     }
   }
 
   if (tag == SCTAG_DOM_FILELIST) {
     NS_ASSERTION(!data, "Data should be empty");
 
     nsISupports* supports;
     if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
@@ -7919,30 +7928,36 @@ static bool
 PostMessageWriteStructuredClone(JSContext* cx,
                                 JSStructuredCloneWriter* writer,
                                 JS::Handle<JSObject*> obj,
                                 void *closure)
 {
   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
   NS_ASSERTION(scInfo, "Must have scInfo!");
 
+  // See if this is a File/Blob object.
+  {
+    File* blob = nullptr;
+    if (scInfo->subsumes && NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
+      FileImpl* blobImpl = blob->Impl();
+      if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) &&
+          JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) {
+        scInfo->event->StoreISupports(blobImpl);
+        return true;
+      }
+    }
+  }
+
   nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
   nsContentUtils::XPConnect()->
     GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
   if (wrappedNative) {
     uint32_t scTag = 0;
     nsISupports* supports = wrappedNative->Native();
 
-    nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
-    if (blob && scInfo->subsumes) {
-      scTag = SCTAG_DOM_BLOB;
-      DOMFile* file = static_cast<DOMFile*>(blob.get());
-      supports = file->Impl();
-    }
-
     nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
     if (list && scInfo->subsumes)
       scTag = SCTAG_DOM_FILELIST;
 
     if (scTag)
       return JS_WriteUint32Pair(writer, scTag, 0) &&
              JS_WriteBytes(writer, &supports, sizeof(supports)) &&
              scInfo->event->StoreISupports(supports);
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -68,20 +68,16 @@
 #include "nsJSPrincipals.h"
 
 #ifdef XP_MACOSX
 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
 #undef check
 #endif
 #include "AccessCheck.h"
 
-#ifdef MOZ_LOGGING
-// Force PR_LOGGING so we can get JS strict warnings even in release builds
-#define FORCE_PR_LOG 1
-#endif
 #include "prlog.h"
 #include "prthread.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
--- a/dom/base/test/file_url.jsm
+++ b/dom/base/test/file_url.jsm
@@ -1,12 +1,12 @@
 this.EXPORTED_SYMBOLS = ['checkFromJSM'];
 
 this.checkFromJSM = function checkFromJSM(ok, is) {
-  Components.utils.importGlobalProperties(['URL']);
+  Components.utils.importGlobalProperties(['URL', 'Blob']);
 
   var url = new URL('http://www.example.com');
   is(url.href, "http://www.example.com/", "JSM should have URL");
 
   var url2 = new URL('/foobar', url);
   is(url2.href, "http://www.example.com/foobar", "JSM should have URL - based on another URL");
 
   var blob = new Blob(['a']);
--- a/dom/base/test/test_messageChannel_post.html
+++ b/dom/base/test/test_messageChannel_post.html
@@ -45,17 +45,21 @@ https://bugzilla.mozilla.org/show_bug.cg
                   null,
                   undefined,
                   "hello world",
                   new Blob([]),
                   true ];
 
     a.port1.onmessage = function(evt) {
       ok(tests.length, "We are waiting for a message");
-      is(tests[0], evt.data, "Value ok: " + tests[0]);
+      if (typeof(tests[0]) == 'object') {
+        is(typeof(tests[0]), typeof(evt.data), "Value ok: " + tests[0]);
+      } else {
+        is(tests[0], evt.data, "Value ok: " + tests[0]);
+      }
       tests.shift();
       runTest();
     }
 
     function runTest() {
       if (!tests.length) {
         SimpleTest.finish();
         return;
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1390,21 +1390,21 @@ XrayDefineProperty(JSContext* cx, JS::Ha
       return true;
 
   const DOMProxyHandler* handler = GetDOMProxyHandler(obj);
   return handler->defineProperty(cx, wrapper, id, desc, defined);
 }
 
 template<typename SpecType>
 bool
-XrayEnumerateAttributesOrMethods(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                                 JS::Handle<JSObject*> obj,
-                                 const Prefable<const SpecType>* list,
-                                 jsid* ids, const SpecType* specList,
-                                 unsigned flags, JS::AutoIdVector& props)
+XrayAttributeOrMethodKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                          JS::Handle<JSObject*> obj,
+                          const Prefable<const SpecType>* list,
+                          jsid* ids, const SpecType* specList,
+                          unsigned flags, JS::AutoIdVector& props)
 {
   for (; list->specs; ++list) {
     if (list->isEnabled(cx, obj)) {
       // Set i to be the index into our full list of ids/specs that we're
       // looking at now.
       size_t i = list->specs - specList;
       for ( ; ids[i] != JSID_VOID; ++i) {
         if (((flags & JSITER_HIDDEN) ||
@@ -1413,51 +1413,51 @@ XrayEnumerateAttributesOrMethods(JSConte
           return false;
         }
       }
     }
   }
   return true;
 }
 
-#define ENUMERATE_IF_DEFINED(fieldName) {                                     \
+#define ADD_KEYS_IF_DEFINED(fieldName) {                                      \
   if (nativeProperties->fieldName##s &&                                       \
-      !XrayEnumerateAttributesOrMethods(cx, wrapper, obj,                     \
-                                        nativeProperties->fieldName##s,       \
-                                        nativeProperties->fieldName##Ids,     \
-                                        nativeProperties->fieldName##Specs,   \
-                                        flags, props)) {                      \
+      !XrayAttributeOrMethodKeys(cx, wrapper, obj,                            \
+                                 nativeProperties->fieldName##s,              \
+                                 nativeProperties->fieldName##Ids,            \
+                                 nativeProperties->fieldName##Specs,          \
+                                 flags, props)) {                             \
     return false;                                                             \
   }                                                                           \
 }
 
 
 bool
-XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                        JS::Handle<JSObject*> obj,
-                        unsigned flags, JS::AutoIdVector& props,
-                        DOMObjectType type,
-                        const NativeProperties* nativeProperties)
+XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                    JS::Handle<JSObject*> obj,
+                    unsigned flags, JS::AutoIdVector& props,
+                    DOMObjectType type,
+                    const NativeProperties* nativeProperties)
 {
   MOZ_ASSERT(type != eNamedPropertiesObject);
 
   if (IsInstance(type)) {
-    ENUMERATE_IF_DEFINED(unforgeableMethod);
-    ENUMERATE_IF_DEFINED(unforgeableAttribute);
+    ADD_KEYS_IF_DEFINED(unforgeableMethod);
+    ADD_KEYS_IF_DEFINED(unforgeableAttribute);
     if (type == eGlobalInstance && GlobalPropertiesAreOwn()) {
-      ENUMERATE_IF_DEFINED(method);
-      ENUMERATE_IF_DEFINED(attribute);
+      ADD_KEYS_IF_DEFINED(method);
+      ADD_KEYS_IF_DEFINED(attribute);
     }
   } else if (type == eInterface) {
-    ENUMERATE_IF_DEFINED(staticMethod);
-    ENUMERATE_IF_DEFINED(staticAttribute);
+    ADD_KEYS_IF_DEFINED(staticMethod);
+    ADD_KEYS_IF_DEFINED(staticAttribute);
   } else if (type != eGlobalInterfacePrototype || !GlobalPropertiesAreOwn()) {
     MOZ_ASSERT(IsInterfacePrototype(type));
-    ENUMERATE_IF_DEFINED(method);
-    ENUMERATE_IF_DEFINED(attribute);
+    ADD_KEYS_IF_DEFINED(method);
+    ADD_KEYS_IF_DEFINED(attribute);
   }
 
   if (nativeProperties->constants) {
     const Prefable<const ConstantSpec>* constant;
     for (constant = nativeProperties->constants; constant->specs; ++constant) {
       if (constant->isEnabled(cx, obj)) {
         // Set i to be the index into our full list of ids/specs that we're
         // looking at now.
@@ -1469,24 +1469,23 @@ XrayEnumerateProperties(JSContext* cx, J
         }
       }
     }
   }
 
   return true;
 }
 
-#undef ENUMERATE_IF_DEFINED
+#undef ADD_KEYS_IF_DEFINED
 
 bool
-XrayEnumerateNativeProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                              const NativePropertyHooks* nativePropertyHooks,
-                              DOMObjectType type,
-                              JS::Handle<JSObject*> obj, unsigned flags,
-                              JS::AutoIdVector& props)
+XrayOwnNativePropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                          const NativePropertyHooks* nativePropertyHooks,
+                          DOMObjectType type, JS::Handle<JSObject*> obj,
+                          unsigned flags, JS::AutoIdVector& props)
 {
   MOZ_ASSERT(type != eNamedPropertiesObject);
 
   if (type == eInterface &&
       nativePropertyHooks->mPrototypeID != prototypes::id::_ID_Count &&
       !AddStringToIDVector(cx, props, "prototype")) {
     return false;
   }
@@ -1497,35 +1496,35 @@ XrayEnumerateNativeProperties(JSContext*
       !AddStringToIDVector(cx, props, "constructor")) {
     return false;
   }
 
   const NativePropertiesHolder& nativeProperties =
     nativePropertyHooks->mNativeProperties;
 
   if (nativeProperties.regular &&
-      !XrayEnumerateProperties(cx, wrapper, obj, flags, props, type,
-                               nativeProperties.regular)) {
+      !XrayOwnPropertyKeys(cx, wrapper, obj, flags, props, type,
+                           nativeProperties.regular)) {
     return false;
   }
 
   if (nativeProperties.chromeOnly &&
       xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
-      !XrayEnumerateProperties(cx, wrapper, obj, flags, props, type,
-                               nativeProperties.chromeOnly)) {
+      !XrayOwnPropertyKeys(cx, wrapper, obj, flags, props, type,
+                           nativeProperties.chromeOnly)) {
     return false;
   }
 
   return true;
 }
 
 bool
-XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                        JS::Handle<JSObject*> obj,
-                        unsigned flags, JS::AutoIdVector& props)
+XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                    JS::Handle<JSObject*> obj,
+                    unsigned flags, JS::AutoIdVector& props)
 {
   DOMObjectType type;
   const NativePropertyHooks* nativePropertyHooks =
     GetNativePropertyHooks(cx, obj, type);
   EnumerateOwnProperties enumerateOwnProperties =
     nativePropertyHooks->mEnumerateOwnProperties;
 
   if (type == eNamedPropertiesObject) {
@@ -1537,18 +1536,18 @@ XrayEnumerateProperties(JSContext* cx, J
     //       Should do something about XBL properties too.
     if (enumerateOwnProperties &&
         !enumerateOwnProperties(cx, wrapper, obj, props)) {
       return false;
     }
   }
 
   return (type == eGlobalInterfacePrototype && GlobalPropertiesAreOwn()) ||
-         XrayEnumerateNativeProperties(cx, wrapper, nativePropertyHooks, type,
-                                       obj, flags, props);
+         XrayOwnNativePropertyKeys(cx, wrapper, nativePropertyHooks, type,
+                                   obj, flags, props);
 }
 
 NativePropertyHooks sWorkerNativePropertyHooks = {
   nullptr,
   nullptr,
   {
     nullptr,
     nullptr
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2339,28 +2339,28 @@ XrayResolveOwnProperty(JSContext* cx, JS
  * defined will be set to true if a property was set as a result of this call.
  */
 bool
 XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
                    JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                    JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined);
 
 /**
- * This enumerates indexed or named properties of obj and operations, attributes
- * and constants of the interfaces for obj.
+ * Add to props the property keys of all indexed or named properties of obj and
+ * operations, attributes and constants of the interfaces for obj.
  *
  * wrapper is the Xray JS object.
  * obj is the target object of the Xray, a binding's instance object or a
  *     interface or interface prototype object.
  * flags are JSITER_* flags.
  */
 bool
-XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                        JS::Handle<JSObject*> obj,
-                        unsigned flags, JS::AutoIdVector& props);
+XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                    JS::Handle<JSObject*> obj,
+                    unsigned flags, JS::AutoIdVector& props);
 
 /**
  * Returns the prototype to use for an Xray for a DOM object, wrapped in cx's
  * compartment. This always returns the prototype that would be used for a DOM
  * object if we ignore any changes that might have been done to the prototype
  * chain by JS, the XBL code or plugins.
  *
  * cx should be in the Xray's compartment.
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -131,23 +131,20 @@ DOMInterfaces = {
         'channelInterpretation': 'channelInterpretationValue',
     },
 },
 
 'BarProp': {
     'headerFile': 'mozilla/dom/BarProps.h',
 },
 
-'Blob': [
-{
-    'headerFile': 'nsIDOMFile.h',
+'Blob': {
+    'nativeType': 'mozilla::dom::File',
+    'headerFile': 'mozilla/dom/File.h',
 },
-{
-    'workers': True,
-}],
 
 'BatteryManager': {
     'nativeType': 'mozilla::dom::battery::BatteryManager',
     'headerFile': 'BatteryManager.h'
 },
 
 'BluetoothAdapter': {
     'nativeType': 'mozilla::dom::bluetooth::BluetoothAdapter',
@@ -399,18 +396,17 @@ DOMInterfaces = {
 'Exception': {
     'headerFile': 'mozilla/dom/DOMException.h',
     'binaryNames': {
         'message': 'messageMoz',
     },
 },
 
 'FileList': {
-    'nativeType': 'nsDOMFileList',
-    'headerFile': 'nsDOMFile.h',
+    'headerFile': 'mozilla/dom/File.h',
 },
 
 'FileReader': {
     'nativeType': 'nsDOMFileReader',
     'implicitJSContext': [ 'readAsArrayBuffer' ],
 },
 
 'FileReaderSync': {
@@ -1793,17 +1789,16 @@ def addExternalIface(iface, nativeType=N
         domInterface['headerFile'] = headerFile
     domInterface['notflattened'] = notflattened
     DOMInterfaces[iface] = domInterface
 
 addExternalIface('ApplicationCache', nativeType='nsIDOMOfflineResourceList')
 addExternalIface('Counter')
 addExternalIface('CSSRule')
 addExternalIface('RTCDataChannel', nativeType='nsIDOMDataChannel')
-addExternalIface('File')
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
 addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
 addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
 addExternalIface('MozControllers', nativeType='nsIControllers')
 addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
 addExternalIface('MozFrameRequestCallback', nativeType='nsIFrameRequestCallback',
@@ -1822,16 +1817,17 @@ addExternalIface('MozWakeLockListener', 
 addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
 addExternalIface('nsIBrowserDOMWindow', nativeType='nsIBrowserDOMWindow',
                  notflattened=True)
 addExternalIface('nsIControllers', nativeType='nsIControllers')
 addExternalIface('nsIDOMCrypto', nativeType='nsIDOMCrypto',
                  headerFile='Crypto.h')
 addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback',
                  headerFile='nsIAsyncInputStream.h')
+addExternalIface('nsIFile', nativeType='nsIFile', notflattened=True)
 addExternalIface('nsIMessageBroadcaster', nativeType='nsIMessageBroadcaster',
                  headerFile='nsIMessageManager.h', notflattened=True)
 addExternalIface('nsISelectionListener', nativeType='nsISelectionListener')
 addExternalIface('nsIStreamListener', nativeType='nsIStreamListener', notflattened=True)
 addExternalIface('nsISupports', nativeType='nsISupports')
 addExternalIface('nsIDocShell', nativeType='nsIDocShell', notflattened=True)
 addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
 addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -9647,17 +9647,17 @@ class CGEnumerateOwnProperties(CGAbstrac
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'wrapper'),
                 Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('JS::AutoIdVector&', 'props')]
         CGAbstractStaticMethod.__init__(self, descriptor,
                                         "EnumerateOwnProperties", "bool", args)
 
     def definition_body(self):
-        return "return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);\n"
+        return "return js::GetProxyHandler(obj)->ownPropertyKeys(cx, wrapper, props);\n"
 
 
 class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod):
     """
     An implementation of Xray EnumerateOwnProperties stuff for things
     that have a newresolve hook.
     """
     def __init__(self, descriptor):
@@ -10405,17 +10405,17 @@ class CGDOMJSProxyHandler_ownPropNames(C
                   }
                 }
                 """)
         else:
             addIndices = ""
 
         if UseHolderForUnforgeable(self.descriptor):
             addUnforgeable = dedent("""
-                if (!js::GetPropertyNames(cx, ${holder}, flags, &props)) {
+                if (!js::GetPropertyKeys(cx, ${holder}, flags, &props)) {
                   return false;
                 }
                 """)
             addUnforgeable = CallOnUnforgeableHolder(self.descriptor,
                                                      addUnforgeable,
                                                      "isXray")
         else:
             addUnforgeable = ""
@@ -10442,17 +10442,17 @@ class CGDOMJSProxyHandler_ownPropNames(C
             """
             bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
             $*{addIndices}
             $*{addUnforgeable}
             $*{addNames}
 
             JS::Rooted<JSObject*> expando(cx);
             if (!isXray && (expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
-                !js::GetPropertyNames(cx, expando, flags, &props)) {
+                !js::GetPropertyKeys(cx, expando, flags, &props)) {
               return false;
             }
 
             return true;
             """,
             addIndices=addIndices,
             addUnforgeable=addUnforgeable,
             addNames=addNames)
@@ -10756,17 +10756,17 @@ class CGDOMJSProxyHandler_slice(ClassMet
                 Argument('JS::Handle<JSObject*>', 'proxy'),
                 Argument('uint32_t', 'begin'),
                 Argument('uint32_t', 'end'),
                 Argument('JS::Handle<JSObject*>', 'array')]
         ClassMethod.__init__(self, "slice", "bool", args, virtual=True, override=True, const=True)
         self.descriptor = descriptor
 
     def getBody(self):
-        # Just like getOwnPropertyNames we'll assume that we have no holes, so
+        # Just like ownPropertyKeys we'll assume that we have no holes, so
         # we have all properties from 0 to length.  If that ever changes
         # (unlikely), we'll need to do something a bit more clever with how we
         # forward on to our ancestor.
 
         templateValues = {
             'jsvalRef': 'temp',
             'jsvalHandle': '&temp',
             'obj': 'proxy',
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -273,36 +273,36 @@ bool
 BaseDOMProxyHandler::enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
                                AutoIdVector& props) const
 {
   JS::Rooted<JSObject*> proto(cx);
   if (!JS_GetPrototype(cx, proxy, &proto))  {
     return false;
   }
   return keys(cx, proxy, props) &&
-         (!proto || js::GetPropertyNames(cx, proto, 0, &props));
+         (!proto || js::GetPropertyKeys(cx, proto, 0, &props));
 }
 
 bool
 BaseDOMProxyHandler::watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                            JS::Handle<JSObject*> callable) const
 {
   return js::WatchGuts(cx, proxy, id, callable);
 }
 
 bool
 BaseDOMProxyHandler::unwatch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const
 {
   return js::UnwatchGuts(cx, proxy, id);
 }
 
 bool
-BaseDOMProxyHandler::getOwnPropertyNames(JSContext* cx,
-                                         JS::Handle<JSObject*> proxy,
-                                         JS::AutoIdVector& props) const
+BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx,
+                                     JS::Handle<JSObject*> proxy,
+                                     JS::AutoIdVector& props) const
 {
   return ownPropNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN, props);
 }
 
 bool
 BaseDOMProxyHandler::keys(JSContext* cx,
                           JS::Handle<JSObject*> proxy,
                           JS::AutoIdVector& props) const
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -60,29 +60,29 @@ public:
   bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
                                 JS::Handle<jsid> id,
                                 JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
 
   bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
              JS::Handle<JSObject*> callable) const MOZ_OVERRIDE;
   bool unwatch(JSContext* cx, JS::Handle<JSObject*> proxy,
                JS::Handle<jsid> id) const MOZ_OVERRIDE;
-  virtual bool getOwnPropertyNames(JSContext* cx, JS::Handle<JSObject*> proxy,
-                                   JS::AutoIdVector &props) const MOZ_OVERRIDE;
+  virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
+                               JS::AutoIdVector &props) const MOZ_OVERRIDE;
   // We override keys() and implement it directly instead of using the
   // default implementation, which would getOwnPropertyNames and then
   // filter out the non-enumerable ones.  This avoids doing
   // unnecessary work during enumeration.
   virtual bool keys(JSContext* cx, JS::Handle<JSObject*> proxy,
                     JS::AutoIdVector &props) const MOZ_OVERRIDE;
 
 protected:
-  // Hook for subclasses to implement shared getOwnPropertyNames()/keys()
+  // Hook for subclasses to implement shared ownPropertyKeys()/keys()
   // functionality.  The "flags" argument is either JSITER_OWNONLY (for keys())
-  // or JSITER_OWNONLY | JSITER_HIDDEN (for getOwnPropertyNames()).
+  // or JSITER_OWNONLY | JSITER_HIDDEN (for ownPropertyKeys()).
   virtual bool ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy,
                             unsigned flags,
                             JS::AutoIdVector& props) const = 0;
 
   // Hook for subclasses to allow set() to ignore named props while other things
   // that look at property descriptors see them.  This is intentionally not
   // named getOwnPropertyDescriptor to avoid subclasses that override it hiding
   // our public getOwnPropertyDescriptor.
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -11,16 +11,17 @@
 #include "nsThreadUtils.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/BluetoothAdapterBinding.h"
 #include "mozilla/dom/BluetoothDeviceEvent.h"
 #include "mozilla/dom/BluetoothDiscoveryStateChangedEvent.h"
 #include "mozilla/dom/BluetoothStatusChangedEvent.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/LazyIdleThread.h"
 
 #include "BluetoothAdapter.h"
 #include "BluetoothDevice.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 #include "BluetoothUtils.h"
@@ -765,17 +766,17 @@ BluetoothAdapter::IsConnected(const uint
   }
   bs->IsConnected(aServiceUuid, results);
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
-                           nsIDOMBlob* aBlob, ErrorResult& aRv)
+                           File& aBlob, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
@@ -785,25 +786,25 @@ BluetoothAdapter::SendFile(const nsAStri
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     // In-process transfer
-    bs->SendFile(aDeviceAddress, aBlob, results);
+    bs->SendFile(aDeviceAddress, &aBlob, results);
   } else {
     ContentChild *cc = ContentChild::GetSingleton();
     if (!cc) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
-    BlobChild* actor = cc->GetOrCreateActorForBlob(aBlob);
+    BlobChild* actor = cc->GetOrCreateActorForBlob(&aBlob);
     if (!actor) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
     bs->SendFile(aDeviceAddress, nullptr, actor, results);
   }
 
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -10,16 +10,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "BluetoothCommon.h"
 #include "BluetoothPropertyContainer.h"
 #include "nsCOMPtr.h"
 
 namespace mozilla {
 namespace dom {
+class File;
 class DOMRequest;
 struct MediaMetaData;
 struct MediaPlayStatus;
 }
 }
 
 BEGIN_BLUETOOTH_NAMESPACE
 
@@ -128,17 +129,17 @@ public:
   already_AddRefed<DOMRequest>
     IsConnected(const uint16_t aServiceUuid,
                 ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
     GetConnectedDevices(uint16_t aServiceUuid, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
-    SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob,
+    SendFile(const nsAString& aDeviceAddress, File& aBlob,
              ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     StopSendingFile(const nsAString& aDeviceAddress, ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     ConfirmReceivingFile(const nsAString& aDeviceAddress, bool aConfirmation,
                          ErrorResult& aRv);
 
   already_AddRefed<DOMRequest> ConnectSco(ErrorResult& aRv);
--- a/dom/bluetooth/bluedroid/BluetoothOppManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothOppManager.cpp
@@ -10,36 +10,37 @@
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
 #include "BluetoothUuid.h"
 #include "ObexBase.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/ipc/BlobParent.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsAutoPtr.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "nsIDOMFile.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsIMIMEService.h"
 #include "nsIOutputStream.h"
 #include "nsIVolumeService.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 
 #define TARGET_SUBDIR "Download/Bluetooth/"
 
 USING_BLUETOOTH_NAMESPACE
 using namespace mozilla;
+using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
 namespace {
 // Sending system message "bluetooth-opp-update-progress" every 50kb
 static const uint32_t kUpdateProgressBase = 50 * 1024;
 
 /*
  * The format of the header of an PUT request is
@@ -344,17 +345,18 @@ BluetoothOppManager::StartSendingNextFil
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               BlobParent* aActor)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsCOMPtr<nsIDOMBlob> blob = aActor->GetBlob();
+  nsRefPtr<FileImpl> impl = aActor->GetBlobImpl();
+  nsCOMPtr<nsIDOMBlob> blob = new File(nullptr, impl);
 
   return SendFile(aDeviceAddress, blob.get());
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               nsIDOMBlob* aBlob)
 {
--- a/dom/bluetooth/bluez/BluetoothOppManager.cpp
+++ b/dom/bluetooth/bluez/BluetoothOppManager.cpp
@@ -9,37 +9,38 @@
 
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
 #include "BluetoothUuid.h"
 #include "ObexBase.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsAutoPtr.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "nsIDOMFile.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsIMIMEService.h"
 #include "nsIOutputStream.h"
 #include "nsIVolumeService.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 
 #define TARGET_SUBDIR "Download/Bluetooth/"
 
 USING_BLUETOOTH_NAMESPACE
 using namespace mozilla;
+using namespace mozilla::dom;
 using namespace mozilla::ipc;
 using mozilla::TimeDuration;
 using mozilla::TimeStamp;
 
 namespace {
 // Sending system message "bluetooth-opp-update-progress" every 50kb
 static const uint32_t kUpdateProgressBase = 50 * 1024;
 
@@ -366,17 +367,18 @@ BluetoothOppManager::StartSendingNextFil
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               BlobParent* aActor)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsCOMPtr<nsIDOMBlob> blob = aActor->GetBlob();
+  nsRefPtr<FileImpl> impl = aActor->GetBlobImpl();
+  nsCOMPtr<nsIDOMBlob> blob = new File(nullptr, impl);
 
   return SendFile(aDeviceAddress, blob.get());
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               nsIDOMBlob* aBlob)
 {
--- a/dom/browser-element/BrowserElementParent.jsm
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -575,17 +575,18 @@ BrowserElementParent.prototype = {
 
     if ('successRv' in data.json) {
       debug("Successful gotDOMRequestResult.");
       let clientObj = Cu.cloneInto(data.json.successRv, this._window);
       Services.DOMRequest.fireSuccess(req, clientObj);
     }
     else {
       debug("Got error in gotDOMRequestResult.");
-      Services.DOMRequest.fireErrorAsync(req, data.json.errorMsg);
+      Services.DOMRequest.fireErrorAsync(req,
+        Cu.cloneInto(data.json.errorMsg, this._window));
     }
   },
 
   _setVisible: function(visible) {
     this._sendAsyncMsg('set-visible', {visible: visible});
     this._frameLoader.visible = visible;
   },
 
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -5,27 +5,27 @@
 #include "DOMCameraControl.h"
 #include "base/basictypes.h"
 #include "nsCOMPtr.h"
 #include "nsDOMClassInfo.h"
 #include "nsHashPropertyBag.h"
 #include "nsThread.h"
 #include "DeviceStorage.h"
 #include "DeviceStorageFileDescriptor.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/MediaManager.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "nsIAppsService.h"
 #include "nsIObserverService.h"
 #include "nsIDOMDeviceStorage.h"
 #include "nsIDOMEventListener.h"
 #include "nsIScriptSecurityManager.h"
-#include "nsDOMFile.h"
 #include "Navigator.h"
 #include "nsXULAppAPI.h"
 #include "DOMCameraManager.h"
 #include "DOMCameraCapabilities.h"
 #include "CameraCommon.h"
 #include "nsGlobalWindow.h"
 #include "CameraPreviewMediaStream.h"
 #include "mozilla/dom/CameraUtilBinding.h"
@@ -1432,33 +1432,35 @@ nsDOMCameraControl::OnFacesDetected(cons
 
   DispatchTrustedEvent(event);
 }
 
 void
 nsDOMCameraControl::OnTakePictureComplete(nsIDOMBlob* aPicture)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aPicture != nullptr);
+  MOZ_ASSERT(aPicture);
 
   nsRefPtr<Promise> promise = mTakePicturePromise.forget();
   if (promise) {
     nsCOMPtr<nsIDOMBlob> picture = aPicture;
     promise->MaybeResolve(picture);
   }
 
+  nsRefPtr<File> blob = static_cast<File*>(aPicture);
+
   nsRefPtr<CameraTakePictureCallback> cb = mTakePictureOnSuccessCb.forget();
   mTakePictureOnErrorCb = nullptr;
   if (cb) {
     ErrorResult ignored;
-    cb->Call(aPicture, ignored);
+    cb->Call(*blob, ignored);
   }
 
   BlobEventInit eventInit;
-  eventInit.mData = aPicture;
+  eventInit.mData = blob;
 
   nsRefPtr<BlobEvent> event = BlobEvent::Constructor(this,
                                                      NS_LITERAL_STRING("picture"),
                                                      eventInit);
 
   DispatchTrustedEvent(event);
 }
 
--- a/dom/camera/DOMCameraControlListener.cpp
+++ b/dom/camera/DOMCameraControlListener.cpp
@@ -1,19 +1,19 @@
 /* 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 "DOMCameraControlListener.h"
 #include "nsThreadUtils.h"
-#include "nsDOMFile.h"
 #include "CameraCommon.h"
 #include "DOMCameraControl.h"
 #include "CameraPreviewMediaStream.h"
 #include "mozilla/dom/CameraManagerBinding.h"
+#include "mozilla/dom/File.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 DOMCameraControlListener::DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl,
                                                    CameraPreviewMediaStream* aStream)
   : mDOMCameraControl(new nsMainThreadPtrHolder<nsDOMCameraControl>(aDOMCameraControl))
   , mStream(aStream)
@@ -343,19 +343,20 @@ DOMCameraControlListener::OnTakePictureC
       , mLength(aLength)
       , mMimeType(aMimeType)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
       nsCOMPtr<nsIDOMBlob> picture =
-        DOMFile::CreateMemoryFile(static_cast<void*>(mData),
-                                  static_cast<uint64_t>(mLength),
-                                  mMimeType);
+        File::CreateMemoryFile(mDOMCameraControl,
+                               static_cast<void*>(mData),
+                               static_cast<uint64_t>(mLength),
+                               mMimeType);
       aDOMCameraControl->OnTakePictureComplete(picture);
     }
 
   protected:
     uint8_t* mData;
     uint32_t mLength;
     nsString mMimeType;
   };
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3086,21 +3086,28 @@ CanvasRenderingContext2D::GetHitRegionRe
  */
 struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcessor
 {
   typedef CanvasRenderingContext2D::ContextState ContextState;
 
   virtual void SetText(const char16_t* text, int32_t length, nsBidiDirection direction)
   {
     mFontgrp->UpdateUserFonts(); // ensure user font generation is current
+    // adjust flags for current direction run
+    uint32_t flags = mTextRunFlags;
+    if (direction & 1) {
+      flags |= gfxTextRunFactory::TEXT_IS_RTL;
+    } else {
+      flags &= ~gfxTextRunFactory::TEXT_IS_RTL;
+    }
     mTextRun = mFontgrp->MakeTextRun(text,
                                      length,
                                      mThebes,
                                      mAppUnitsPerDevPixel,
-                                     direction==NSBIDI_RTL ? gfxTextRunFactory::TEXT_IS_RTL : 0);
+                                     flags);
   }
 
   virtual nscoord GetWidth()
   {
     gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText(0,
                                                                mTextRun->GetLength(),
                                                                mDoMeasureBoundingBox ?
                                                                  gfxFont::TIGHT_INK_EXTENTS :
@@ -3116,34 +3123,38 @@ struct MOZ_STACK_CLASS CanvasBidiProcess
     }
 
     return NSToCoordRound(textRunMetrics.mAdvanceWidth);
   }
 
   virtual void DrawText(nscoord xOffset, nscoord width)
   {
     gfxPoint point = mPt;
-    point.x += xOffset;
+    bool rtl = mTextRun->IsRightToLeft();
+    bool verticalRun = mTextRun->IsVertical();
+
+    gfxFloat& inlineCoord = verticalRun ? point.y : point.x;
+    inlineCoord += xOffset;
 
     // offset is given in terms of left side of string
-    if (mTextRun->IsRightToLeft()) {
+    if (rtl) {
       // Bug 581092 - don't use rounded pixel width to advance to
       // right-hand end of run, because this will cause different
       // glyph positioning for LTR vs RTL drawing of the same
       // glyph string on OS X and DWrite where textrun widths may
       // involve fractional pixels.
       gfxTextRun::Metrics textRunMetrics =
         mTextRun->MeasureText(0,
                               mTextRun->GetLength(),
                               mDoMeasureBoundingBox ?
                                   gfxFont::TIGHT_INK_EXTENTS :
                                   gfxFont::LOOSE_INK_EXTENTS,
                               mThebes,
                               nullptr);
-      point.x += textRunMetrics.mAdvanceWidth;
+      inlineCoord += textRunMetrics.mAdvanceWidth;
       // old code was:
       //   point.x += width * mAppUnitsPerDevPixel;
       // TODO: restore this if/when we move to fractional coords
       // throughout the text layout process
     }
 
     uint32_t numRuns;
     const gfxTextRun::GlyphRun *runs = mTextRun->GetGlyphRuns(&numRuns);
@@ -3152,16 +3163,25 @@ struct MOZ_STACK_CLASS CanvasBidiProcess
     Point baselineOrigin =
       Point(point.x * devUnitsPerAppUnit, point.y * devUnitsPerAppUnit);
 
     float advanceSum = 0;
 
     mCtx->EnsureTarget();
     for (uint32_t c = 0; c < numRuns; c++) {
       gfxFont *font = runs[c].mFont;
+
+      bool verticalFont =
+        runs[c].mOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
+
+      const float& baselineOriginInline =
+        verticalFont ? baselineOrigin.y : baselineOrigin.x;
+      const float& baselineOriginBlock =
+        verticalFont ? baselineOrigin.x : baselineOrigin.y;
+
       uint32_t endRun = 0;
       if (c + 1 < numRuns) {
         endRun = runs[c + 1].mCharacterOffset;
       } else {
         endRun = mTextRun->GetLength();
       }
 
       const gfxTextRun::CompressedGlyph *glyphs = mTextRun->GetCharacterGlyphs();
@@ -3169,70 +3189,100 @@ struct MOZ_STACK_CLASS CanvasBidiProcess
       RefPtr<ScaledFont> scaledFont =
         gfxPlatform::GetPlatform()->GetScaledFontForFont(mCtx->mTarget, font);
 
       if (!scaledFont) {
         // This can occur when something switched DirectWrite off.
         return;
       }
 
+      AutoRestoreTransform sidewaysRestore;
+      if (runs[c].mOrientation ==
+          gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT) {
+        sidewaysRestore.Init(mCtx->mTarget);
+        // TODO: The baseline adjustment here is kinda ad-hoc; eventually
+        // perhaps we should check for horizontal and vertical baseline data
+        // in the font, and adjust accordingly.
+        // (The same will be true for HTML text layout.)
+        const gfxFont::Metrics& metrics = mTextRun->GetFontGroup()->
+          GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal);
+        mCtx->mTarget->SetTransform(mCtx->mTarget->GetTransform().Copy().
+          PreTranslate(baselineOrigin).      // translate origin for rotation
+          PreRotate(gfx::Float(M_PI / 2.0)). // turn 90deg clockwise
+          PreTranslate(-baselineOrigin).     // undo the translation
+          PreTranslate(Point(0, metrics.emAscent - metrics.emDescent) / 2));
+                              // and offset the (alphabetic) baseline of the
+                              // horizontally-shaped text from the (centered)
+                              // default baseline used for vertical
+      }
+
       RefPtr<GlyphRenderingOptions> renderingOptions = font->GetGlyphRenderingOptions();
 
       GlyphBuffer buffer;
 
       std::vector<Glyph> glyphBuf;
 
+      // TODO:
+      // This more-or-less duplicates the code found in gfxTextRun::Draw
+      // and the gfxFont methods that uses (Draw, DrawGlyphs, DrawOneGlyph);
+      // it would be nice to refactor and share that code.
       for (uint32_t i = runs[c].mCharacterOffset; i < endRun; i++) {
         Glyph newGlyph;
+
+        float& inlinePos =
+          verticalFont ? newGlyph.mPosition.y : newGlyph.mPosition.x;
+        float& blockPos =
+          verticalFont ? newGlyph.mPosition.x : newGlyph.mPosition.y;
+
         if (glyphs[i].IsSimpleGlyph()) {
           newGlyph.mIndex = glyphs[i].GetSimpleGlyph();
-          if (mTextRun->IsRightToLeft()) {
-            newGlyph.mPosition.x = baselineOrigin.x - advanceSum -
+          if (rtl) {
+            inlinePos = baselineOriginInline - advanceSum -
               glyphs[i].GetSimpleAdvance() * devUnitsPerAppUnit;
           } else {
-            newGlyph.mPosition.x = baselineOrigin.x + advanceSum;
+            inlinePos = baselineOriginInline + advanceSum;
           }
-          newGlyph.mPosition.y = baselineOrigin.y;
+          blockPos = baselineOriginBlock;
           advanceSum += glyphs[i].GetSimpleAdvance() * devUnitsPerAppUnit;
           glyphBuf.push_back(newGlyph);
           continue;
         }
 
         if (!glyphs[i].GetGlyphCount()) {
           continue;
         }
 
-        gfxTextRun::DetailedGlyph *detailedGlyphs =
-          mTextRun->GetDetailedGlyphs(i);
+        const gfxTextRun::DetailedGlyph *d = mTextRun->GetDetailedGlyphs(i);
 
         if (glyphs[i].IsMissing()) {
           newGlyph.mIndex = 0;
-          if (mTextRun->IsRightToLeft()) {
-            newGlyph.mPosition.x = baselineOrigin.x - advanceSum -
-              detailedGlyphs[0].mAdvance * devUnitsPerAppUnit;
+          if (rtl) {
+            inlinePos = baselineOriginInline - advanceSum -
+              d->mAdvance * devUnitsPerAppUnit;
           } else {
-            newGlyph.mPosition.x = baselineOrigin.x + advanceSum;
+            inlinePos = baselineOriginInline + advanceSum;
           }
-          newGlyph.mPosition.y = baselineOrigin.y;
-          advanceSum += detailedGlyphs[0].mAdvance * devUnitsPerAppUnit;
+          blockPos = baselineOriginBlock;
+          advanceSum += d->mAdvance * devUnitsPerAppUnit;
           glyphBuf.push_back(newGlyph);
           continue;
         }
 
-        for (uint32_t c = 0; c < glyphs[i].GetGlyphCount(); c++) {
-          newGlyph.mIndex = detailedGlyphs[c].mGlyphID;
-          if (mTextRun->IsRightToLeft()) {
-            newGlyph.mPosition.x = baselineOrigin.x + detailedGlyphs[c].mXOffset * devUnitsPerAppUnit -
-              advanceSum - detailedGlyphs[c].mAdvance * devUnitsPerAppUnit;
+        for (uint32_t c = 0; c < glyphs[i].GetGlyphCount(); c++, d++) {
+          newGlyph.mIndex = d->mGlyphID;
+          if (rtl) {
+            inlinePos = baselineOriginInline - advanceSum -
+              d->mAdvance * devUnitsPerAppUnit;
           } else {
-            newGlyph.mPosition.x = baselineOrigin.x + detailedGlyphs[c].mXOffset * devUnitsPerAppUnit + advanceSum;
+            inlinePos = baselineOriginInline + advanceSum;
           }
-          newGlyph.mPosition.y = baselineOrigin.y + detailedGlyphs[c].mYOffset * devUnitsPerAppUnit;
+          inlinePos += d->mXOffset * devUnitsPerAppUnit;
+          blockPos = baselineOriginBlock + d->mYOffset * devUnitsPerAppUnit;
           glyphBuf.push_back(newGlyph);
-          advanceSum += detailedGlyphs[c].mAdvance * devUnitsPerAppUnit;
+          advanceSum += d->mAdvance * devUnitsPerAppUnit;
         }
       }
 
       if (!glyphBuf.size()) {
         // This may happen for glyph runs for a 0 size font.
         continue;
       }
 
@@ -3297,16 +3347,19 @@ struct MOZ_STACK_CLASS CanvasBidiProcess
   CanvasRenderingContext2D::TextDrawOperation mOp;
 
   // context state
   ContextState *mState;
 
   // union of bounding boxes of all runs, needed for shadows
   gfxRect mBoundingBox;
 
+  // flags to use when creating textrun, based on CSS style
+  uint32_t mTextRunFlags;
+
   // true iff the bounding box should be measured
   bool mDoMeasureBoundingBox;
 };
 
 nsresult
 CanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
                                             float aX,
                                             float aY,
@@ -3336,19 +3389,20 @@ CanvasRenderingContext2D::DrawOrMeasureT
 
   // replace all the whitespace characters with U+0020 SPACE
   nsAutoString textToDraw(aRawText);
   TextReplaceWhitespaceCharacters(textToDraw);
 
   // for now, default to ltr if not in doc
   bool isRTL = false;
 
+  nsRefPtr<nsStyleContext> canvasStyle;
   if (mCanvasElement && mCanvasElement->IsInDoc()) {
     // try to find the closest context
-    nsRefPtr<nsStyleContext> canvasStyle =
+    canvasStyle =
       nsComputedDOMStyle::GetStyleContextForElement(mCanvasElement,
                                                     nullptr,
                                                     presShell);
     if (!canvasStyle) {
       return NS_ERROR_FAILURE;
     }
 
     isRTL = canvasStyle->StyleVisibility()->mDirection ==
@@ -3373,16 +3427,24 @@ CanvasRenderingContext2D::DrawOrMeasureT
 
   const ContextState &state = CurrentState();
 
   // This is only needed to know if we can know the drawing bounding box easily.
   bool doCalculateBounds = NeedToCalculateBounds();
 
   CanvasBidiProcessor processor;
 
+  // If we don't have a style context, we can't set up vertical-text flags
+  // (for now, at least; perhaps we need new Canvas API to control this).
+  processor.mTextRunFlags = canvasStyle ?
+    nsLayoutUtils::GetTextRunFlagsForStyle(canvasStyle,
+                                           canvasStyle->StyleFont(),
+                                           canvasStyle->StyleText(),
+                                           0) : 0;
+
   GetAppUnitsValues(&processor.mAppUnitsPerDevPixel, nullptr);
   processor.mPt = gfxPoint(aX, aY);
   processor.mThebes =
     new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
 
   // If we don't have a target then we don't have a transform. A target won't
   // be needed in the case where we're measuring the text size. This allows
   // to avoid creating a target if it's only being used to measure text sizes.
@@ -3439,17 +3501,20 @@ CanvasRenderingContext2D::DrawOrMeasureT
     anchorX = 1;
   }
 
   processor.mPt.x -= anchorX * totalWidth;
 
   // offset pt.y based on text baseline
   processor.mFontgrp->UpdateUserFonts(); // ensure user font generation is current
   const gfxFont::Metrics& fontMetrics =
-    processor.mFontgrp->GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal); // XXX vertical?
+    processor.mFontgrp->GetFirstValidFont()->GetMetrics(
+      ((processor.mTextRunFlags & gfxTextRunFactory::TEXT_ORIENT_MASK) ==
+        gfxTextRunFactory::TEXT_ORIENT_HORIZONTAL)
+      ? gfxFont::eHorizontal : gfxFont::eVertical);
 
   gfxFloat anchorY;
 
   switch (state.textBaseline)
   {
   case TextBaseline::HANGING:
       // fall through; best we can do with the information available
   case TextBaseline::TOP:
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -85,18 +85,19 @@ ContactManager.prototype = {
     this.__DOM_IMPL__.setEventHandler("oncontactchange", aHandler);
   },
 
   get oncontactchange() {
     return this.__DOM_IMPL__.getEventHandler("oncontactchange");
   },
 
   _convertContact: function(aContact) {
-    let newContact = new this._window.mozContact(aContact.properties);
-    newContact.setMetadata(aContact.id, aContact.published, aContact.updated);
+    let contact = Cu.cloneInto(aContact, this._window);
+    let newContact = new this._window.mozContact(contact.properties);
+    newContact.setMetadata(contact.id, contact.published, contact.updated);
     return newContact;
   },
 
   _convertContacts: function(aContacts) {
     let contacts = new this._window.Array();
     for (let i in aContacts) {
       contacts.push(this._convertContact(aContacts[i]));
     }
--- a/dom/contacts/tests/test_contacts_blobs.html
+++ b/dom/contacts/tests/test_contacts_blobs.html
@@ -83,24 +83,24 @@ var properties2 = {
 };
 
 var sample_id1;
 var createResult1;
 var findResult1;
 
 function verifyBlob(blob1, blob2, isLast)
 {
-  is(blob1 instanceof SpecialPowers.Ci.nsIDOMBlob, true,
-     "blob1 is an instance of nsIDOMBlob");
-  is(blob2 instanceof SpecialPowers.Ci.nsIDOMBlob, true,
-     "blob2 is an instance of nsIDOMBlob");
-  isnot(blob1 instanceof SpecialPowers.Ci.nsIDOMFile, true,
-     "blob1 is an instance of nsIDOMFile");
-  isnot(blob2 instanceof SpecialPowers.Ci.nsIDOMFile, true,
-     "blob2 is an instance of nsIDOMFile");
+  is(blob1 instanceof Blob, true,
+     "blob1 is an instance of DOMBlob");
+  is(blob2 instanceof Blob, true,
+     "blob2 is an instance of DOMBlob");
+  isnot(blob1 instanceof File, true,
+     "blob1 is an instance of File");
+  isnot(blob2 instanceof File, true,
+     "blob2 is an instance of File");
   ise(blob1.size, blob2.size, "Same size");
   ise(blob1.type, blob2.type, "Same type");
 
   var buffer1;
   var buffer2;
 
   var reader1 = new FileReader();
   reader1.readAsArrayBuffer(blob2);
--- a/dom/devicestorage/DeviceStorageRequestChild.cpp
+++ b/dom/devicestorage/DeviceStorageRequestChild.cpp
@@ -2,17 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "DeviceStorageRequestChild.h"
 #include "DeviceStorageFileDescriptor.h"
 #include "nsDeviceStorage.h"
-#include "nsDOMFile.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 
 namespace mozilla {
 namespace dom {
 namespace devicestorage {
 
 DeviceStorageRequestChild::DeviceStorageRequestChild()
   : mCallback(nullptr)
@@ -98,22 +98,25 @@ DeviceStorageRequestChild::
       mRequest->FireSuccess(result);
       break;
     }
 
     case DeviceStorageResponseValue::TBlobResponse:
     {
       BlobResponse r = aValue;
       BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
-      nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
+      nsRefPtr<FileImpl> bloblImpl = actor->GetBlobImpl();
+      nsRefPtr<File> blob = new File(mRequest->GetParentObject(), bloblImpl);
+
+      AutoJSContext cx;
 
-      nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob);
-      AutoJSContext cx;
-      JS::Rooted<JS::Value> result(cx,
-        InterfaceToJsval(window, file, &NS_GET_IID(nsIDOMFile)));
+      JS::Rooted<JSObject*> obj(cx, blob->WrapObject(cx));
+      MOZ_ASSERT(obj);
+
+      JS::Rooted<JS::Value> result(cx, JS::ObjectValue(*obj));
       mRequest->FireSuccess(result);
       break;
     }
 
     case DeviceStorageResponseValue::TFreeSpaceStorageResponse:
     {
       FreeSpaceStorageResponse r = aValue;
       AutoJSContext cx;
--- a/dom/devicestorage/DeviceStorageRequestParent.cpp
+++ b/dom/devicestorage/DeviceStorageRequestParent.cpp
@@ -1,18 +1,18 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DeviceStorageRequestParent.h"
-#include "nsDOMFile.h"
 #include "nsIMIMEService.h"
 #include "nsCExternalHandlerService.h"
 #include "mozilla/unused.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "ContentParent.h"
 #include "nsProxyRelease.h"
 #include "AppProcessChecker.h"
 #include "mozilla/Preferences.h"
 #include "nsNetCID.h"
 
 namespace mozilla {
@@ -39,20 +39,20 @@ DeviceStorageRequestParent::Dispatch()
     case DeviceStorageParams::TDeviceStorageAddParams:
     {
       DeviceStorageAddParams p = mParams;
 
       nsRefPtr<DeviceStorageFile> dsf =
         new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
 
       BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
-      nsCOMPtr<nsIDOMBlob> blob = bp->GetBlob();
+      nsRefPtr<FileImpl> blobImpl = bp->GetBlobImpl();
 
       nsCOMPtr<nsIInputStream> stream;
-      blob->GetInternalStream(getter_AddRefs(stream));
+      blobImpl->GetInternalStream(getter_AddRefs(stream));
 
       nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream,
                                                           DEVICE_STORAGE_REQUEST_CREATE);
 
       nsCOMPtr<nsIEventTarget> target
         = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       MOZ_ASSERT(target);
       target->Dispatch(r, NS_DISPATCH_NORMAL);
@@ -62,20 +62,20 @@ DeviceStorageRequestParent::Dispatch()
     case DeviceStorageParams::TDeviceStorageAppendParams:
     {
       DeviceStorageAppendParams p = mParams;
 
       nsRefPtr<DeviceStorageFile> dsf =
         new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
 
       BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
-      nsCOMPtr<nsIDOMBlob> blob = bp->GetBlob();
+      nsRefPtr<FileImpl> blobImpl = bp->GetBlobImpl();
 
       nsCOMPtr<nsIInputStream> stream;
-      blob->GetInternalStream(getter_AddRefs(stream));
+      blobImpl->GetInternalStream(getter_AddRefs(stream));
 
       nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream,
                                                           DEVICE_STORAGE_REQUEST_APPEND);
 
       nsCOMPtr<nsIEventTarget> target
         = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       MOZ_ASSERT(target);
       target->Dispatch(r, NS_DISPATCH_NORMAL);
@@ -517,19 +517,19 @@ nsresult
 DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsString mime;
   CopyASCIItoUTF16(mMimeType, mime);
 
   nsString fullPath;
   mFile->GetFullPath(fullPath);
-  nsCOMPtr<nsIDOMBlob> blob = new DOMFile(
-    new DOMFileImplFile(fullPath, mime, mLength, mFile->mFile,
-                        mLastModificationDate));
+  nsRefPtr<File> blob = new File(nullptr,
+    new FileImplFile(fullPath, mime, mLength, mFile->mFile,
+                     mLastModificationDate));
 
   ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
   BlobParent* actor = cp->GetOrCreateActorForBlob(blob);
   if (!actor) {
     ErrorResponse response(NS_LITERAL_STRING(POST_ERROR_EVENT_UNKNOWN));
     unused << mParent->Send__delete__(mParent, response);
     return NS_OK;
   }
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -31,18 +31,16 @@
 #include "nsArrayUtils.h"
 #include "nsAutoPtr.h"
 #include "nsGlobalWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIFile.h"
 #include "nsIDirectoryEnumerator.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceDefs.h"
-#include "nsIDOMFile.h"
-#include "nsDOMBlobBuilder.h"
 #include "nsNetUtil.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIPrincipal.h"
 #include "nsJSUtils.h"
 #include "nsContentUtils.h"
 #include "nsXULAppAPI.h"
 #include "DeviceStorageFileDescriptor.h"
 #include "DeviceStorageRequestChild.h"
@@ -1800,20 +1798,20 @@ nsIFileToJsval(nsPIDOMWindow* aWindow, D
   aFile->GetFullPath(fullPath);
 
   // This check is useful to know if somewhere the DeviceStorageFile
   // has not been properly set. Mimetype is not checked because it can be
   // empty.
   MOZ_ASSERT(aFile->mLength != UINT64_MAX);
   MOZ_ASSERT(aFile->mLastModifiedDate != UINT64_MAX);
 
-  nsCOMPtr<nsIDOMBlob> blob = new DOMFile(
-    new DOMFileImplFile(fullPath, aFile->mMimeType,
-                        aFile->mLength, aFile->mFile,
-                        aFile->mLastModifiedDate));
+  nsCOMPtr<nsIDOMBlob> blob = new File(aWindow,
+    new FileImplFile(fullPath, aFile->mMimeType,
+                     aFile->mLength, aFile->mFile,
+                     aFile->mLastModifiedDate));
   return InterfaceToJsval(aWindow, blob, &NS_GET_IID(nsIDOMBlob));
 }
 
 bool
 StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString,
               JS::MutableHandle<JS::Value> result)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -2475,17 +2473,17 @@ public:
 private:
   nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
   nsRefPtr<DOMRequest> mRequest;
 };
 
 class WriteFileEvent : public nsRunnable
 {
 public:
-  WriteFileEvent(DOMFileImpl* aBlobImpl,
+  WriteFileEvent(FileImpl* aBlobImpl,
                  DeviceStorageFile *aFile,
                  already_AddRefed<DOMRequest> aRequest,
                  int32_t aRequestType)
     : mBlobImpl(aBlobImpl)
     , mFile(aFile)
     , mRequest(aRequest)
     , mRequestType(aRequestType)
   {
@@ -2541,17 +2539,17 @@ public:
     nsString fullPath;
     mFile->GetFullPath(fullPath);
     nsCOMPtr<nsIRunnable> event =
       new PostResultEvent(mRequest.forget(), fullPath);
     return NS_DispatchToMainThread(event);
   }
 
 private:
-  nsRefPtr<DOMFileImpl> mBlobImpl;
+  nsRefPtr<FileImpl> mBlobImpl;
   nsRefPtr<DeviceStorageFile> mFile;
   nsRefPtr<DOMRequest> mRequest;
   int32_t mRequestType;
 };
 
 
 class ReadFileEvent : public nsRunnable
 {
@@ -2909,17 +2907,18 @@ public:
             !typeChecker->Check(mFile->mStorageType, mBlob)) {
           r = new PostErrorEvent(mRequest.forget(),
                                  POST_ERROR_EVENT_ILLEGAL_TYPE);
           return NS_DispatchToCurrentThread(r);
         }
 
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
           BlobChild* actor
-            = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob);
+            = ContentChild::GetSingleton()->GetOrCreateActorForBlob(
+              static_cast<File*>(mBlob.get()));
           if (!actor) {
             return NS_ERROR_FAILURE;
           }
 
           DeviceStorageAddParams params;
           params.blobChild() = actor;
           params.type() = mFile->mStorageType;
           params.storageName() = mFile->mStorageName;
@@ -2927,17 +2926,17 @@ public:
 
           PDeviceStorageRequestChild* child
             = new DeviceStorageRequestChild(mRequest, mFile);
           ContentChild::GetSingleton()
             ->SendPDeviceStorageRequestConstructor(child, params);
           return NS_OK;
         }
 
-        DOMFile* blob = static_cast<DOMFile*>(mBlob.get());
+        File* blob = static_cast<File*>(mBlob.get());
         r = new WriteFileEvent(blob->Impl(), mFile, mRequest.forget(),
                                mRequestType);
         break;
       }
 
       case DEVICE_STORAGE_REQUEST_APPEND:
       {
         if (!mBlob || !mFile->mFile) {
@@ -2954,17 +2953,18 @@ public:
             !typeChecker->Check(mFile->mStorageType, mBlob)) {
           r = new PostErrorEvent(mRequest.forget(),
                                  POST_ERROR_EVENT_ILLEGAL_TYPE);
           return NS_DispatchToCurrentThread(r);
         }
 
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
           BlobChild* actor
-            = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob);
+            = ContentChild::GetSingleton()->GetOrCreateActorForBlob(
+              static_cast<File*>(mBlob.get()));
           if (!actor) {
             return NS_ERROR_FAILURE;
           }
 
           DeviceStorageAppendParams params;
           params.blobChild() = actor;
           params.type() = mFile->mStorageType;
           params.storageName() = mFile->mStorageName;
@@ -2972,17 +2972,17 @@ public:
 
           PDeviceStorageRequestChild* child
             = new DeviceStorageRequestChild(mRequest, mFile);
           ContentChild::GetSingleton()
             ->SendPDeviceStorageRequestConstructor(child, params);
           return NS_OK;
         }
 
-        DOMFile* blob = static_cast<DOMFile*>(mBlob.get());
+        File* blob = static_cast<File*>(mBlob.get());
         r = new WriteFileEvent(blob->Impl(), mFile, mRequest.forget(),
                                mRequestType);
         break;
       }
 
       case DEVICE_STORAGE_REQUEST_READ:
       case DEVICE_STORAGE_REQUEST_WRITE:
       {
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -264,26 +264,26 @@ DataTransfer::SetEffectAllowedInt(uint32
 
 NS_IMETHODIMP
 DataTransfer::GetMozUserCancelled(bool* aUserCancelled)
 {
   *aUserCancelled = MozUserCancelled();
   return NS_OK;
 }
 
-nsDOMFileList*
+FileList*
 DataTransfer::GetFiles(ErrorResult& aRv)
 {
   if (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP &&
       mEventType != NS_PASTE) {
     return nullptr;
   }
 
   if (!mFiles) {
-    mFiles = new nsDOMFileList(static_cast<nsIDOMDataTransfer*>(this));
+    mFiles = new FileList(static_cast<nsIDOMDataTransfer*>(this));
 
     uint32_t count = mItems.Length();
 
     for (uint32_t i = 0; i < count; i++) {
       nsCOMPtr<nsIVariant> variant;
       aRv = MozGetDataAt(NS_ConvertUTF8toUTF16(kFileMime), i, getter_AddRefs(variant));
       if (aRv.Failed()) {
         return nullptr;
@@ -298,17 +298,17 @@ DataTransfer::GetFiles(ErrorResult& aRv)
       if (NS_FAILED(rv))
         continue;
 
       nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
 
       if (!file)
         continue;
 
-      nsRefPtr<DOMFile> domFile = DOMFile::CreateFromFile(file);
+      nsRefPtr<File> domFile = File::CreateFromFile(GetParentObject(), file);
 
       if (!mFiles->Append(domFile)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return nullptr;
       }
     }
   }
 
--- a/dom/events/DataTransfer.h
+++ b/dom/events/DataTransfer.h
@@ -11,18 +11,18 @@
 #include "nsIVariant.h"
 #include "nsIPrincipal.h"
 #include "nsIDOMDataTransfer.h"
 #include "nsIDOMElement.h"
 #include "nsIDragService.h"
 #include "nsCycleCollectionParticipant.h"
 
 #include "nsAutoPtr.h"
-#include "nsDOMFile.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/File.h"
 
 class nsINode;
 class nsITransferable;
 class nsISupportsArray;
 class nsILoadContext;
 
 namespace mozilla {
 
@@ -138,17 +138,17 @@ public:
   void SetDragImage(Element& aElement, int32_t aX, int32_t aY,
                     ErrorResult& aRv);
   already_AddRefed<DOMStringList> Types();
   void GetData(const nsAString& aFormat, nsAString& aData, ErrorResult& aRv);
   void SetData(const nsAString& aFormat, const nsAString& aData,
                ErrorResult& aRv);
   void ClearData(const mozilla::dom::Optional<nsAString>& aFormat,
                  mozilla::ErrorResult& aRv);
-  nsDOMFileList* GetFiles(mozilla::ErrorResult& aRv);
+  FileList* GetFiles(mozilla::ErrorResult& aRv);
   void AddElement(Element& aElement, mozilla::ErrorResult& aRv);
   uint32_t MozItemCount()
   {
     return mItems.Length();
   }
   void GetMozCursor(nsString& aCursor)
   {
     if (mCursorState) {
@@ -273,17 +273,17 @@ protected:
   // Indicates which clipboard type to use for clipboard operations. Ignored for
   // drag and drop.
   int32_t mClipboardType;
 
   // array of items, each containing an array of format->data pairs
   nsTArray<nsTArray<TransferItem> > mItems;
 
   // array of files, containing only the files present in the dataTransfer
-  nsRefPtr<nsDOMFileList> mFiles;
+  nsRefPtr<FileList> mFiles;
 
   // the target of the drag. The drag and dragend events will fire at this.
   nsCOMPtr<mozilla::dom::Element> mDragTarget;
 
   // the custom drag image and coordinates within the image. If mDragImage is
   // null, the default image is created from the drag target.
   nsCOMPtr<mozilla::dom::Element> mDragImage;
   uint32_t mDragImageX;
--- a/dom/events/test/test_eventctors.html
+++ b/dom/events/test/test_eventctors.html
@@ -198,17 +198,17 @@ ok(ex, "Shouldn't be able to re-define t
 ex = false;
 ok(!e.isTrusted, "BlobEvent shouldn't be trusted!");
 
 ok(!e.bubbles, "Event shouldn't bubble!");
 ok(!e.cancelable, "Event shouldn't be cancelable!");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
 
-var blob = Blob();
+var blob = new Blob();
 e = new BlobEvent("hello", { bubbles: true, cancelable: true, data: blob });
 is(e.type, "hello", "Wrong event type!");
 ok(!e.isTrusted, "Event shouldn't be trusted!");
 ok(e.bubbles, "Event should bubble!");
 ok(e.cancelable, "Event should be cancelable!");
 is(e.data, blob , "Wrong event.data!");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -3,33 +3,32 @@
  * 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 "Request.h"
 
 #include "nsIUnicodeDecoder.h"
 #include "nsIURI.h"
 
-#include "nsDOMFile.h"
 #include "nsDOMString.h"
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
 #include "nsStreamUtils.h"
 #include "nsStringStream.h"
 
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/EncodingUtils.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/Headers.h"
 #include "mozilla/dom/Fetch.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/URL.h"
 #include "mozilla/dom/workers/bindings/URL.h"
 
 // dom/workers
-#include "File.h"
 #include "WorkerPrivate.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Request)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Request)
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner)
@@ -353,36 +352,27 @@ Request::ConsumeBody(ConsumeType aType, 
       // XXXnsm it is actually possible to avoid these duplicate allocations
       // for the Blob case by having the Blob adopt the stream's memory
       // directly, but I've not added a special case for now.
       //
       // This is similar to nsContentUtils::CreateBlobBuffer, but also deals
       // with worker wrapping.
       uint32_t blobLen = buffer.Length();
       void* blobData = moz_malloc(blobLen);
-      nsCOMPtr<nsIDOMBlob> blob;
+      nsRefPtr<File> blob;
       if (blobData) {
         memcpy(blobData, buffer.BeginReading(), blobLen);
-        blob = DOMFile::CreateMemoryFile(blobData, blobLen,
-                                         NS_ConvertUTF8toUTF16(mMimeType));
+        blob = File::CreateMemoryFile(GetParentObject(), blobData, blobLen,
+                                      NS_ConvertUTF8toUTF16(mMimeType));
       } else {
         aRv = NS_ERROR_OUT_OF_MEMORY;
         return nullptr;
       }
 
-      JS::Rooted<JS::Value> jsBlob(cx);
-      if (NS_IsMainThread()) {
-        aRv = nsContentUtils::WrapNative(cx, blob, &jsBlob);
-        if (aRv.Failed()) {
-          return nullptr;
-        }
-      } else {
-        jsBlob.setObject(*workers::file::CreateBlob(cx, blob));
-      }
-      promise->MaybeResolve(cx, jsBlob);
+      promise->MaybeResolve(blob);
       return promise.forget();
     }
     case CONSUME_JSON: {
       nsString decoded;
       aRv = DecodeUTF8(buffer, decoded);
       if (aRv.Failed()) {
         return nullptr;
       }
--- a/dom/filehandle/FileHandle.cpp
+++ b/dom/filehandle/FileHandle.cpp
@@ -8,21 +8,21 @@
 
 #include "AsyncHelper.h"
 #include "FileHelper.h"
 #include "FileRequest.h"
 #include "FileService.h"
 #include "FileStreamWrappers.h"
 #include "MemoryStreams.h"
 #include "mozilla/dom/EncodingUtils.h"
+#include "mozilla/dom/File.h"
 #include "MutableFile.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsError.h"
-#include "nsIDOMFile.h"
 #include "nsIEventTarget.h"
 #include "nsISeekableStream.h"
 #include "nsNetUtil.h"
 #include "nsString.h"
 #include "nsStringStream.h"
 #include "nsThreadUtils.h"
 #include "xpcpublic.h"
 
@@ -617,27 +617,27 @@ FileHandleBase::GetInputStream(const Arr
   }
 
   *aInputLength = length;
   return stream.forget();
 }
 
 // static
 already_AddRefed<nsIInputStream>
-FileHandleBase::GetInputStream(nsIDOMBlob* aValue, uint64_t* aInputLength,
+FileHandleBase::GetInputStream(const File& aValue, uint64_t* aInputLength,
                                ErrorResult& aRv)
 {
-  uint64_t length;
-  aRv = aValue->GetSize(&length);
+  File& file = const_cast<File&>(aValue);
+  uint64_t length = file.GetSize(aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   nsCOMPtr<nsIInputStream> stream;
-  aRv = aValue->GetInternalStream(getter_AddRefs(stream));
+  aRv = file.GetInternalStream(getter_AddRefs(stream));
   if (aRv.Failed()) {
     return nullptr;
   }
 
   *aInputLength = length;
   return stream.forget();
 }
 
--- a/dom/filehandle/FileHandle.h
+++ b/dom/filehandle/FileHandle.h
@@ -16,21 +16,21 @@
 #include "mozilla/ErrorResult.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIInputStream.h"
 #include "nsIRunnable.h"
 #include "nsTArray.h"
 
 class nsAString;
-class nsIDOMBlob;
 
 namespace mozilla {
 namespace dom {
 
+class File;
 class FileHelper;
 class FileRequestBase;
 class FileService;
 class FinishHelper;
 class MetadataHelper;
 class MutableFileBase;
 
 /**
@@ -235,17 +235,18 @@ protected:
   nsresult
   Finish();
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(const ArrayBuffer& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 
   static already_AddRefed<nsIInputStream>
-  GetInputStream(nsIDOMBlob* aValue, uint64_t* aInputLength, ErrorResult& aRv);
+  GetInputStream(const File& aValue, uint64_t* aInputLength,
+                 ErrorResult& aRv);
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(const nsAString& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 };
 
 class FinishHelper MOZ_FINAL : public nsIRunnable
 {
--- a/dom/filesystem/CreateFileTask.cpp
+++ b/dom/filesystem/CreateFileTask.cpp
@@ -5,34 +5,34 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "CreateFileTask.h"
 
 #include <algorithm>
 
 #include "DOMError.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
-#include "nsDOMFile.h"
 #include "nsIFile.h"
 #include "nsNetUtil.h"
 #include "nsStringGlue.h"
 
 namespace mozilla {
 namespace dom {
 
 uint32_t CreateFileTask::sOutputBufferSize = 0;
 
 CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
                                const nsAString& aPath,
-                               nsIDOMBlob* aBlobData,
+                               File* aBlobData,
                                InfallibleTArray<uint8_t>& aArrayData,
                                bool replace,
                                ErrorResult& aRv)
   : FileSystemTaskBase(aFileSystem)
   , mTargetRealPath(aPath)
   , mReplace(replace)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
@@ -74,19 +74,20 @@ CreateFileTask::CreateFileTask(FileSyste
   auto& data = aParam.data();
 
   if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
     mArrayData = data;
     return;
   }
 
   BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
-  nsCOMPtr<nsIDOMBlob> blobData = bp->GetBlob();
-  MOZ_ASSERT(blobData, "blobData should not be null.");
-  nsresult rv = blobData->GetInternalStream(getter_AddRefs(mBlobStream));
+  nsRefPtr<FileImpl> blobImpl = bp->GetBlobImpl();
+  MOZ_ASSERT(blobImpl, "blobData should not be null.");
+
+  nsresult rv = blobImpl->GetInternalStream(getter_AddRefs(mBlobStream));
   NS_WARN_IF(NS_FAILED(rv));
 }
 
 CreateFileTask::~CreateFileTask()
 {
   MOZ_ASSERT((!mPromise && !mBlobData) || NS_IsMainThread(),
              "mPromise and mBlobData should be released on main thread!");
 
@@ -121,34 +122,34 @@ CreateFileTask::GetRequestParams(const n
   }
   return param;
 }
 
 FileSystemResponseValue
 CreateFileTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
-  nsRefPtr<DOMFile> file = new DOMFile(mTargetFileImpl);
+  nsRefPtr<File> file = new File(mFileSystem->GetWindow(),
+                                       mTargetFileImpl);
   BlobParent* actor = GetBlobParent(file);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
 
 void
 CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   FileSystemFileResponse r = aValue;
   BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
-  nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
-  mTargetFileImpl = static_cast<DOMFile*>(blob.get())->Impl();
+  mTargetFileImpl = actor->GetBlobImpl();
 }
 
 nsresult
 CreateFileTask::Work()
 {
   class AutoClose
   {
   public:
@@ -255,17 +256,17 @@ CreateFileTask::Work()
 
     mBlobStream->Close();
     mBlobStream = nullptr;
 
     if (mFileSystem->IsShutdown()) {
       return NS_ERROR_FAILURE;
     }
 
-    mTargetFileImpl = new DOMFileImplFile(file);
+    mTargetFileImpl = new FileImplFile(file);
     return NS_OK;
   }
 
   // Write file content from array data.
 
   uint32_t written;
   rv = bufferedOutputStream->Write(
     reinterpret_cast<char*>(mArrayData.Elements()),
@@ -274,17 +275,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 DOMFileImplFile(file);
+  mTargetFileImpl = new FileImplFile(file);
   return NS_OK;
 }
 
 void
 CreateFileTask::HandlerCallback()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mFileSystem->IsShutdown()) {
@@ -297,17 +298,17 @@ CreateFileTask::HandlerCallback()
     nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
       mErrorValue);
     mPromise->MaybeRejectBrokenly(domError);
     mPromise = nullptr;
     mBlobData = nullptr;
     return;
   }
 
-  nsCOMPtr<nsIDOMFile> file = new DOMFile(mTargetFileImpl);
+  nsCOMPtr<nsIDOMFile> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
   mPromise->MaybeResolve(file);
   mPromise = nullptr;
   mBlobData = nullptr;
 }
 
 void
 CreateFileTask::GetPermissionAccessType(nsCString& aAccess) const
 {
--- a/dom/filesystem/CreateFileTask.h
+++ b/dom/filesystem/CreateFileTask.h
@@ -6,32 +6,32 @@
 
 #ifndef mozilla_dom_CreateFileTask_h
 #define mozilla_dom_CreateFileTask_h
 
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "nsAutoPtr.h"
 #include "mozilla/ErrorResult.h"
 
-class nsIDOMBlob;
 class nsIInputStream;
 
 namespace mozilla {
 namespace dom {
 
-class DOMFileImpl;
+class File;
+class FileImpl;
 class Promise;
 
 class CreateFileTask MOZ_FINAL
   : public FileSystemTaskBase
 {
 public:
   CreateFileTask(FileSystemBase* aFileSystem,
                  const nsAString& aPath,
-                 nsIDOMBlob* aBlobData,
+                 File* 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.
-  nsCOMPtr<nsIDOMBlob> mBlobData;
+  nsRefPtr<File> mBlobData;
 
   nsCOMPtr<nsIInputStream> mBlobStream;
   InfallibleTArray<uint8_t> mArrayData;
   bool mReplace;
 
-  // This cannot be a DOMFile because this object is created on a different
-  // thread and DOMFile is not thread-safe. Let's use the DOMFileImpl instead.
-  nsRefPtr<DOMFileImpl> mTargetFileImpl;
+  // 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;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CreateFileTask_h
--- a/dom/filesystem/DeviceStorageFileSystem.cpp
+++ b/dom/filesystem/DeviceStorageFileSystem.cpp
@@ -4,21 +4,21 @@
  * 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/DeviceStorageFileSystem.h"
 
 #include "DeviceStorage.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Directory.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/FileSystemUtils.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsDeviceStorage.h"
-#include "nsDOMFile.h"
 #include "nsIFile.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
 DeviceStorageFileSystem::DeviceStorageFileSystem(
   const nsAString& aStorageType,
@@ -109,26 +109,28 @@ 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(DOMFileImpl* aFile, nsAString& aRealPath) const
+DeviceStorageFileSystem::GetRealPath(FileImpl* 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;
-  if (NS_FAILED(aFile->GetMozFullPathInternal(filePath))) {
+  ErrorResult rv;
+  aFile->GetMozFullPathInternal(filePath, rv);
+  if (NS_WARN_IF(rv.Failed())) {
     return false;
   }
 
   return LocalPathToRealPath(filePath, aRealPath);
 }
 
 const nsAString&
 DeviceStorageFileSystem::GetRootName() const
--- a/dom/filesystem/DeviceStorageFileSystem.h
+++ b/dom/filesystem/DeviceStorageFileSystem.h
@@ -32,17 +32,17 @@ public:
 
   virtual nsPIDOMWindow*
   GetWindow() const MOZ_OVERRIDE;
 
   virtual already_AddRefed<nsIFile>
   GetLocalFile(const nsAString& aRealPath) const MOZ_OVERRIDE;
 
   virtual bool
-  GetRealPath(DOMFileImpl* aFile, nsAString& aRealPath) const MOZ_OVERRIDE;
+  GetRealPath(FileImpl* aFile, nsAString& aRealPath) const MOZ_OVERRIDE;
 
   virtual const nsAString&
   GetRootName() const MOZ_OVERRIDE;
 
   virtual bool
   IsSafeFile(nsIFile* aFile) const MOZ_OVERRIDE;
 
   virtual bool
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -96,17 +96,17 @@ Directory::GetName(nsString& aRetval) co
 }
 
 already_AddRefed<Promise>
 Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
                       ErrorResult& aRv)
 {
   nsresult error = NS_OK;
   nsString realPath;
-  nsRefPtr<nsIDOMBlob> blobData;
+  nsRefPtr<File> blobData;
   InfallibleTArray<uint8_t> arrayData;
   bool replace = (aOptions.mIfExists == CreateIfExistsMode::Replace);
 
   // Get the file content.
   if (aOptions.mData.WasPassed()) {
     auto& data = aOptions.mData.Value();
     if (data.IsString()) {
       NS_ConvertUTF16toUTF8 str(data.GetAsString());
@@ -124,18 +124,18 @@ Directory::CreateFile(const nsAString& a
       blobData = data.GetAsBlob();
     }
   }
 
   if (!DOMPathToRealPath(aPath, realPath)) {
     error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
   }
 
-  nsRefPtr<CreateFileTask> task = new CreateFileTask(mFileSystem, realPath,
-    blobData, arrayData, replace, aRv);
+  nsRefPtr<CreateFileTask> task =
+    new CreateFileTask(mFileSystem, realPath, blobData, arrayData, replace, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
   task->SetError(error);
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
 
@@ -188,22 +188,22 @@ Directory::RemoveDeep(const StringOrFile
 }
 
 already_AddRefed<Promise>
 Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
                           ErrorResult& aRv)
 {
   nsresult error = NS_OK;
   nsString realPath;
-  nsRefPtr<DOMFileImpl> file;
+  nsRefPtr<FileImpl> file;
 
   // Check and get the target path.
 
   if (aPath.IsFile()) {
-    file = static_cast<DOMFile*>(aPath.GetAsFile())->Impl();
+    file = aPath.GetAsFile().Impl();
     goto parameters_check_done;
   }
 
   if (aPath.IsString()) {
     if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) {
       error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
     }
     goto parameters_check_done;
--- a/dom/filesystem/Directory.h
+++ b/dom/filesystem/Directory.h
@@ -5,19 +5,19 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Directory_h
 #define mozilla_dom_Directory_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/File.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsDOMFile.h"
 #include "nsPIDOMWindow.h"
 #include "nsWrapperCache.h"
 
 // Resolve the name collision of Microsoft's API name with macros defined in
 // Windows header files. Undefine the macro of CreateDirectory to avoid
 // Directory#CreateDirectory being replaced by Directory#CreateDirectoryW.
 #ifdef CreateDirectory
 #undef CreateDirectory
--- a/dom/filesystem/FileSystemBase.h
+++ b/dom/filesystem/FileSystemBase.h
@@ -11,17 +11,17 @@
 #include "nsString.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class Directory;
-class DOMFileImpl;
+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(DOMFileImpl* aFile, nsAString& aRealPath) const = 0;
+  GetRealPath(FileImpl* 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
@@ -3,24 +3,24 @@
 /* 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/FileSystemTaskBase.h"
 
 #include "nsNetUtil.h" // Stream transport service.
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemRequestParent.h"
 #include "mozilla/dom/FileSystemUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PContent.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/unused.h"
-#include "nsDOMFile.h"
 
 namespace mozilla {
 namespace dom {
 
 FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem)
   : mErrorValue(NS_OK)
   , mFileSystem(aFileSystem)
 {
@@ -165,17 +165,17 @@ FileSystemTaskBase::GetBlobParent(nsIDOM
   nsString mimeType;
   aFile->GetType(mimeType);
   uint64_t fileSize;
   aFile->GetSize(&fileSize);
   uint64_t lastModifiedDate;
   aFile->GetMozLastModifiedDate(&lastModifiedDate);
 
   ContentParent* cp = static_cast<ContentParent*>(mRequestParent->Manager());
-  return cp->GetOrCreateActorForBlob(aFile);
+  return cp->GetOrCreateActorForBlob(static_cast<File*>(aFile));
 }
 
 void
 FileSystemTaskBase::SetError(const nsresult& aErrorValue)
 {
   uint16_t module = NS_ERROR_GET_MODULE(aErrorValue);
   if (module == NS_ERROR_MODULE_DOM_FILESYSTEM ||
       module == NS_ERROR_MODULE_DOM_FILE ||
--- a/dom/filesystem/GetFileOrDirectoryTask.cpp
+++ b/dom/filesystem/GetFileOrDirectoryTask.cpp
@@ -3,22 +3,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GetFileOrDirectoryTask.h"
 
 #include "js/Value.h"
 #include "mozilla/dom/Directory.h"
+#include "mozilla/dom/DOMError.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
-#include "nsDOMFile.h"
 #include "nsIFile.h"
 #include "nsStringGlue.h"
 
 namespace mozilla {
 namespace dom {
 
 GetFileOrDirectoryTask::GetFileOrDirectoryTask(
   FileSystemBase* aFileSystem,
@@ -76,17 +77,17 @@ GetFileOrDirectoryTask::GetRequestParams
 FileSystemResponseValue
 GetFileOrDirectoryTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mIsDirectory) {
     return FileSystemDirectoryResponse(mTargetRealPath);
   }
 
-  nsRefPtr<DOMFile> file = new DOMFile(mTargetFileImpl);
+  nsRefPtr<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
   BlobParent* actor = GetBlobParent(file);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
@@ -94,18 +95,17 @@ GetFileOrDirectoryTask::GetSuccessReques
 void
 GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   switch (aValue.type()) {
     case FileSystemResponseValue::TFileSystemFileResponse: {
       FileSystemFileResponse r = aValue;
       BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
-      nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
-      mTargetFileImpl = static_cast<DOMFile*>(blob.get())->Impl();
+      mTargetFileImpl = actor->GetBlobImpl();
       mIsDirectory = false;
       break;
     }
     case FileSystemResponseValue::TFileSystemDirectoryResponse: {
       FileSystemDirectoryResponse r = aValue;
       mTargetRealPath = r.realPath();
       mIsDirectory = true;
       break;
@@ -180,17 +180,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 DOMFileImplFile(file);
+  mTargetFileImpl = new FileImplFile(file);
 
   return NS_OK;
 }
 
 void
 GetFileOrDirectoryTask::HandlerCallback()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
@@ -209,17 +209,17 @@ GetFileOrDirectoryTask::HandlerCallback(
 
   if (mIsDirectory) {
     nsRefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
     mPromise->MaybeResolve(dir);
     mPromise = nullptr;
     return;
   }
 
-  nsCOMPtr<nsIDOMFile> file = new DOMFile(mTargetFileImpl);
+  nsRefPtr<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
   mPromise->MaybeResolve(file);
   mPromise = nullptr;
 }
 
 void
 GetFileOrDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
 {
   aAccess.AssignLiteral("read");
--- a/dom/filesystem/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 DOMFileImpl;
+class FileImpl;
 
 class GetFileOrDirectoryTask MOZ_FINAL
   : public FileSystemTaskBase
 {
 public:
   // If aDirectoryOnly is set, we should ensure that the target is a directory.
   GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
                          const nsAString& aTargetPath,
@@ -54,17 +54,17 @@ protected:
   HandlerCallback() MOZ_OVERRIDE;
 
 private:
   nsRefPtr<Promise> mPromise;
   nsString mTargetRealPath;
   // Whether we get a directory.
   bool mIsDirectory;
 
-  // This cannot be a DOMFile bacause this object is created on a different
-  // thread and DOMFile is not thread-safe. Let's use the DOMFileImpl instead.
-  nsRefPtr<DOMFileImpl> mTargetFileImpl;
+  // 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;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_GetFileOrDirectory_h
--- a/dom/filesystem/RemoveTask.cpp
+++ b/dom/filesystem/RemoveTask.cpp
@@ -2,31 +2,31 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "RemoveTask.h"
 
 #include "DOMError.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
-#include "nsDOMFile.h"
 #include "nsIFile.h"
 #include "nsStringGlue.h"
 
 namespace mozilla {
 namespace dom {
 
 RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
                        const nsAString& aDirPath,
-                       DOMFileImpl* aTargetFile,
+                       FileImpl* aTargetFile,
                        const nsAString& aTargetPath,
                        bool aRecursive,
                        ErrorResult& aRv)
   : FileSystemTaskBase(aFileSystem)
   , mDirRealPath(aDirPath)
   , mTargetFileImpl(aTargetFile)
   , mTargetRealPath(aTargetPath)
   , mRecursive(aRecursive)
@@ -61,19 +61,18 @@ RemoveTask::RemoveTask(FileSystemBase* a
   const FileSystemPathOrFileValue& target = aParam.target();
 
   if (target.type() == FileSystemPathOrFileValue::TnsString) {
     mTargetRealPath = target;
     return;
   }
 
   BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(target));
-  nsCOMPtr<nsIDOMBlob> blob = bp->GetBlob();
-  MOZ_ASSERT(blob);
-  mTargetFileImpl = static_cast<DOMFile*>(blob.get())->Impl();
+  mTargetFileImpl = bp->GetBlobImpl();
+  MOZ_ASSERT(mTargetFileImpl);
 }
 
 RemoveTask::~RemoveTask()
 {
   MOZ_ASSERT(!mPromise || NS_IsMainThread(),
              "mPromise should be released on main thread!");
 }
 
@@ -88,17 +87,17 @@ FileSystemParams
 RemoveTask::GetRequestParams(const nsString& aFileSystem) const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   FileSystemRemoveParams param;
   param.filesystem() = aFileSystem;
   param.directory() = mDirRealPath;
   param.recursive() = mRecursive;
   if (mTargetFileImpl) {
-    nsRefPtr<DOMFile> file = new DOMFile(mTargetFileImpl);
+    nsRefPtr<File> file = new File(mFileSystem->GetWindow(), mTargetFileImpl);
     BlobChild* actor
       = ContentChild::GetSingleton()->GetOrCreateActorForBlob(file);
     if (actor) {
       param.target() = actor;
     }
   } else {
     param.target() = mTargetRealPath;
   }
@@ -126,17 +125,17 @@ RemoveTask::Work()
   MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
              "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 DOMFile is passed as the target.
+  // Get the DOM path if a File is passed as the target.
   if (mTargetFileImpl) {
     if (!mFileSystem->GetRealPath(mTargetFileImpl, mTargetRealPath)) {
       return NS_ERROR_DOM_SECURITY_ERR;
     }
     if (!FileSystemUtils::IsDescendantPath(mDirRealPath, mTargetRealPath)) {
       return NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
     }
   }
--- 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 DOMFileImpl;
+class FileImpl;
 class Promise;
 
 class RemoveTask MOZ_FINAL
   : public FileSystemTaskBase
 {
 public:
   RemoveTask(FileSystemBase* aFileSystem,
              const nsAString& aDirPath,
-             DOMFileImpl* aTargetFile,
+             FileImpl* aTargetFile,
              const nsAString& aTargetPath,
              bool aRecursive,
              ErrorResult& aRv);
   RemoveTask(FileSystemBase* aFileSystem,
              const FileSystemRemoveParams& aParam,
              FileSystemRequestParent* aParent);
 
   virtual
@@ -54,19 +54,19 @@ protected:
   Work() MOZ_OVERRIDE;
 
   virtual void
   HandlerCallback() MOZ_OVERRIDE;
 
 private:
   nsRefPtr<Promise> mPromise;
   nsString mDirRealPath;
-  // This cannot be a DOMFile because this object will be used on a different
-  // thread and DOMFile is not thread-safe. Let's use the DOMFileImpl instead.
-  nsRefPtr<DOMFileImpl> mTargetFileImpl;
+  // 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;
   nsString mTargetRealPath;
   bool mRecursive;
   bool mReturnValue;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -519,18 +519,20 @@ ConvertActorsToBlobs(IDBDatabase* aDatab
 
   if (!blobs.IsEmpty()) {
     const uint32_t count = blobs.Length();
     aFiles.SetCapacity(count);
 
     for (uint32_t index = 0; index < count; index++) {
       BlobChild* actor = static_cast<BlobChild*>(blobs[index]);
 
-      nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
-      MOZ_ASSERT(blob);
+      nsRefPtr<FileImpl> blobImpl = actor->GetBlobImpl();
+      MOZ_ASSERT(blobImpl);
+
+      nsRefPtr<File> blob = new File(aDatabase->GetOwner(), blobImpl);
 
       nsRefPtr<FileInfo> fileInfo;
       if (!fileInfos.IsEmpty()) {
         fileInfo = dont_AddRef(reinterpret_cast<FileInfo*>(fileInfos[index]));
 
         MOZ_ASSERT(fileInfo);
         MOZ_ASSERT(fileInfo->Id() > 0);
 
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -24,16 +24,17 @@
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/storage.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBCursorParent.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseParent.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseFileParent.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryParent.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryRequestParent.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBRequestParent.h"
@@ -51,22 +52,20 @@
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/InputStreamParams.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/ipc/PBackground.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsClassHashtable.h"
 #include "nsCOMPtr.h"
 #include "nsDataHashtable.h"
-#include "nsDOMFile.h"
 #include "nsEscape.h"
 #include "nsHashKeys.h"
 #include "nsNetUtil.h"
 #include "nsIAppsService.h"
-#include "nsIDOMFile.h"
 #include "nsIEventTarget.h"
 #include "nsIFile.h"
 #include "nsIFileURL.h"
 #include "nsIInputStream.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsInterfaceHashtable.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
@@ -3023,17 +3022,17 @@ private:
   RecvClose() MOZ_OVERRIDE;
 };
 
 class DatabaseFile MOZ_FINAL
   : public PBackgroundIDBDatabaseFileParent
 {
   friend class Database;
 
-  nsRefPtr<DOMFileImpl> mBlobImpl;
+  nsRefPtr<FileImpl> mBlobImpl;
   nsRefPtr<FileInfo> mFileInfo;
 
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::indexedDB::DatabaseFile);
 
   FileInfo*
   GetFileInfo() const
   {
@@ -3070,17 +3069,17 @@ private:
   explicit DatabaseFile(FileInfo* aFileInfo)
     : mFileInfo(aFileInfo)
   {
     AssertIsOnBackgroundThread();
     MOZ_ASSERT(aFileInfo);
   }
 
   // Called when receiving from the child.
-  DatabaseFile(DOMFileImpl* aBlobImpl, FileInfo* aFileInfo)
+  DatabaseFile(FileImpl* aBlobImpl, FileInfo* aFileInfo)
     : mBlobImpl(aBlobImpl)
     , mFileInfo(aFileInfo)
   {
     AssertIsOnBackgroundThread();
     MOZ_ASSERT(aBlobImpl);
     MOZ_ASSERT(aFileInfo);
   }
 
@@ -5008,21 +5007,21 @@ private:
     MOZ_ASSERT(!mWaitingFactoryOp ||
                !mWaitingFactoryOp->HasBlockedDatabases());
 
     MOZ_COUNT_DTOR(DatabaseActorInfo);
   }
 };
 
 class NonMainThreadHackBlobImpl MOZ_FINAL
-  : public DOMFileImplFile
+  : public FileImplFile
 {
 public:
   NonMainThreadHackBlobImpl(nsIFile* aFile, FileInfo* aFileInfo)
-    : DOMFileImplFile(aFile, aFileInfo)
+    : FileImplFile(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
@@ -5495,17 +5494,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<DOMFileImpl> impl =
+    nsRefPtr<FileImpl> 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;
@@ -6235,17 +6234,17 @@ Database::ActorDestroy(ActorDestroyReaso
 }
 
 PBackgroundIDBDatabaseFileParent*
 Database::AllocPBackgroundIDBDatabaseFileParent(PBlobParent* aBlobParent)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aBlobParent);
 
-  nsRefPtr<DOMFileImpl> blobImpl =
+  nsRefPtr<FileImpl> 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
@@ -21,20 +21,20 @@ namespace indexedDB {
 
 // Create as a stored file
 FileImplSnapshot::FileImplSnapshot(const nsAString& aName,
                                    const nsAString& aContentType,
                                    MetadataParameters* aMetadataParams,
                                    nsIFile* aFile,
                                    IDBFileHandle* aFileHandle,
                                    FileInfo* aFileInfo)
-  : DOMFileImplBase(aName,
-                    aContentType,
-                    aMetadataParams->Size(),
-                    aMetadataParams->LastModified())
+  : FileImplBase(aName,
+                 aContentType,
+                 aMetadataParams->Size(),
+                 aMetadataParams->LastModified())
   , mFile(aFile)
   , mFileHandle(aFileHandle)
   , mWholeFile(true)
 {
   AssertSanity();
   MOZ_ASSERT(aMetadataParams);
   MOZ_ASSERT(aMetadataParams->Size() != UINT64_MAX);
   MOZ_ASSERT(aMetadataParams->LastModified() != INT64_MAX);
@@ -45,17 +45,17 @@ FileImplSnapshot::FileImplSnapshot(const
   mFileInfos.AppendElement(aFileInfo);
 }
 
 // Create slice
 FileImplSnapshot::FileImplSnapshot(const FileImplSnapshot* aOther,
                                    uint64_t aStart,
                                    uint64_t aLength,
                                    const nsAString& aContentType)
-  : DOMFileImplBase(aContentType, aOther->mStart + aStart, aLength)
+  : FileImplBase(aContentType, aOther->mStart + aStart, aLength)
   , mFile(aOther->mFile)
   , mFileHandle(aOther->mFileHandle)
   , mWholeFile(false)
 {
   AssertSanity();
   MOZ_ASSERT(aOther);
 
   FileInfo* fileInfo;
@@ -81,17 +81,17 @@ void
 FileImplSnapshot::AssertSanity()
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 #endif // DEBUG
 
-NS_IMPL_ISUPPORTS_INHERITED0(FileImplSnapshot, DOMFileImpl)
+NS_IMPL_ISUPPORTS_INHERITED0(FileImplSnapshot, FileImpl)
 
 void
 FileImplSnapshot::Unlink()
 {
   AssertSanity();
 
   FileImplSnapshot* tmp = this;
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileHandle);
@@ -123,36 +123,38 @@ FileImplSnapshot::GetInternalStream(nsII
                                              aStream);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   return NS_OK;
 }
 
-already_AddRefed<DOMFileImpl>
+already_AddRefed<FileImpl>
 FileImplSnapshot::CreateSlice(uint64_t aStart,
                               uint64_t aLength,
-                              const nsAString& aContentType)
+                              const nsAString& aContentType,
+                              ErrorResult& aRv)
 {
   AssertSanity();
 
-  nsRefPtr<DOMFileImpl> impl =
+  nsRefPtr<FileImpl> impl =
     new FileImplSnapshot(this, aStart, aLength, aContentType);
 
   return impl.forget();
 }
 
-nsresult
-FileImplSnapshot::GetMozFullPathInternal(nsAString& aFilename)
+void
+FileImplSnapshot::GetMozFullPathInternal(nsAString& aFilename,
+                                         ErrorResult& aRv)
 {
   AssertSanity();
   MOZ_ASSERT(mIsFile);
 
-  return mFile->GetPath(aFilename);
+  aRv = mFile->GetPath(aFilename);
 }
 
 bool
 FileImplSnapshot::IsStoredFile() const
 {
   AssertSanity();
 
   return true;
--- a/dom/indexedDB/FileSnapshot.h
+++ b/dom/indexedDB/FileSnapshot.h
@@ -3,31 +3,31 @@
 /* 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_indexeddb_filesnapshot_h__
 #define mozilla_dom_indexeddb_filesnapshot_h__
 
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/File.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
-#include "nsDOMFile.h"
 
 namespace mozilla {
 namespace dom {
 
 class MetadataParameters;
 
 namespace indexedDB {
 
 class IDBFileHandle;
 
 class FileImplSnapshot MOZ_FINAL
-  : public DOMFileImplBase
+  : public FileImplBase
 {
   typedef mozilla::dom::MetadataParameters MetadataParameters;
 
   nsCOMPtr<nsIFile> mFile;
   nsRefPtr<IDBFileHandle> mFileHandle;
 
   bool mWholeFile;
 
@@ -54,35 +54,36 @@ private:
   static void
   AssertSanity()
 #ifdef DEBUG
   ;
 #else
   { }
 #endif
 
-  virtual nsresult
-  GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
+  virtual void
+  GetMozFullPathInternal(nsAString& aFullPath, ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual nsresult
   GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
   virtual void
   Unlink() MOZ_OVERRIDE;
 
   virtual void
   Traverse(nsCycleCollectionTraversalCallback &aCb) MOZ_OVERRIDE;
 
   virtual bool
   IsCCed() const MOZ_OVERRIDE;
 
-  virtual already_AddRefed<DOMFileImpl>
+  virtual already_AddRefed<FileImpl>
   CreateSlice(uint64_t aStart,
               uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
+              const nsAString& aContentType,
+              ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual bool
   IsStoredFile() const MOZ_OVERRIDE;
 
   virtual bool
   IsWholeFile() const MOZ_OVERRIDE;
 
   virtual bool
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -20,32 +20,31 @@
 #include "mozilla/ErrorResult.h"
 #include "mozilla/EventDispatcher.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Services.h"
 #include "mozilla/storage.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/dom/DOMStringListBinding.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/IDBDatabaseBinding.h"
 #include "mozilla/dom/IDBObjectStoreBinding.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseFileChild.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/nsIRemoteBlob.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/ipc/FileDescriptor.h"
 #include "mozilla/ipc/InputStreamParams.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "nsCOMPtr.h"
-#include "nsDOMFile.h"
 #include "nsIDocument.h"
-#include "nsIDOMFile.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsISupportsPrimitives.h"
 #include "nsThreadUtils.h"
 #include "ProfilerHelpers.h"
 #include "ReportInternalError.h"
 
 // Include this last to avoid path problems on Windows.
@@ -798,33 +797,34 @@ IDBDatabase::AbortTransactions()
       return PL_DHASH_NEXT;
     }
   };
 
   Helper::AbortTransactions(mTransactions);
<