merge mozilla-central to mozilla-inbound. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Sat, 29 Apr 2017 11:13:06 +0200
changeset 355784 a55987f8d963b51d62d853c6d2400bf1df8c8ede
parent 355783 5022472053033960fd63f266f1c100c02df8de7a (current diff)
parent 355743 308cdb913d717f8edc932f5bac93854e3e54b84d (diff)
child 355785 53672c48392add5e976edd062af5abfa45f48818
push id31740
push userarchaeopteryx@coole-files.de
push dateSat, 29 Apr 2017 19:31:26 +0000
treeherdermozilla-central@2fe636103d71 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-central to mozilla-inbound. r=merge a=merge
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6441,21 +6441,32 @@ var IndexedDBPromptHelper = {
 
 function CanCloseWindow() {
   // Avoid redundant calls to canClose from showing multiple
   // PermitUnload dialogs.
   if (Services.startup.shuttingDown || window.skipNextCanClose) {
     return true;
   }
 
+  let timedOutProcesses = new WeakSet();
+
   for (let browser of gBrowser.browsers) {
+    let pmm = browser.messageManager.processMessageManager;
+
+    if (timedOutProcesses.has(pmm)) {
+      continue;
+    }
+
     let {permitUnload, timedOut} = browser.permitUnload();
+
     if (timedOut) {
-      return true;
-    }
+      timedOutProcesses.add(pmm);
+      continue;
+    }
+
     if (!permitUnload) {
       return false;
     }
   }
   return true;
 }
 
 function WindowIsClosing() {
--- a/browser/components/uitour/test/browser_closeTab.js
+++ b/browser/components/uitour/test/browser_closeTab.js
@@ -7,12 +7,17 @@ var gContentAPI;
 var gContentWindow;
 
 add_task(setup_UITourTest);
 
 add_UITour_task(function* test_closeTab() {
   // Setting gTestTab to null indicates that the tab has already been closed,
   // and if this does not happen the test run will fail.
   let closePromise = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabClose");
-  yield gContentAPI.closeTab();
+  // In the e10s-case, having content request a tab close might mean
+  // that the ContentTask used to send this closeTab message won't
+  // get a response (since the message manager may have closed down).
+  // So we ignore the Promise that closeTab returns, and use the TabClose
+  // event to tell us when the tab has gone away.
+  gContentAPI.closeTab();
   yield closePromise;
   gTestTab = null;
 });
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -12,16 +12,17 @@ this.EXPORTED_SYMBOLS = ["FormAutofillHe
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 /**
  * Returns the autocomplete information of fields according to heuristics.
  */
 this.FormAutofillHeuristics = {
   VALID_FIELDS: [
+    "name",
     "given-name",
     "additional-name",
     "family-name",
     "organization",
     "street-address",
     "address-line1",
     "address-line2",
     "address-line3",
--- a/browser/extensions/formautofill/FormAutofillNameUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillNameUtils.jsm
@@ -121,16 +121,20 @@ var FormAutofillNameUtils = {
     // no more than 2 words.
     //
     // Chinese and Japanese names are usually spelled out using the Han
     // characters (logographs), which constitute the "CJK Unified Ideographs"
     // block in Unicode, also referred to as Unihan. Korean names are usually
     // spelled out in the Korean alphabet (Hangul), although they do have a Han
     // equivalent as well.
 
+    if (!name) {
+      return false;
+    }
+
     let previousWasCJK = false;
     let wordCount = 0;
 
     for (let c of name) {
       let isMiddleDot = this.MIDDLE_DOT.includes(c);
       let isCJK = !isMiddleDot && this.reCJK.test(c);
       if (!isCJK && !isMiddleDot && !this.WHITESPACE.includes(c)) {
         return false;
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -16,29 +16,16 @@ this.FormAutofillUtils = {
       let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
       return new ConsoleAPI({
         maxLogLevelPref: "browser.formautofill.loglevel",
         prefix: logPrefix,
       });
     });
   },
 
-  generateFullName(firstName, lastName, middleName) {
-    // TODO: The implementation should depend on the L10N spec, but a simplified
-    // rule is used here.
-    let fullName = firstName;
-    if (middleName) {
-      fullName += " " + middleName;
-    }
-    if (lastName) {
-      fullName += " " + lastName;
-    }
-    return fullName;
-  },
-
   findLabelElements(element) {
     let document = element.ownerDocument;
     let labels = [];
     // TODO: querySelectorAll is inefficient here. However, bug 1339726 is for
     // a more efficient implementation from DOM API perspective. This function
     // should be refined after input.labels API landed.
     for (let label of document.querySelectorAll("label[for]")) {
       if (element.id == label.htmlFor) {
--- a/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
+++ b/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
@@ -95,52 +95,43 @@ ProfileAutoCompleteResult.prototype = {
       "given-name",
       "additional-name",
       "family-name",
     ];
 
     focusedFieldName = possibleNameFields.includes(focusedFieldName) ?
                        "name" : focusedFieldName;
 
-    // Clones the profile to avoid exposing our modification.
-    let clonedProfile = Object.assign({}, profile);
-    if (!clonedProfile.name) {
-      clonedProfile.name =
-        FormAutofillUtils.generateFullName(clonedProfile["given-name"],
-                                           clonedProfile["family-name"],
-                                           clonedProfile["additional-name"]);
-    }
-
     const secondaryLabelOrder = [
       "street-address",  // Street address
       "name",            // Full name
       "address-level2",  // City/Town
       "organization",    // Company or organization name
       "address-level1",  // Province/State (Standardized code if possible)
       "country",         // Country
       "postal-code",     // Postal code
       "tel",             // Phone number
       "email",           // Email address
     ];
 
     for (const currentFieldName of secondaryLabelOrder) {
       if (focusedFieldName == currentFieldName ||
-          !clonedProfile[currentFieldName]) {
+          !profile[currentFieldName]) {
         continue;
       }
 
       let matching;
       if (currentFieldName == "name") {
         matching = allFieldNames.some(fieldName => possibleNameFields.includes(fieldName));
       } else {
         matching = allFieldNames.includes(currentFieldName);
       }
 
       if (matching) {
-        return clonedProfile[currentFieldName];
+        return profile[currentFieldName];
       }
     }
 
     return ""; // Nothing matched.
   },
 
   _generateLabels(focusedFieldName, allFieldNames, profiles) {
     // Skip results without a primary label.
--- a/browser/extensions/formautofill/ProfileStorage.jsm
+++ b/browser/extensions/formautofill/ProfileStorage.jsm
@@ -295,16 +295,24 @@ ProfileStorage.prototype = {
     return Object.assign({}, profile);
   },
 
   _findByGUID(guid) {
     return this._store.data.profiles.find(profile => profile.guid == guid);
   },
 
   _computeFields(profile) {
+    // Compute name
+    profile.name = FormAutofillNameUtils.joinNameParts({
+      given: profile["given-name"],
+      middle: profile["additional-name"],
+      family: profile["family-name"],
+    });
+
+    // Compute address
     if (profile["street-address"]) {
       let streetAddress = profile["street-address"].split("\n");
       // TODO: we should prevent the dataloss by concatenating the rest of lines
       //       with a locale-specific character in the future (bug 1360114).
       for (let i = 0; i < 3; i++) {
         if (streetAddress[i]) {
           profile["address-line" + (i + 1)] = streetAddress[i];
         }
@@ -332,17 +340,36 @@ ProfileStorage.prototype = {
 
       // Concatenate "address-line*" if "street-address" is omitted.
       if (!profile["street-address"]) {
         profile["street-address"] = addressLines.join("\n");
       }
     }
   },
 
+  _normalizeName(profile) {
+    if (!profile.name) {
+      return;
+    }
+
+    let nameParts = FormAutofillNameUtils.splitName(profile.name);
+    if (!profile["given-name"] && nameParts.given) {
+      profile["given-name"] = nameParts.given;
+    }
+    if (!profile["additional-name"] && nameParts.middle) {
+      profile["additional-name"] = nameParts.middle;
+    }
+    if (!profile["family-name"] && nameParts.family) {
+      profile["family-name"] = nameParts.family;
+    }
+    delete profile.name;
+  },
+
   _normalizeProfile(profile) {
+    this._normalizeName(profile);
     this._normalizeAddress(profile);
 
     for (let key in profile) {
       if (!VALID_FIELDS.includes(key)) {
         throw new Error(`"${key}" is not a valid field.`);
       }
       if (typeof profile[key] !== "string" &&
           typeof profile[key] !== "number") {
--- a/browser/extensions/formautofill/test/unit/test_profileAutocompleteResult.js
+++ b/browser/extensions/formautofill/test/unit/test_profileAutocompleteResult.js
@@ -1,23 +1,25 @@
 "use strict";
 
 Cu.import("resource://formautofill/ProfileAutoCompleteResult.jsm");
 
 let matchingProfiles = [{
   guid: "test-guid-1",
   "given-name": "Timothy",
   "family-name": "Berners-Lee",
+  name: "Timothy Berners-Lee",
   organization: "Sesame Street",
   "street-address": "123 Sesame Street.",
   tel: "1-345-345-3456.",
 }, {
   guid: "test-guid-2",
   "given-name": "John",
   "family-name": "Doe",
+  name: "John Doe",
   organization: "Mozilla",
   "street-address": "331 E. Evelyn Avenue",
   tel: "1-650-903-0800",
 }, {
   guid: "test-guid-3",
   organization: "",
   "street-address": "321, No Name St.",
   tel: "1-000-000-0000",
--- a/browser/extensions/formautofill/test/unit/test_transformFields.js
+++ b/browser/extensions/formautofill/test/unit/test_transformFields.js
@@ -14,16 +14,32 @@ const COMPUTE_TESTCASES = [
   {
     description: "Empty profile",
     profile: {
     },
     expectedResult: {
     },
   },
 
+  // Name
+  {
+    description: "Has split names",
+    profile: {
+      "given-name": "Timothy",
+      "additional-name": "John",
+      "family-name": "Berners-Lee",
+    },
+    expectedResult: {
+      "given-name": "Timothy",
+      "additional-name": "John",
+      "family-name": "Berners-Lee",
+      "name": "Timothy John Berners-Lee",
+    },
+  },
+
   // Address
   {
     description: "\"street-address\" with single line",
     profile: {
       "street-address": "single line",
     },
     expectedResult: {
       "street-address": "single line",
@@ -73,16 +89,55 @@ const NORMALIZE_TESTCASES = [
   {
     description: "Empty profile",
     profile: {
     },
     expectedResult: {
     },
   },
 
+  // Name
+  {
+    description: "Has \"name\", and the split names are omitted",
+    profile: {
+      "name": "Timothy John Berners-Lee",
+    },
+    expectedResult: {
+      "given-name": "Timothy",
+      "additional-name": "John",
+      "family-name": "Berners-Lee",
+    },
+  },
+  {
+    description: "Has both \"name\" and split names",
+    profile: {
+      "name": "John Doe",
+      "given-name": "Timothy",
+      "additional-name": "John",
+      "family-name": "Berners-Lee",
+    },
+    expectedResult: {
+      "given-name": "Timothy",
+      "additional-name": "John",
+      "family-name": "Berners-Lee",
+    },
+  },
+  {
+    description: "Has \"name\", and some of split names are omitted",
+    profile: {
+      "name": "John Doe",
+      "given-name": "Timothy",
+    },
+    expectedResult: {
+      "given-name": "Timothy",
+      "family-name": "Doe",
+    },
+  },
+
+
   // Address
   {
     description: "Has \"address-line1~3\" and \"street-address\" is omitted",
     profile: {
       "address-line1": "line1",
       "address-line2": "line2",
       "address-line3": "line3",
     },
--- a/docshell/test/browser/browser_grouped_shistory_dead_navigate.js
+++ b/docshell/test/browser/browser_grouped_shistory_dead_navigate.js
@@ -23,16 +23,17 @@ add_task(function* () {
       isPrerendered: true,
     });
     yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser);
     browser1.frameLoader.appendPartialSHistoryAndSwap(tab2.linkedBrowser.frameLoader);
     yield awaitProcessChange(browser1);
 
     // Close tab2 such that the back frameloader is dead
     yield BrowserTestUtils.removeTab(tab2);
+    yield BrowserTestUtils.waitForCondition(() => browser1.canGoBack);
     browser1.goBack();
     yield BrowserTestUtils.browserLoaded(browser1);
     yield ContentTask.spawn(browser1, null, function() {
       is(content.window.location + "", "data:text/html,a");
       let webNav = content.window.QueryInterface(Ci.nsIInterfaceRequestor)
             .getInterface(Ci.nsIWebNavigation);
       is(webNav.canGoForward, true, "canGoForward is correct");
       is(webNav.canGoBack, false, "canGoBack is correct");
--- a/dom/base/Attr.cpp
+++ b/dom/base/Attr.cpp
@@ -246,17 +246,18 @@ void
 Attr::SetNodeValueInternal(const nsAString& aNodeValue, ErrorResult& aError)
 {
   OwnerDoc()->WarnOnceAbout(nsIDocument::eNodeValue);
 
   aError = SetValue(aNodeValue);
 }
 
 nsresult
-Attr::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+Attr::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+            bool aPreallocateChildren) const
 {
   nsAutoString value;
   const_cast<Attr*>(this)->GetValue(value);
 
   RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
   *aResult = new Attr(nullptr, ni.forget(), value);
   if (!*aResult) {
     return NS_ERROR_OUT_OF_MEMORY;
--- a/dom/base/Attr.h
+++ b/dom/base/Attr.h
@@ -65,17 +65,18 @@ public:
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
   virtual uint32_t GetChildCount() const override;
   virtual nsIContent *GetChildAt(uint32_t aIndex) const override;
   virtual nsIContent * const * GetChildArray(uint32_t* aChildCount) const override;
   virtual int32_t IndexOf(const nsINode* aPossibleChild) const override;
   virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
                                  bool aNotify) override;
   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
   virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override;
 
   static void Initialize();
   static void Shutdown();
 
   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Attr,
                                                                    nsIAttribute)
 
--- a/dom/base/DocumentFragment.h
+++ b/dom/base/DocumentFragment.h
@@ -139,17 +139,18 @@ public:
   virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const override;
 #endif
 
 protected:
   virtual ~DocumentFragment()
   {
   }
 
-  nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                 bool aPreallocateChildren) const override;
   nsIContent* mHost; // Weak
 };
 
 } // namespace dom
 } // namespace mozilla
 
 
 #endif // mozilla_dom_DocumentFragment_h__
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1648,50 +1648,52 @@ inline void nsINode::UnsetRestyleFlagsIf
 }
 
 /**
  * Macros to implement Clone(). _elementName is the class for which to implement
  * Clone.
  */
 #define NS_IMPL_ELEMENT_CLONE(_elementName)                                 \
 nsresult                                                                    \
-_elementName::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const \
+_elementName::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,   \
+                    bool aPreallocateChildren) const                        \
 {                                                                           \
   *aResult = nullptr;                                                       \
   already_AddRefed<mozilla::dom::NodeInfo> ni =                             \
     RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();                   \
   _elementName *it = new _elementName(ni);                                  \
   if (!it) {                                                                \
     return NS_ERROR_OUT_OF_MEMORY;                                          \
   }                                                                         \
                                                                             \
   nsCOMPtr<nsINode> kungFuDeathGrip = it;                                   \
-  nsresult rv = const_cast<_elementName*>(this)->CopyInnerTo(it);           \
+  nsresult rv = const_cast<_elementName*>(this)->CopyInnerTo(it, aPreallocateChildren); \
   if (NS_SUCCEEDED(rv)) {                                                   \
     kungFuDeathGrip.swap(*aResult);                                         \
   }                                                                         \
                                                                             \
   return rv;                                                                \
 }
 
 #define NS_IMPL_ELEMENT_CLONE_WITH_INIT(_elementName)                       \
 nsresult                                                                    \
-_elementName::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const \
+_elementName::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,   \
+                    bool aPreallocateChildren) const                        \
 {                                                                           \
   *aResult = nullptr;                                                       \
   already_AddRefed<mozilla::dom::NodeInfo> ni =                             \
     RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();                   \
   _elementName *it = new _elementName(ni);                                  \
   if (!it) {                                                                \
     return NS_ERROR_OUT_OF_MEMORY;                                          \
   }                                                                         \
                                                                             \
   nsCOMPtr<nsINode> kungFuDeathGrip = it;                                   \
   nsresult rv = it->Init();                                                 \
-  nsresult rv2 = const_cast<_elementName*>(this)->CopyInnerTo(it);          \
+  nsresult rv2 = const_cast<_elementName*>(this)->CopyInnerTo(it, aPreallocateChildren); \
   if (NS_FAILED(rv2)) {                                                     \
     rv = rv2;                                                               \
   }                                                                         \
   if (NS_SUCCEEDED(rv)) {                                                   \
     kungFuDeathGrip.swap(*aResult);                                         \
   }                                                                         \
                                                                             \
   return rv;                                                                \
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -2053,25 +2053,30 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(FragmentOrElement)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(FragmentOrElement,
                                                    nsNodeUtils::LastRelease(this))
 
 //----------------------------------------------------------------------
 
 nsresult
-FragmentOrElement::CopyInnerTo(FragmentOrElement* aDst)
+FragmentOrElement::CopyInnerTo(FragmentOrElement* aDst,
+                               bool aPreallocateChildren)
 {
+  nsresult rv = aDst->mAttrsAndChildren.EnsureCapacityToClone(mAttrsAndChildren,
+                                                              aPreallocateChildren);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   uint32_t i, count = mAttrsAndChildren.AttrCount();
   for (i = 0; i < count; ++i) {
     const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
     const nsAttrValue* value = mAttrsAndChildren.AttrAt(i);
     nsAutoString valStr;
     value->ToString(valStr);
-    nsresult rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
+    rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
                                 name->GetPrefix(), valStr, false);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 const nsTextFragment*
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -231,17 +231,17 @@ public:
   static bool IsHTMLVoid(nsIAtom* aLocalName);
 protected:
   virtual ~FragmentOrElement();
 
   /**
    * Copy attributes and state to another element
    * @param aDest the object to copy to
    */
-  nsresult CopyInnerTo(FragmentOrElement* aDest);
+  nsresult CopyInnerTo(FragmentOrElement* aDest, bool aPreallocateChildren);
 
 public:
   // Because of a bug in MS C++ compiler nsDOMSlots must be declared public,
   // otherwise nsXULElement::nsXULSlots doesn't compile.
   /**
    * There are a set of DOM- and scripting-specific instance variables
    * that may only be instantiated when a content object is accessed
    * through the DOM. Rather than burn actual slots in the content
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1992,33 +1992,42 @@ ToCString(const MediaKeySystemConfigurat
   str.Append(ToCString(aConfig.mSessionTypes));
 
   str.AppendLiteral("}");
 
   return str;
 }
 
 static nsCString
-RequestKeySystemAccessLogString(const nsAString& aKeySystem,
-                                const Sequence<MediaKeySystemConfiguration>& aConfigs)
+RequestKeySystemAccessLogString(
+  const nsAString& aKeySystem,
+  const Sequence<MediaKeySystemConfiguration>& aConfigs,
+  bool aIsSecureContext)
 {
   nsCString str;
   str.AppendPrintf("Navigator::RequestMediaKeySystemAccess(keySystem='%s' options=",
                    NS_ConvertUTF16toUTF8(aKeySystem).get());
   str.Append(ToCString(aConfigs));
-  str.AppendLiteral(")");
+  str.AppendLiteral(") secureContext=");
+  str.AppendInt(aIsSecureContext);
   return str;
 }
 
 already_AddRefed<Promise>
 Navigator::RequestMediaKeySystemAccess(const nsAString& aKeySystem,
                                        const Sequence<MediaKeySystemConfiguration>& aConfigs,
                                        ErrorResult& aRv)
 {
-  EME_LOG("%s", RequestKeySystemAccessLogString(aKeySystem, aConfigs).get());
+  EME_LOG("%s",
+          RequestKeySystemAccessLogString(
+            aKeySystem, aConfigs, mWindow->IsSecureContext())
+            .get());
+
+  Telemetry::Accumulate(Telemetry::MEDIA_EME_SECURE_CONTEXT,
+                        mWindow->IsSecureContext());
 
   nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
   RefPtr<DetailedPromise> promise =
     DetailedPromise::Create(go, aRv,
       NS_LITERAL_CSTRING("navigator.requestMediaKeySystemAccess"),
       Telemetry::VIDEO_EME_REQUEST_SUCCESS_LATENCY_MS,
       Telemetry::VIDEO_EME_REQUEST_FAILURE_LATENCY_MS);
   if (aRv.Failed()) {
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -705,17 +705,18 @@ ShadowRoot::ContentRemoved(nsIDocument* 
   // Watch for node that is removed from the pool because
   // it may need to be removed from an insertion point.
   if (IsPooledNode(aChild, aContainer, mPoolHost)) {
     RemoveDistributedNode(aChild);
   }
 }
 
 nsresult
-ShadowRoot::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+ShadowRoot::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                  bool aPreallocateChildren) const
 {
   *aResult = nullptr;
   return NS_ERROR_DOM_DATA_CLONE_ERR;
 }
 
 void
 ShadowRoot::DestroyContent()
 {
--- a/dom/base/ShadowRoot.h
+++ b/dom/base/ShadowRoot.h
@@ -181,17 +181,18 @@ protected:
   bool mInsertionPointChanged;
 
   // Flag to indicate whether the descendants of this shadow root are part of the
   // composed document. Ideally, we would use a node flag on nodes to
   // mark whether it is in the composed document, but we have run out of flags
   // so instead we track it here.
   bool mIsComposedDocParticipant;
 
-  nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                 bool aPreallocateChildren) const override;
 };
 
 class ShadowRootStyleSheetList : public StyleSheetList
 {
 public:
   explicit ShadowRootStyleSheetList(ShadowRoot* aShadowRoot);
 
   NS_DECL_ISUPPORTS_INHERITED
--- a/dom/base/nsAttrAndChildArray.cpp
+++ b/dom/base/nsAttrAndChildArray.cpp
@@ -789,16 +789,54 @@ nsAttrAndChildArray::MakeMappedUnique(ns
 }
 
 const nsMappedAttributes*
 nsAttrAndChildArray::GetMapped() const
 {
   return mImpl ? mImpl->mMappedAttrs : nullptr;
 }
 
+nsresult nsAttrAndChildArray::EnsureCapacityToClone(const nsAttrAndChildArray& aOther,
+                                                    bool aAllocateChildren)
+{
+  NS_PRECONDITION(!mImpl, "nsAttrAndChildArray::EnsureCapacityToClone requires the array be empty when called");
+
+  uint32_t attrCount = aOther.NonMappedAttrCount();
+  uint32_t childCount = 0;
+  if (aAllocateChildren) {
+    childCount = aOther.ChildCount();
+  }
+
+  if (attrCount == 0 && childCount == 0) {
+    return NS_OK;
+  }
+
+  // No need to use a CheckedUint32 because we are cloning. We know that we
+  // have already allocated an nsAttrAndChildArray of this size.
+  uint32_t size = attrCount;
+  size *= ATTRSIZE;
+  size += childCount;
+  uint32_t totalSize = size;
+  totalSize += NS_IMPL_EXTRA_SIZE;
+
+  mImpl = static_cast<Impl*>(malloc(totalSize * sizeof(void*)));
+  NS_ENSURE_TRUE(mImpl, NS_ERROR_OUT_OF_MEMORY);
+
+  mImpl->mMappedAttrs = nullptr;
+  mImpl->mBufferSize = size;
+
+  // The array is now the right size, but we should reserve the correct
+  // number of slots for attributes so that children don't get written into
+  // that part of the array (which will then need to be moved later).
+  memset(static_cast<void*>(mImpl->mBuffer), 0, sizeof(InternalAttr) * attrCount);
+  SetAttrSlotAndChildCount(attrCount, 0);
+
+  return NS_OK;
+}
+
 bool
 nsAttrAndChildArray::GrowBy(uint32_t aGrowSize)
 {
   CheckedUint32 size = 0;
   if (mImpl) {
     size += mImpl->mBufferSize;
     size += NS_IMPL_EXTRA_SIZE;
     if (!size.isValid()) {
--- a/dom/base/nsAttrAndChildArray.h
+++ b/dom/base/nsAttrAndChildArray.h
@@ -138,16 +138,23 @@ public:
 
   // Force this to have mapped attributes, even if those attributes are empty.
   nsresult ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument);
 
   // Clear the servo declaration block on the mapped attributes, if any
   // Will assert off main thread
   void ClearMappedServoStyle();
 
+  // Increases capacity (if necessary) to have enough space to accomodate the
+  // unmapped attributes and children of |aOther|. If |aAllocateChildren| is not
+  // true, only enough space for unmapped attributes will be reserved.
+  // It is REQUIRED that this function be called ONLY when the array is empty.
+  nsresult EnsureCapacityToClone(const nsAttrAndChildArray& aOther,
+                                 bool aAllocateChildren);
+
 private:
   nsAttrAndChildArray(const nsAttrAndChildArray& aOther) = delete;
   nsAttrAndChildArray& operator=(const nsAttrAndChildArray& aOther) = delete;
 
   void Clear();
 
   uint32_t NonMappedAttrCount() const;
   uint32_t MappedAttrCount() const;
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -9313,17 +9313,17 @@ nsDocument::RefreshLinkHrefs()
   // Reset all of our styled links.
   nsAutoScriptBlocker scriptBlocker;
   for (LinkArray::size_type i = 0; i < linksToNotify.Length(); i++) {
     linksToNotify[i]->ResetLinkState(true, linksToNotify[i]->ElementHasHref());
   }
 }
 
 nsresult
-nsDocument::CloneDocHelper(nsDocument* clone) const
+nsDocument::CloneDocHelper(nsDocument* clone, bool aPreallocateChildren) const
 {
   clone->mIsStaticDocument = mCreatingStaticClone;
 
   // Init document
   nsresult rv = clone->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mCreatingStaticClone) {
@@ -9390,16 +9390,21 @@ nsDocument::CloneDocHelper(nsDocument* c
   clone->mContentLanguage = mContentLanguage;
   clone->SetContentTypeInternal(GetContentTypeInternal());
   clone->mSecurityInfo = mSecurityInfo;
 
   // State from nsDocument
   clone->mType = mType;
   clone->mXMLDeclarationBits = mXMLDeclarationBits;
   clone->mBaseTarget = mBaseTarget;
+
+  // Preallocate attributes and child arrays
+  rv = clone->mChildren.EnsureCapacityToClone(mChildren, aPreallocateChildren);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   return NS_OK;
 }
 
 void
 nsDocument::SetReadyStateInternal(ReadyState rs)
 {
   mReadyState = rs;
   if (rs == READYSTATE_UNINITIALIZED) {
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -807,17 +807,18 @@ public:
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
   virtual nsIContent *GetChildAt(uint32_t aIndex) const override;
   virtual nsIContent * const * GetChildArray(uint32_t* aChildCount) const override;
   virtual int32_t IndexOf(const nsINode* aPossibleChild) const override;
   virtual uint32_t GetChildCount() const override;
   virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
                                  bool aNotify) override;
   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override
   {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   // nsIRadioGroupContainer
   NS_IMETHOD WalkRadioGroup(const nsAString& aName,
                             nsIRadioVisitor* aVisitor,
                             bool aFlushContent) override;
@@ -1006,17 +1007,17 @@ public:
   }
 
   void SetLoadedAsData(bool aLoadedAsData) { mLoadedAsData = aLoadedAsData; }
   void SetLoadedAsInteractiveData(bool aLoadedAsInteractiveData)
   {
     mLoadedAsInteractiveData = aLoadedAsInteractiveData;
   }
 
-  nsresult CloneDocHelper(nsDocument* clone) const;
+  nsresult CloneDocHelper(nsDocument* clone, bool aPreallocateChildren) const;
 
   void MaybeInitializeFinalizeFrameLoaders();
 
   void MaybeEndOutermostXBLUpdate();
 
   virtual void PreloadPictureOpened() override;
   virtual void PreloadPictureClosed() override;
 
--- a/dom/base/nsGenericDOMDataNode.h
+++ b/dom/base/nsGenericDOMDataNode.h
@@ -162,17 +162,18 @@ public:
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
   virtual bool IsLink(nsIURI** aURI) const override;
 
   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
   virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
                                               int32_t aModType) const;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override
   {
     nsCOMPtr<nsINode> result = CloneDataNode(aNodeInfo, true);
     result.forget(aResult);
 
     if (!*aResult) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1565,17 +1565,18 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
 #endif
     mCleanedUp(false),
     mDialogAbuseCount(0),
     mAreDialogsEnabled(true),
 #ifdef DEBUG
     mIsValidatingTabGroup(false),
 #endif
     mCanSkipCCGeneration(0),
-    mAutoActivateVRDisplayID(0)
+    mAutoActivateVRDisplayID(0),
+    mBeforeUnloadListenerCount(0)
 {
   AssertIsOnMainThread();
 
   nsLayoutStatics::AddRef();
 
   // Initialize the PRCList (this).
   PR_INIT_CLIST(this);
 
@@ -1602,16 +1603,23 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
       Preferences::AddStrongObserver(mObserver, "intl.accept_languages");
     }
   } else {
     // |this| is an outer window. Outer windows start out frozen and
     // remain frozen until they get an inner window.
     MOZ_ASSERT(IsFrozen());
   }
 
+  if (XRE_IsContentProcess()) {
+    nsCOMPtr<nsIDocShell> docShell = GetDocShell();
+    if (docShell) {
+      mTabChild = docShell->GetTabChild();
+    }
+  }
+
   // We could have failed the first time through trying
   // to create the entropy collector, so we should
   // try to get one until we succeed.
 
   gRefCnt++;
 
   static bool sFirstTime = true;
   if (sFirstTime) {
@@ -2117,16 +2125,22 @@ nsGlobalWindow::FreeInnerObjects()
   mAudioContexts.Clear();
 
   DisableGamepadUpdates();
   mHasGamepad = false;
   mGamepads.Clear();
   DisableVRUpdates();
   mHasVREvents = false;
   mVRDisplays.Clear();
+
+  if (mTabChild) {
+    while (mBeforeUnloadListenerCount-- > 0) {
+      mTabChild->BeforeUnloadRemoved();
+    }
+  }
 }
 
 //*****************************************************************************
 // nsGlobalWindow::nsISupports
 //*****************************************************************************
 
 // QueryInterface implementation for nsGlobalWindow
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
@@ -2256,16 +2270,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDoc)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor)
   for (IdleRequest* request : tmp->mIdleRequestCallbacks) {
     cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest));
   }
@@ -2339,16 +2354,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
   if (tmp->mApplicationCache) {
     static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())->Disconnect();
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDoc)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChild)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWakeLock)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
@@ -13406,25 +13422,47 @@ nsGlobalWindow::EventListenerAdded(nsIAt
   if (aType == nsGkAtoms::onvrdisplayactivate ||
       aType == nsGkAtoms::onvrdisplayconnect ||
       aType == nsGkAtoms::onvrdisplaydeactivate ||
       aType == nsGkAtoms::onvrdisplaydisconnect ||
       aType == nsGkAtoms::onvrdisplaypresentchange) {
     NotifyVREventListenerAdded();
   }
 
+  if (aType == nsGkAtoms::onbeforeunload &&
+      mTabChild &&
+      (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) {
+    MOZ_ASSERT(IsInnerWindow());
+    mBeforeUnloadListenerCount++;
+    MOZ_ASSERT(mBeforeUnloadListenerCount > 0);
+    mTabChild->BeforeUnloadAdded();
+  }
+
   // We need to initialize localStorage in order to receive notifications.
   if (aType == nsGkAtoms::onstorage) {
     ErrorResult rv;
     GetLocalStorage(rv);
     rv.SuppressException();
   }
 }
 
 void
+nsGlobalWindow::EventListenerRemoved(nsIAtom* aType)
+{
+  if (aType == nsGkAtoms::onbeforeunload &&
+      mTabChild &&
+      (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) {
+    MOZ_ASSERT(IsInnerWindow());
+    mBeforeUnloadListenerCount--;
+    MOZ_ASSERT(mBeforeUnloadListenerCount >= 0);
+    mTabChild->BeforeUnloadRemoved();
+  }
+}
+
+void
 nsGlobalWindow::NotifyVREventListenerAdded()
 {
   MOZ_ASSERT(IsInnerWindow());
   mHasVREvents = true;
   EnableVRUpdates();
 }
 
 bool
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -82,16 +82,17 @@ class nsIContent;
 class nsICSSDeclaration;
 class nsIDocShellTreeOwner;
 class nsIDOMOfflineResourceList;
 class nsIScrollableFrame;
 class nsIControllers;
 class nsIJSID;
 class nsIScriptContext;
 class nsIScriptTimeoutHandler;
+class nsITabChild;
 class nsITimeoutHandler;
 class nsIWebBrowserChrome;
 class mozIDOMWindowProxy;
 
 class nsDOMWindowList;
 class nsScreen;
 class nsHistory;
 class nsGlobalWindowObserver;
@@ -454,16 +455,18 @@ public:
 
   // Inner windows only.
   virtual void SetHasGamepadEventListener(bool aHasGamepad = true) override;
   void NotifyVREventListenerAdded();
   bool HasUsedVR() const;
 
   using EventTarget::EventListenerAdded;
   virtual void EventListenerAdded(nsIAtom* aType) override;
+  using EventTarget::EventListenerRemoved;
+  virtual void EventListenerRemoved(nsIAtom* aType) override;
 
   // nsIInterfaceRequestor
   NS_DECL_NSIINTERFACEREQUESTOR
 
   // WebIDL interface.
   already_AddRefed<nsPIDOMWindowOuter> IndexedGetterOuter(uint32_t aIndex);
   already_AddRefed<nsPIDOMWindowOuter> IndexedGetter(uint32_t aIndex);
 
@@ -1947,16 +1950,18 @@ protected:
   // These member variable are used only on inner windows.
   RefPtr<mozilla::EventListenerManager> mListenerManager;
   RefPtr<mozilla::dom::Location> mLocation;
   RefPtr<nsHistory>           mHistory;
   RefPtr<mozilla::dom::CustomElementRegistry> mCustomElements;
 
   // These member variables are used on both inner and the outer windows.
   nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
+  // mTabChild is only ever populated in the content process.
+  nsCOMPtr<nsITabChild>  mTabChild;
 
   uint32_t mSuspendDepth;
   uint32_t mFreezeDepth;
 
   // the method that was used to focus mFocusedNode
   uint32_t mFocusMethod;
 
   uint32_t mSerial;
@@ -2035,16 +2040,17 @@ protected:
   nsTArray<RefPtr<mozilla::dom::VRDisplay>> mVRDisplays;
 
   RefPtr<mozilla::dom::VREventObserver> mVREventObserver;
 
   // When non-zero, the document should receive a vrdisplayactivate event
   // after loading.  The value is the ID of the VRDisplay that content should
   // begin presentation on.
   uint32_t mAutoActivateVRDisplayID; // Outer windows only
+  int64_t mBeforeUnloadListenerCount; // Inner windows only
 
 #ifdef ENABLE_INTL_API
   RefPtr<mozilla::dom::IntlUtils> mIntlUtils;
 #endif
 
   friend class nsDOMScriptableHelper;
   friend class nsDOMWindowUtils;
   friend class mozilla::dom::PostMessageEvent;
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -1079,18 +1079,21 @@ public:
   /**
    * Clones this node. This needs to be overriden by all node classes. aNodeInfo
    * should be identical to this node's nodeInfo, except for the document which
    * may be different. When cloning an element, all attributes of the element
    * will be cloned. The children of the node will not be cloned.
    *
    * @param aNodeInfo the nodeinfo to use for the clone
    * @param aResult the clone
+   * @param aPreallocateChildren If true, the array of children will be
+   *                             preallocated in preparation for a deep copy.
    */
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const = 0;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const = 0;
 
   // This class can be extended by subclasses that wish to store more
   // information in the slots.
   class nsSlots
   {
   public:
     nsSlots();
 
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -468,17 +468,17 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
 
     nodeInfo = newNodeInfo;
   }
 
   Element *elem = aNode->IsElement() ? aNode->AsElement() : nullptr;
 
   nsCOMPtr<nsINode> clone;
   if (aClone) {
-    rv = aNode->Clone(nodeInfo, getter_AddRefs(clone));
+    rv = aNode->Clone(nodeInfo, getter_AddRefs(clone), aDeep);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (clone->IsElement()) {
       // The cloned node may be a custom element that may require
       // enqueing created callback and prototype swizzling.
       Element* elem = clone->AsElement();
       if (nsContentUtils::IsCustomElementName(nodeInfo->NameAtom())) {
         nsContentUtils::SetupCustomElement(elem);
--- a/dom/html/HTMLAnchorElement.h
+++ b/dom/html/HTMLAnchorElement.h
@@ -76,17 +76,18 @@ public:
                            bool aNotify) override;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) override;
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual EventStates IntrinsicState() const override;
 
   virtual void OnDNSPrefetchDeferred() override;
   virtual void OnDNSPrefetchRequested() override;
   virtual bool HasDeferredDNSPrefetchRequest() override;
 
   // WebIDL API
--- a/dom/html/HTMLAreaElement.h
+++ b/dom/html/HTMLAreaElement.h
@@ -62,17 +62,18 @@ public:
     return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
   }
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify) override;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual EventStates IntrinsicState() const override;
 
   // WebIDL
 
   // The XPCOM GetAlt is OK for us
   void SetAlt(const nsAString& aAlt, ErrorResult& aError)
   {
--- a/dom/html/HTMLAudioElement.h
+++ b/dom/html/HTMLAudioElement.h
@@ -24,17 +24,18 @@ public:
   explicit HTMLAudioElement(already_AddRefed<NodeInfo>& aNodeInfo);
 
   // Element
   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
 
   // nsIDOMHTMLMediaElement
   using HTMLMediaElement::GetPaused;
 
-  virtual nsresult Clone(NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
   virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel) override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
   // WebIDL
 
   static already_AddRefed<HTMLAudioElement>
   Audio(const GlobalObject& aGlobal,
--- a/dom/html/HTMLBRElement.h
+++ b/dom/html/HTMLBRElement.h
@@ -20,17 +20,18 @@ public:
   explicit HTMLBRElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   bool Clear()
   {
     return GetBoolAttr(nsGkAtoms::clear);
   }
   void SetClear(const nsAString& aClear, ErrorResult& aError)
   {
     return SetHTMLAttr(nsGkAtoms::clear, aClear, aError);
--- a/dom/html/HTMLBodyElement.h
+++ b/dom/html/HTMLBodyElement.h
@@ -101,17 +101,18 @@ public:
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   virtual already_AddRefed<nsIEditor> GetAssociatedEditor() override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual bool IsEventAttributeName(nsIAtom* aName) override;
 
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   /**
--- a/dom/html/HTMLButtonElement.h
+++ b/dom/html/HTMLButtonElement.h
@@ -57,17 +57,18 @@ public:
 
   // nsIDOMEventTarget
   virtual nsresult GetEventTargetParent(
                      EventChainPreVisitor& aVisitor) override;
   virtual nsresult PostHandleEvent(
                      EventChainPostVisitor& aVisitor) override;
 
   // nsINode
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   // nsIContent
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -556,19 +556,20 @@ HTMLCanvasElement::IsPrintCallbackDone()
 
 HTMLCanvasElement*
 HTMLCanvasElement::GetOriginalCanvas()
 {
   return mOriginalCanvas ? mOriginalCanvas.get() : this;
 }
 
 nsresult
-HTMLCanvasElement::CopyInnerTo(Element* aDest)
+HTMLCanvasElement::CopyInnerTo(Element* aDest,
+                               bool aPreallocateChildren)
 {
-  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
+  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest, aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
   if (aDest->OwnerDoc()->IsStaticDocument()) {
     HTMLCanvasElement* dest = static_cast<HTMLCanvasElement*>(aDest);
     dest->mOriginalCanvas = this;
 
     nsCOMPtr<nsISupports> cxt;
     dest->GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(cxt));
     RefPtr<CanvasRenderingContext2D> context2d =
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -302,18 +302,20 @@ public:
   }
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify) override;
 
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                              bool aNotify) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
-  nsresult CopyInnerTo(mozilla::dom::Element* aDest);
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
+  nsresult CopyInnerTo(mozilla::dom::Element* aDest,
+                       bool aPreallocateChildren);
 
   virtual nsresult GetEventTargetParent(
                      mozilla::EventChainPreVisitor& aVisitor) override;
 
   /*
    * Helpers called by various users of Canvas
    */
 
--- a/dom/html/HTMLContentElement.h
+++ b/dom/html/HTMLContentElement.h
@@ -35,17 +35,18 @@ public:
       return static_cast<HTMLContentElement*>(aContent);
     }
 
     return nullptr;
   }
 
   virtual bool IsHTMLContentElement() const override { return true; }
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
 
   virtual void UnbindFromTree(bool aDeep = true,
--- a/dom/html/HTMLDataElement.h
+++ b/dom/html/HTMLDataElement.h
@@ -26,17 +26,18 @@ public:
     GetHTMLAttr(nsGkAtoms::value, aValue);
   }
 
   void SetValue(const nsAString& aValue, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::value, aValue, aError);
   }
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual ~HTMLDataElement();
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 } // namespace dom
--- a/dom/html/HTMLDataListElement.h
+++ b/dom/html/HTMLDataListElement.h
@@ -29,17 +29,18 @@ public:
     if (!mOptions) {
       mOptions = new nsContentList(this, MatchOptions, nullptr, nullptr, true);
     }
 
     return mOptions;
   }
 
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // This function is used to generate the nsContentList (option elements).
   static bool MatchOptions(Element* aElement, int32_t aNamespaceID,
                            nsIAtom* aAtom, void* aData);
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLDataListElement,
                                            nsGenericHTMLElement)
 protected:
--- a/dom/html/HTMLDetailsElement.h
+++ b/dom/html/HTMLDetailsElement.h
@@ -27,17 +27,18 @@ public:
     : nsGenericHTMLElement(aNodeInfo)
   {
   }
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLDetailsElement, details)
 
   nsIContent* GetFirstSummary() const;
 
-  nsresult Clone(NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  nsresult Clone(NodeInfo* aNodeInfo, nsINode** aResult,
+                 bool aPreallocateChildren) const override;
 
   nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
                                       int32_t aModType) const override;
 
   nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                          const nsAttrValueOrString* aValue,
                          bool aNotify) override;
 
--- a/dom/html/HTMLDialogElement.h
+++ b/dom/html/HTMLDialogElement.h
@@ -19,17 +19,18 @@ class HTMLDialogElement final : public n
 {
 public:
   explicit HTMLDialogElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo) : nsGenericHTMLElement(aNodeInfo)
   {
   }
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLDialogElement, dialog)
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
   static bool IsDialogEnabled();
 
   bool Open() const { return GetBoolAttr(nsGkAtoms::open); }
   void SetOpen(bool aOpen, ErrorResult& aError)
   {
     SetHTMLBoolAttr(nsGkAtoms::open, aOpen, aError);
   }
--- a/dom/html/HTMLDivElement.h
+++ b/dom/html/HTMLDivElement.h
@@ -30,17 +30,18 @@ public:
   }
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual ~HTMLDivElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
--- a/dom/html/HTMLElement.cpp
+++ b/dom/html/HTMLElement.cpp
@@ -13,17 +13,18 @@ namespace dom {
 
 class HTMLElement final : public nsGenericHTMLElement
 {
 public:
   explicit HTMLElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual ~HTMLElement();
 
   virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo,
-                         nsINode** aResult) const override;
+                         nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 HTMLElement::HTMLElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
 {
--- a/dom/html/HTMLFieldSetElement.h
+++ b/dom/html/HTMLFieldSetElement.h
@@ -48,17 +48,18 @@ public:
   virtual nsresult InsertChildAt(nsIContent* aChild, uint32_t aIndex,
                                      bool aNotify) override;
   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
 
   // nsIFormControl
   NS_IMETHOD Reset() override;
   NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
   virtual bool IsDisabledForEvents(EventMessage aMessage) override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   const nsIContent* GetFirstLegend() const { return mFirstLegend; }
 
   void AddElement(nsGenericHTMLFormElement* aElement);
 
   void RemoveElement(nsGenericHTMLFormElement* aElement);
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLFieldSetElement,
--- a/dom/html/HTMLFontElement.h
+++ b/dom/html/HTMLFontElement.h
@@ -46,17 +46,18 @@ public:
   }
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual ~HTMLFontElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
--- a/dom/html/HTMLFormElement.h
+++ b/dom/html/HTMLFormElement.h
@@ -117,17 +117,18 @@ public:
                                 const nsAttrValue* aValue, bool aNotify) override;
 
   /**
    * Forget all information about the current submission (and the fact that we
    * are currently submitting at all).
    */
   void ForgetCurrentSubmission();
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLFormElement,
                                            nsGenericHTMLElement)
 
   /**
    * Remove an element from this form's list of elements
    *
    * @param aElement the element to remove
--- a/dom/html/HTMLFrameElement.h
+++ b/dom/html/HTMLFrameElement.h
@@ -30,17 +30,18 @@ public:
   // nsIDOMHTMLFrameElement
   NS_DECL_NSIDOMHTMLFRAMEELEMENT
 
   // nsIContent
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL API
   // The XPCOM GetFrameBorder is OK for us
   void SetFrameBorder(const nsAString& aFrameBorder, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::frameborder, aFrameBorder, aError);
   }
 
--- a/dom/html/HTMLFrameSetElement.h
+++ b/dom/html/HTMLFrameSetElement.h
@@ -131,17 +131,18 @@ public:
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
                                               int32_t aModType) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual ~HTMLFrameSetElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   nsresult ParseRowCol(const nsAString& aValue,
--- a/dom/html/HTMLHRElement.h
+++ b/dom/html/HTMLHRElement.h
@@ -30,17 +30,18 @@ public:
   NS_DECL_NSIDOMHTMLHRELEMENT
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL API
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
 
   // The XPCOM GetColor is OK for us
--- a/dom/html/HTMLHeadingElement.h
+++ b/dom/html/HTMLHeadingElement.h
@@ -22,17 +22,18 @@ public:
   }
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     return SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
   void GetAlign(DOMString& aAlign) const
   {
     return GetHTMLAttr(nsGkAtoms::align, aAlign);
--- a/dom/html/HTMLIFrameElement.h
+++ b/dom/html/HTMLIFrameElement.h
@@ -39,17 +39,18 @@ public:
   // nsIContent
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                    const nsAString& aValue, bool aNotify)
   {
     return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
   }
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -805,25 +805,25 @@ HTMLImageElement::NaturalWidth()
 NS_IMETHODIMP
 HTMLImageElement::GetNaturalWidth(uint32_t* aNaturalWidth)
 {
   *aNaturalWidth = NaturalWidth();
   return NS_OK;
 }
 
 nsresult
-HTMLImageElement::CopyInnerTo(Element* aDest)
+HTMLImageElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren)
 {
   bool destIsStatic = aDest->OwnerDoc()->IsStaticDocument();
   auto dest = static_cast<HTMLImageElement*>(aDest);
   if (destIsStatic) {
     CreateStaticImageClone(dest);
   }
 
-  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
+  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest, aPreallocateChildren);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   if (!destIsStatic) {
     // In SetAttr (called from nsGenericHTMLElement::CopyInnerTo), dest skipped
     // doing the image load because we passed in false for aNotify.  But we
     // really do want it to do the load, so set it up to happen once the cloning
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -87,21 +87,22 @@ public:
                            bool aNotify) override;
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
 
   virtual EventStates IntrinsicState() const override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual void NodeInfoChanged(nsIDocument* aOldDoc) override;
 
-  nsresult CopyInnerTo(Element* aDest);
+  nsresult CopyInnerTo(Element* aDest, bool aPreallocateChildren);
 
   void MaybeLoadImage();
 
   bool IsMap()
   {
     return GetBoolAttr(nsGkAtoms::ismap);
   }
   void SetIsMap(bool aIsMap, ErrorResult& aError)
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -1280,25 +1280,26 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION
 NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElementWithState)
 
 // nsIConstraintValidation
 NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(HTMLInputElement)
 
 // nsIDOMNode
 
 nsresult
-HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const
+HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                        bool aPreallocateArrays) const
 {
   *aResult = nullptr;
 
   already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
   RefPtr<HTMLInputElement> it = new HTMLInputElement(ni, NOT_FROM_PARSER,
                                                      FromClone::yes);
 
-  nsresult rv = const_cast<HTMLInputElement*>(this)->CopyInnerTo(it);
+  nsresult rv = const_cast<HTMLInputElement*>(this)->CopyInnerTo(it, aPreallocateArrays);
   NS_ENSURE_SUCCESS(rv, rv);
 
   switch (GetValueMode()) {
     case VALUE_MODE_VALUE:
       if (mValueChanged) {
         // We don't have our default value anymore.  Set our value on
         // the clone.
         nsAutoString value;
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -280,17 +280,18 @@ public:
    * Helper function returning the currently selected button in the radio group.
    * Returning null if the element is not a button or if there is no selectied
    * button in the group.
    *
    * @return the selected button (or null).
    */
   already_AddRefed<nsIDOMHTMLInputElement> GetSelectedRadioButton() const;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLInputElement,
                                            nsGenericHTMLFormElementWithState)
 
   static UploadLastDir* gUploadLastDir;
   // create and destroy the static UploadLastDir object for remembering
   // which directory was last used on a site-by-site basis
   static void InitUploadLastDir();
--- a/dom/html/HTMLLIElement.h
+++ b/dom/html/HTMLLIElement.h
@@ -31,17 +31,18 @@ public:
   NS_DECL_NSIDOMHTMLLIELEMENT
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL API
   void GetType(DOMString& aType)
   {
     GetHTMLAttr(nsGkAtoms::type, aType);
   }
   void SetType(const nsAString& aType, mozilla::ErrorResult& rv)
   {
--- a/dom/html/HTMLLabelElement.h
+++ b/dom/html/HTMLLabelElement.h
@@ -61,17 +61,18 @@ public:
 
   virtual bool IsDisabled() const override { return false; }
 
   // nsIContent
   virtual nsresult PostHandleEvent(
                      EventChainPostVisitor& aVisitor) override;
   virtual bool PerformAccesskey(bool aKeyCausesActivation,
                                 bool aIsTrustedEvent) override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   nsGenericHTMLElement* GetLabeledElement() const;
 protected:
   virtual ~HTMLLabelElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   nsGenericHTMLElement* GetFirstLabelableDescendant() const;
--- a/dom/html/HTMLLegendElement.h
+++ b/dom/html/HTMLLegendElement.h
@@ -48,17 +48,18 @@ public:
     return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
   }
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify) override;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
   Element* GetFormElement() const
   {
     nsCOMPtr<nsIFormControl> fieldsetControl = do_QueryInterface(GetFieldSet());
 
     return fieldsetControl ? fieldsetControl->GetFormElement() : nullptr;
   }
 
--- a/dom/html/HTMLLinkElement.h
+++ b/dom/html/HTMLLinkElement.h
@@ -47,17 +47,18 @@ public:
 
   // nsIDOMEventTarget
   virtual nsresult GetEventTargetParent(
                      EventChainPreVisitor& aVisitor) override;
   virtual nsresult PostHandleEvent(
                      EventChainPostVisitor& aVisitor) override;
 
   // nsINode
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   // nsIContent
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
--- a/dom/html/HTMLMapElement.h
+++ b/dom/html/HTMLMapElement.h
@@ -24,17 +24,18 @@ public:
   explicit HTMLMapElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMHTMLMapElement
   NS_DECL_NSIDOMHTMLMAPELEMENT
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(HTMLMapElement,
                                                      nsGenericHTMLElement)
 
   // XPCOM GetName is fine.
   void SetName(const nsAString& aName, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::name, aName, aError);
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -6371,19 +6371,19 @@ already_AddRefed<nsILoadGroup> HTMLMedia
 {
   if (!OwnerDoc()->IsActive()) {
     NS_WARNING("Load group requested for media element in inactive document.");
   }
   return OwnerDoc()->GetDocumentLoadGroup();
 }
 
 nsresult
-HTMLMediaElement::CopyInnerTo(Element* aDest)
-{
-  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
+HTMLMediaElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren)
+{
+  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest, aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
   if (aDest->OwnerDoc()->IsStaticDocument()) {
     HTMLMediaElement* dest = static_cast<HTMLMediaElement*>(aDest);
     dest->SetMediaInfo(mMediaInfo);
   }
   return rv;
 }
 
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -380,17 +380,17 @@ public:
   already_AddRefed<nsILoadGroup> GetDocumentLoadGroup();
 
   /**
    * Returns true if the media has played or completed a seek.
    * Used by video frame to determine whether to paint the poster.
    */
   bool GetPlayedOrSeeked() const { return mHasPlayedOrSeeked; }
 
-  nsresult CopyInnerTo(Element* aDest);
+  nsresult CopyInnerTo(Element* aDest, bool aPreallocateChildren);
 
   /**
    * Sets the Accept header on the HTTP channel to the required
    * video or audio MIME types.
    */
   virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel) = 0;
 
   /**
--- a/dom/html/HTMLMenuElement.h
+++ b/dom/html/HTMLMenuElement.h
@@ -32,17 +32,18 @@ public:
 
   nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                         const nsAttrValue* aValue, bool aNotify) override;
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   uint8_t GetType() const { return mType; }
 
   // WebIDL
 
   // The XPCOM GetType is OK for us
   void SetType(const nsAString& aType, ErrorResult& aError)
   {
--- a/dom/html/HTMLMenuItemElement.cpp
+++ b/dom/html/HTMLMenuItemElement.cpp
@@ -173,23 +173,24 @@ HTMLMenuItemElement::~HTMLMenuItemElemen
 }
 
 
 NS_IMPL_ISUPPORTS_INHERITED(HTMLMenuItemElement, nsGenericHTMLElement,
                             nsIDOMHTMLMenuItemElement)
 
 //NS_IMPL_ELEMENT_CLONE(HTMLMenuItemElement)
 nsresult
-HTMLMenuItemElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+HTMLMenuItemElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                           bool aPreallocateArrays) const
 {
   *aResult = nullptr;
   already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
   RefPtr<HTMLMenuItemElement> it =
     new HTMLMenuItemElement(ni, NOT_FROM_PARSER);
-  nsresult rv = const_cast<HTMLMenuItemElement*>(this)->CopyInnerTo(it);
+  nsresult rv = const_cast<HTMLMenuItemElement*>(this)->CopyInnerTo(it, aPreallocateArrays);
   if (NS_SUCCEEDED(rv)) {
     switch (mType) {
       case CMD_TYPE_CHECKBOX:
       case CMD_TYPE_RADIO:
         if (mCheckedDirty) {
           // We no longer have our original checked state.  Set our
           // checked state on the clone.
           it->mCheckedDirty = true;
--- a/dom/html/HTMLMenuItemElement.h
+++ b/dom/html/HTMLMenuItemElement.h
@@ -47,17 +47,18 @@ public:
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
 
   virtual void DoneCreatingElement() override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   uint8_t GetType() const { return mType; }
 
   /**
    * Syntax sugar to make it easier to check for checked and checked dirty
    */
   bool IsChecked() const { return mChecked; }
   bool IsCheckedDirty() const { return mCheckedDirty; }
--- a/dom/html/HTMLMetaElement.h
+++ b/dom/html/HTMLMetaElement.h
@@ -32,17 +32,18 @@ public:
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify) override;
 
   void CreateAndDispatchEvent(nsIDocument* aDoc, const nsAString& aEventName);
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // XPCOM GetName is fine.
   void SetName(const nsAString& aName, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::name, aName, aRv);
   }
   // XPCOM GetHttpEquiv is fine.
   void SetHttpEquiv(const nsAString& aHttpEquiv, ErrorResult& aRv)
--- a/dom/html/HTMLMeterElement.h
+++ b/dom/html/HTMLMeterElement.h
@@ -19,17 +19,18 @@ namespace dom {
 
 class HTMLMeterElement final : public nsGenericHTMLElement
 {
 public:
   explicit HTMLMeterElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   virtual EventStates IntrinsicState() const override;
 
-  nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                 bool aPreallocateChildren) const override;
 
   bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
                       const nsAString& aValue, nsAttrValue& aResult) override;
 
   // WebIDL
 
   /* @return the value */
   double Value() const;
--- a/dom/html/HTMLModElement.h
+++ b/dom/html/HTMLModElement.h
@@ -14,17 +14,18 @@
 namespace mozilla {
 namespace dom {
 
 class HTMLModElement final : public nsGenericHTMLElement
 {
 public:
   explicit HTMLModElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   void GetCite(nsString& aCite)
   {
     GetHTMLURIAttr(nsGkAtoms::cite, aCite);
   }
   void SetCite(const nsAString& aCite, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::cite, aCite, aRv);
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -565,19 +565,20 @@ HTMLObjectElement::GetCapabilities() con
 void
 HTMLObjectElement::DestroyContent()
 {
   nsObjectLoadingContent::DestroyContent();
   nsGenericHTMLFormElement::DestroyContent();
 }
 
 nsresult
-HTMLObjectElement::CopyInnerTo(Element* aDest)
+HTMLObjectElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren)
 {
-  nsresult rv = nsGenericHTMLFormElement::CopyInnerTo(aDest);
+  nsresult rv = nsGenericHTMLFormElement::CopyInnerTo(aDest,
+                                                      aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aDest->OwnerDoc()->IsStaticDocument()) {
     CreateStaticClone(static_cast<HTMLObjectElement*>(aDest));
   }
 
   return rv;
 }
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -84,19 +84,20 @@ public:
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom *aAttribute) const override;
   virtual EventStates IntrinsicState() const override;
   virtual void DestroyContent() override;
 
   // nsObjectLoadingContent
   virtual uint32_t GetCapabilities() const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
-  nsresult CopyInnerTo(Element* aDest);
+  nsresult CopyInnerTo(Element* aDest, bool aPreallocateChildren);
 
   void StartObjectLoad() { StartObjectLoad(true, false); }
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLObjectElement,
                                            nsGenericHTMLFormElement)
 
   // Web IDL binding methods
   // XPCOM GetData is ok; note that it's a URI attribute with a weird base URI
--- a/dom/html/HTMLOptGroupElement.h
+++ b/dom/html/HTMLOptGroupElement.h
@@ -35,17 +35,18 @@ public:
   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
 
   // nsIContent
   virtual nsresult GetEventTargetParent(
                      EventChainPreVisitor& aVisitor) override;
 
   virtual EventStates IntrinsicState() const override;
  
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify) override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
   virtual bool IsDisabled() const override {
     return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
--- a/dom/html/HTMLOptionElement.cpp
+++ b/dom/html/HTMLOptionElement.cpp
@@ -432,19 +432,19 @@ HTMLOptionElement::Option(const GlobalOb
       }
     }
   }
 
   return option.forget();
 }
 
 nsresult
-HTMLOptionElement::CopyInnerTo(Element* aDest)
+HTMLOptionElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren)
 {
-  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
+  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest, aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aDest->OwnerDoc()->IsStaticDocument()) {
     static_cast<HTMLOptionElement*>(aDest)->SetSelected(Selected());
   }
   return NS_OK;
 }
 
--- a/dom/html/HTMLOptionElement.h
+++ b/dom/html/HTMLOptionElement.h
@@ -58,19 +58,20 @@ public:
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
   // nsIContent
   virtual EventStates IntrinsicState() const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
-  nsresult CopyInnerTo(mozilla::dom::Element* aDest);
+  nsresult CopyInnerTo(mozilla::dom::Element* aDest, bool aPreallocateChildren);
 
   virtual bool IsDisabled() const override {
     return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
   }
 
   bool Disabled() const
   {
     return GetBoolAttr(nsGkAtoms::disabled);
--- a/dom/html/HTMLOutputElement.h
+++ b/dom/html/HTMLOutputElement.h
@@ -31,17 +31,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIFormControl
   NS_IMETHOD Reset() override;
   NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
 
   virtual bool IsDisabled() const override { return false; }
 
-  nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                 bool aPreallocateChildren) const override;
 
   bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
                         const nsAString& aValue, nsAttrValue& aResult) override;
 
   virtual void DoneAddingChildren(bool aHaveNotified) override;
 
   EventStates IntrinsicState() const override;
 
--- a/dom/html/HTMLParagraphElement.h
+++ b/dom/html/HTMLParagraphElement.h
@@ -32,17 +32,18 @@ public:
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL API
   // The XPCOM GetAlign is fine for our purposes
   void SetAlign(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::align, aValue, rv);
   }
 
--- a/dom/html/HTMLPictureElement.h
+++ b/dom/html/HTMLPictureElement.h
@@ -21,17 +21,18 @@ public:
   explicit HTMLPictureElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMHTMLPictureElement
   NS_DECL_NSIDOMHTMLPICTUREELEMENT
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
   virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify) override;
 
 protected:
   virtual ~HTMLPictureElement();
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
--- a/dom/html/HTMLPreElement.h
+++ b/dom/html/HTMLPreElement.h
@@ -33,17 +33,18 @@ public:
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL API
   int32_t Width() const
   {
     return GetIntAttr(nsGkAtoms::width, 0);
   }
   void SetWidth(int32_t aWidth, mozilla::ErrorResult& rv)
   {
--- a/dom/html/HTMLProgressElement.h
+++ b/dom/html/HTMLProgressElement.h
@@ -18,17 +18,18 @@ namespace dom {
 
 class HTMLProgressElement final : public nsGenericHTMLElement
 {
 public:
   explicit HTMLProgressElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   EventStates IntrinsicState() const override;
 
-  nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                 bool aPreallocateChildren) const override;
 
   bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
                         const nsAString& aValue, nsAttrValue& aResult) override;
 
   // WebIDL
   double Value() const;
   void SetValue(double aValue, ErrorResult& aRv)
   {
--- a/dom/html/HTMLScriptElement.cpp
+++ b/dom/html/HTMLScriptElement.cpp
@@ -88,25 +88,26 @@ HTMLScriptElement::ParseAttribute(int32_
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
 nsresult
-HTMLScriptElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+HTMLScriptElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const
 {
   *aResult = nullptr;
 
   already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
   HTMLScriptElement* it = new HTMLScriptElement(ni, NOT_FROM_PARSER);
 
   nsCOMPtr<nsINode> kungFuDeathGrip = it;
-  nsresult rv = const_cast<HTMLScriptElement*>(this)->CopyInnerTo(it);
+  nsresult rv = const_cast<HTMLScriptElement*>(this)->CopyInnerTo(it, aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // The clone should be marked evaluated if we are.
   it->mAlreadyStarted = mAlreadyStarted;
   it->mLineNumber = mLineNumber;
   it->mMalformed = mMalformed;
 
   kungFuDeathGrip.swap(*aResult);
--- a/dom/html/HTMLScriptElement.h
+++ b/dom/html/HTMLScriptElement.h
@@ -48,17 +48,18 @@ public:
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // Element
   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify) override;
 
   // WebIDL
   void SetText(const nsAString& aValue, ErrorResult& rv);
   void SetCharset(const nsAString& aCharset, ErrorResult& rv);
--- a/dom/html/HTMLSelectElement.h
+++ b/dom/html/HTMLSelectElement.h
@@ -397,17 +397,18 @@ public:
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
                                               int32_t aModType) const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLSelectElement,
                                            nsGenericHTMLFormElementWithState)
 
   HTMLOptionsCollection* GetOptions()
   {
     return mOptions;
   }
--- a/dom/html/HTMLShadowElement.h
+++ b/dom/html/HTMLShadowElement.h
@@ -34,17 +34,18 @@ public:
       return static_cast<HTMLShadowElement*>(aContent);
     }
 
     return nullptr;
   }
 
   virtual bool IsHTMLShadowElement() const override { return true; }
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
 
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
--- a/dom/html/HTMLSharedElement.h
+++ b/dom/html/HTMLSharedElement.h
@@ -76,17 +76,18 @@ public:
                               bool aCompileEventHandlers) override;
 
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL API
   // HTMLParamElement
   void GetName(DOMString& aValue)
   {
     MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::param));
     GetHTMLAttr(nsGkAtoms::name, aValue);
   }
--- a/dom/html/HTMLSharedListElement.h
+++ b/dom/html/HTMLSharedListElement.h
@@ -36,17 +36,18 @@ public:
   // fully declared by NS_DECL_NSIDOMHTMLOLISTELEMENT
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   bool Reversed() const
   {
     return GetBoolAttr(nsGkAtoms::reversed);
   }
   void SetReversed(bool aReversed, mozilla::ErrorResult& rv)
   {
     SetHTMLBoolAttr(nsGkAtoms::reversed, aReversed, rv);
--- a/dom/html/HTMLSharedObjectElement.cpp
+++ b/dom/html/HTMLSharedObjectElement.cpp
@@ -341,19 +341,19 @@ HTMLSharedObjectElement::GetCapabilities
 void
 HTMLSharedObjectElement::DestroyContent()
 {
   nsObjectLoadingContent::DestroyContent();
   nsGenericHTMLElement::DestroyContent();
 }
 
 nsresult
-HTMLSharedObjectElement::CopyInnerTo(Element* aDest)
+HTMLSharedObjectElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren)
 {
-  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
+  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest, aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aDest->OwnerDoc()->IsStaticDocument()) {
     CreateStaticClone(static_cast<HTMLSharedObjectElement*>(aDest));
   }
 
   return rv;
 }
--- a/dom/html/HTMLSharedObjectElement.h
+++ b/dom/html/HTMLSharedObjectElement.h
@@ -74,19 +74,20 @@ public:
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom *aAttribute) const override;
   virtual EventStates IntrinsicState() const override;
   virtual void DestroyContent() override;
 
   // nsObjectLoadingContent
   virtual uint32_t GetCapabilities() const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
-  nsresult CopyInnerTo(Element* aDest);
+  nsresult CopyInnerTo(Element* aDest, bool aPreallocateChildren);
 
   void StartObjectLoad() { StartObjectLoad(true, false); }
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(HTMLSharedObjectElement,
                                                      nsGenericHTMLElement)
 
   // WebIDL API for <applet>
   void GetAlign(DOMString& aValue)
--- a/dom/html/HTMLSourceElement.h
+++ b/dom/html/HTMLSourceElement.h
@@ -30,17 +30,18 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLSourceElement,
                                            nsGenericHTMLElement)
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLSourceElement, source)
 
   // nsIDOMHTMLSourceElement
   NS_DECL_NSIDOMHTMLSOURCEELEMENT
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
   // Override BindToTree() so that we can trigger a load when we add a
   // child source element.
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
 
   // If this element's media attr matches for its owner document.  Returns true
--- a/dom/html/HTMLSpanElement.h
+++ b/dom/html/HTMLSpanElement.h
@@ -21,17 +21,18 @@ namespace dom {
 class HTMLSpanElement final : public nsGenericHTMLElement
 {
 public:
   explicit HTMLSpanElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : nsGenericHTMLElement(aNodeInfo)
   {
   }
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual ~HTMLSpanElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 } // namespace dom
--- a/dom/html/HTMLStyleElement.h
+++ b/dom/html/HTMLStyleElement.h
@@ -45,17 +45,18 @@ public:
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue,
                                 bool aNotify) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   bool Disabled();
--- a/dom/html/HTMLSummaryElement.h
+++ b/dom/html/HTMLSummaryElement.h
@@ -24,17 +24,18 @@ public:
 
   explicit HTMLSummaryElement(already_AddRefed<NodeInfo>& aNodeInfo)
     : nsGenericHTMLElement(aNodeInfo)
   {
   }
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLSummaryElement, summary)
 
-  nsresult Clone(NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  nsresult Clone(NodeInfo* aNodeInfo, nsINode** aResult,
+                 bool aPreallocateChildren) const override;
 
   nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
 
   bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
                        int32_t* aTabIndex) override;
 
   int32_t TabIndexDefault() override;
 
--- a/dom/html/HTMLTableCaptionElement.h
+++ b/dom/html/HTMLTableCaptionElement.h
@@ -32,17 +32,18 @@ public:
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual ~HTMLTableCaptionElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
--- a/dom/html/HTMLTableCellElement.h
+++ b/dom/html/HTMLTableCellElement.h
@@ -146,17 +146,18 @@ public:
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
   // Get mapped attributes of ancestor table, if any
   nsMappedAttributes* GetMappedAttributesInheritedFromTable() const;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual ~HTMLTableCellElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   HTMLTableElement* GetTable() const;
 
--- a/dom/html/HTMLTableColElement.h
+++ b/dom/html/HTMLTableColElement.h
@@ -74,17 +74,18 @@ public:
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual ~HTMLTableColElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
--- a/dom/html/HTMLTableElement.h
+++ b/dom/html/HTMLTableElement.h
@@ -184,17 +184,18 @@ public:
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
   /**
    * Called when an attribute is about to be changed
--- a/dom/html/HTMLTableRowElement.h
+++ b/dom/html/HTMLTableRowElement.h
@@ -80,17 +80,18 @@ public:
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(HTMLTableRowElement,
                                                      nsGenericHTMLElement)
 
 protected:
   virtual ~HTMLTableRowElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/html/HTMLTableSectionElement.h
+++ b/dom/html/HTMLTableSectionElement.h
@@ -65,17 +65,18 @@ public:
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(HTMLTableSectionElement,
                                                      nsGenericHTMLElement)
 protected:
   virtual ~HTMLTableSectionElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
--- a/dom/html/HTMLTemplateElement.h
+++ b/dom/html/HTMLTemplateElement.h
@@ -21,17 +21,18 @@ public:
   explicit HTMLTemplateElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLTemplateElement,
                                            nsGenericHTMLElement)
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   DocumentFragment* Content()
   {
     return mContent;
   }
 
 protected:
   virtual ~HTMLTemplateElement();
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -97,24 +97,25 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION
                                nsIMutationObserver,
                                nsIConstraintValidation)
 NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElementWithState)
 
 
 // nsIDOMHTMLTextAreaElement
 
 nsresult
-HTMLTextAreaElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+HTMLTextAreaElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                           bool aPreallocateChildren) const
 {
   *aResult = nullptr;
   already_AddRefed<mozilla::dom::NodeInfo> ni =
     RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
   RefPtr<HTMLTextAreaElement> it = new HTMLTextAreaElement(ni);
 
-  nsresult rv = const_cast<HTMLTextAreaElement*>(this)->CopyInnerTo(it);
+  nsresult rv = const_cast<HTMLTextAreaElement*>(this)->CopyInnerTo(it, aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mValueChanged) {
     // Set our value on the clone.
     nsAutoString value;
     GetValueInternal(value, true);
 
     // SetValueInternal handles setting mValueChanged for us
@@ -1115,19 +1116,20 @@ HTMLTextAreaElement::AfterSetAttr(int32_
     }
   }
 
   return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName, aValue,
                                                          aNotify);
   }
 
 nsresult
-HTMLTextAreaElement::CopyInnerTo(Element* aDest)
+HTMLTextAreaElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren)
 {
-  nsresult rv = nsGenericHTMLFormElementWithState::CopyInnerTo(aDest);
+  nsresult rv = nsGenericHTMLFormElementWithState::CopyInnerTo(aDest,
+                                                               aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aDest->OwnerDoc()->IsStaticDocument()) {
     nsAutoString value;
     GetValueInternal(value, true);
     return static_cast<HTMLTextAreaElement*>(aDest)->SetValue(value);
   }
   return NS_OK;
--- a/dom/html/HTMLTextAreaElement.h
+++ b/dom/html/HTMLTextAreaElement.h
@@ -140,19 +140,20 @@ public:
   virtual nsresult PostHandleEvent(
                      EventChainPostVisitor& aVisitor) override;
 
   virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
 
   virtual void DoneAddingChildren(bool aHaveNotified) override;
   virtual bool IsDoneAddingChildren() override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
-  nsresult CopyInnerTo(Element* aDest);
+  nsresult CopyInnerTo(Element* aDest, bool aPreallocateChildren);
 
   /**
    * Called when an attribute is about to be changed
    */
   virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                  const nsAttrValueOrString* aValue,
                                  bool aNotify) override;
 
--- a/dom/html/HTMLTimeElement.h
+++ b/dom/html/HTMLTimeElement.h
@@ -27,17 +27,18 @@ public:
     GetHTMLAttr(nsGkAtoms::datetime, aDateTime);
   }
 
   void SetDateTime(const nsAString& aDateTime, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::datetime, aDateTime, aError);
   }
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/html/HTMLTitleElement.h
+++ b/dom/html/HTMLTitleElement.h
@@ -33,17 +33,18 @@ public:
   void SetText(const nsAString& aText, ErrorResult& aError);
 
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual nsresult BindToTree(nsIDocument *aDocument, nsIContent *aParent,
                               nsIContent *aBindingParent,
                               bool aCompileEventHandlers) override;
 
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
--- a/dom/html/HTMLTrackElement.h
+++ b/dom/html/HTMLTrackElement.h
@@ -85,17 +85,18 @@ public:
     SetHTMLBoolAttr(nsGkAtoms::_default, aDefault, aError);
   }
 
   uint16_t ReadyState() const;
   void SetReadyState(uint16_t aReadyState);
 
   TextTrack* GetTrack();
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
   // Override ParseAttribute() to convert kind strings to enum values.
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
 
   // Override BindToTree() so that we can trigger a load when we become
--- a/dom/html/HTMLUnknownElement.h
+++ b/dom/html/HTMLUnknownElement.h
@@ -26,17 +26,18 @@ public:
   explicit HTMLUnknownElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : nsGenericHTMLElement(aNodeInfo)
   {
     if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
       SetHasDirAuto();
     }
   }
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual ~HTMLUnknownElement() {}
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(HTMLUnknownElement, NS_HTMLUNKNOWNELEMENT_IID)
 
--- a/dom/html/HTMLVideoElement.h
+++ b/dom/html/HTMLVideoElement.h
@@ -36,17 +36,18 @@ public:
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
   static void Init();
 
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
 
-  virtual nsresult Clone(NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // Set size with the current video frame's height and width.
   // If there is no video frame, returns NS_ERROR_FAILURE.
   nsresult GetVideoSize(nsIntSize* size);
 
   virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel) override;
 
   // Element
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -170,19 +170,24 @@ NS_IMPL_RELEASE_INHERITED(nsGenericHTMLE
 
 NS_INTERFACE_MAP_BEGIN(nsGenericHTMLElement)
   NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLElement)
   NS_INTERFACE_MAP_ENTRY(nsIDOMElement)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
 NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElementBase)
 
 nsresult
-nsGenericHTMLElement::CopyInnerTo(Element* aDst)
+nsGenericHTMLElement::CopyInnerTo(Element* aDst, bool aPreallocateChildren)
 {
   nsresult rv;
+
+  rv = static_cast<nsGenericHTMLElement*>(aDst)->mAttrsAndChildren.
+       EnsureCapacityToClone(mAttrsAndChildren, aPreallocateChildren);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   int32_t i, count = GetAttrCount();
   for (i = 0; i < count; ++i) {
     const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
     const nsAttrValue *value = mAttrsAndChildren.AttrAt(i);
 
     nsAutoString valStr;
     value->ToString(valStr);
 
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -63,17 +63,17 @@ public:
     SetFlags(NODE_HAS_DIRECTION_LTR);
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMPL_FROMCONTENT(nsGenericHTMLElement, kNameSpaceID_XHTML)
 
   // From Element
-  nsresult CopyInnerTo(mozilla::dom::Element* aDest);
+  nsresult CopyInnerTo(mozilla::dom::Element* aDest, bool aPreallocateChildren);
 
   void GetTitle(mozilla::dom::DOMString& aTitle)
   {
     GetHTMLAttr(nsGkAtoms::title, aTitle);
   }
   NS_IMETHOD SetTitle(const nsAString& aTitle) override
   {
     SetHTMLAttr(nsGkAtoms::title, aTitle);
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -428,19 +428,20 @@ nsGenericHTMLFrameElement::DestroyConten
     mFrameLoader->Destroy();
     mFrameLoader = nullptr;
   }
 
   nsGenericHTMLElement::DestroyContent();
 }
 
 nsresult
-nsGenericHTMLFrameElement::CopyInnerTo(Element* aDest)
+nsGenericHTMLFrameElement::CopyInnerTo(Element* aDest,
+                                       bool aPreallocateChildren)
 {
-  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
+  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest, aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsIDocument* doc = aDest->OwnerDoc();
   if (doc->IsStaticDocument() && mFrameLoader) {
     nsGenericHTMLFrameElement* dest =
       static_cast<nsGenericHTMLFrameElement*>(aDest);
     nsFrameLoader* fl = nsFrameLoader::Create(dest, nullptr, false);
     NS_ENSURE_STATE(fl);
--- a/dom/html/nsGenericHTMLFrameElement.h
+++ b/dom/html/nsGenericHTMLFrameElement.h
@@ -63,17 +63,17 @@ public:
                            bool aNotify) override;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) override;
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue,
                                 bool aNotify) override;
   virtual void DestroyContent() override;
 
-  nsresult CopyInnerTo(mozilla::dom::Element* aDest);
+  nsresult CopyInnerTo(mozilla::dom::Element* aDest, bool aPreallocateChildren);
 
   virtual int32_t TabIndexDefault() override;
 
   virtual nsIMozBrowserFrame* GetAsMozBrowserFrame() override { return this; }
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGenericHTMLFrameElement,
                                            nsGenericHTMLElement)
 
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -3649,23 +3649,24 @@ nsHTMLDocument::QueryCommandValue(const 
   // regardless.
   nsXPIDLCString cStringResult;
   cmdParams->GetCStringValue("state_attribute",
                              getter_Copies(cStringResult));
   CopyUTF8toUTF16(cStringResult, aValue);
 }
 
 nsresult
-nsHTMLDocument::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+nsHTMLDocument::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                      bool aPreallocateChildren) const
 {
   NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
                "Can't import this document into another document!");
 
   RefPtr<nsHTMLDocument> clone = new nsHTMLDocument();
-  nsresult rv = CloneDocHelper(clone.get());
+  nsresult rv = CloneDocHelper(clone.get(), aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // State from nsHTMLDocument
   clone->mLoadFlags = mLoadFlags;
 
   return CallQueryInterface(clone.get(), aResult);
 }
 
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -143,17 +143,18 @@ public:
   friend class nsAutoEditingState;
 
   void EndUpdate(nsUpdateType aUpdateType) override;
 
   virtual void SetMayStartLayout(bool aMayStartLayout) override;
 
   virtual nsresult SetEditingState(EditingState aState) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual void RemovedFromDocShell() override;
 
   virtual mozilla::dom::Element *GetElementById(const nsAString& aElementId) override
   {
     return nsDocument::GetElementById(aElementId);
   }
 
--- a/dom/interfaces/base/nsITabChild.idl
+++ b/dom/interfaces/base/nsITabChild.idl
@@ -29,10 +29,13 @@ interface nsITabChild : nsISupports
 
   [noscript] void remoteSizeShellTo(in int32_t width, in int32_t height,
                                     in int32_t shellItemWidth, in int32_t shellItemHeight);
 
   [noscript] void remoteDropLinks(in unsigned long linksCount,
                                   [array, size_is(linksCount)] in nsIDroppedLinkItem links);
 
   readonly attribute uint64_t tabId;
+
+  [noscript, notxpcom] void beforeUnloadAdded();
+  [noscript, notxpcom] void beforeUnloadRemoved();
 };
 
--- a/dom/interfaces/base/nsITabParent.idl
+++ b/dom/interfaces/base/nsITabParent.idl
@@ -64,9 +64,15 @@ interface nsITabParent : nsISupports
    */
   readonly attribute boolean hasPresented;
 
   /**
    * Ensures that the content process which has this tab parent has all of the
    * permissions required to load a document with the given principal.
    */
   void transmitPermissionsForPrincipal(in nsIPrincipal aPrincipal);
+
+  /**
+   * True if any of the frames loaded in the TabChild have registered
+   * an onbeforeunload event handler.
+   */
+  readonly attribute boolean hasBeforeUnload;
 };
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -550,16 +550,18 @@ parent:
      * If the number of tabs can't be determined, returns 0.
      *
      * @param aValue where to store the tab count
      */
     sync GetTabCount() returns (uint32_t value);
 
     async AccessKeyNotHandled(WidgetKeyboardEvent event);
 
+    async SetHasBeforeUnload(bool aHasBeforeUnload);
+
 child:
     async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
 
 
 parent:
 
     /**
      * Child informs the parent that the graphics objects are ready for
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -374,16 +374,17 @@ TabChild::TabChild(nsIContentChild* aMan
                    uint32_t aChromeFlags)
   : TabContext(aContext)
   , mTabGroup(aTabGroup)
   , mRemoteFrame(nullptr)
   , mManager(aManager)
   , mChromeFlags(aChromeFlags)
   , mActiveSuppressDisplayport(0)
   , mLayersId(0)
+  , mBeforeUnloadListeners(0)
   , mLayersConnected(true)
   , mDidFakeShow(false)
   , mNotified(false)
   , mTriedBrowserInit(false)
   , mOrientation(eScreenOrientation_PortraitPrimary)
   , mIgnoreKeyPressEvent(false)
   , mHasValidInnerSize(false)
   , mDestroyed(false)
@@ -3310,16 +3311,38 @@ TabChild::ForcePaint(uint64_t aLayerObse
     // message on the PContent channel.
     return;
   }
 
   nsAutoScriptBlocker scriptBlocker;
   RecvSetDocShellIsActive(true, false, aLayerObserverEpoch);
 }
 
+void
+TabChild::BeforeUnloadAdded()
+{
+  if (mBeforeUnloadListeners == 0) {
+    SendSetHasBeforeUnload(true);
+  }
+
+  mBeforeUnloadListeners++;
+  MOZ_ASSERT(mBeforeUnloadListeners >= 0);
+}
+
+void
+TabChild::BeforeUnloadRemoved()
+{
+  mBeforeUnloadListeners--;
+  MOZ_ASSERT(mBeforeUnloadListeners >= 0);
+
+  if (mBeforeUnloadListeners == 0) {
+    SendSetHasBeforeUnload(false);
+  }
+}
+
 already_AddRefed<nsISHistory>
 TabChild::GetRelatedSHistory()
 {
   nsCOMPtr<nsISHistory> shistory;
   mWebNav->GetSessionHistory(getter_AddRefs(shistory));
   return shistory.forget();
 }
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -775,16 +775,17 @@ private:
   RefPtr<PuppetWidget> mPuppetWidget;
   nsCOMPtr<nsIURI> mLastURI;
   RenderFrameChild* mRemoteFrame;
   RefPtr<nsIContentChild> mManager;
   RefPtr<TabChildSHistoryListener> mHistoryListener;
   uint32_t mChromeFlags;
   int32_t mActiveSuppressDisplayport;
   uint64_t mLayersId;
+  int64_t mBeforeUnloadListeners;
   CSSRect mUnscaledOuterRect;
   nscolor mLastBackgroundColor;
   bool mLayersConnected;
   bool mDidFakeShow;
   bool mNotified;
   bool mTriedBrowserInit;
   ScreenOrientationInternal mOrientation;
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -163,16 +163,17 @@ TabParent::TabParent(nsIContentParent* a
   , mTabSetsCursor(false)
   , mHasContentOpener(false)
 #ifdef DEBUG
   , mActiveSupressDisplayportCount(0)
 #endif
   , mLayerTreeEpoch(0)
   , mPreserveLayers(false)
   , mHasPresented(false)
+  , mHasBeforeUnload(false)
 {
   MOZ_ASSERT(aManager);
 }
 
 TabParent::~TabParent()
 {
 }
 
@@ -2020,16 +2021,23 @@ TabParent::RecvAccessKeyNotHandled(const
     NS_ENSURE_TRUE(presContext, IPC_OK());
 
     EventDispatcher::Dispatch(mFrameElement, presContext, &localEvent);
   }
 
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+TabParent::RecvSetHasBeforeUnload(const bool& aHasBeforeUnload)
+{
+  mHasBeforeUnload = aHasBeforeUnload;
+  return IPC_OK();
+}
+
 bool
 TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
   if (NS_WARN_IF(!mContentCache.HandleQueryContentEvent(aEvent, widget)) ||
@@ -2792,16 +2800,23 @@ TabParent::TransmitPermissionsForPrincip
   if (!manager->IsContentParent()) {
     return NS_ERROR_UNEXPECTED;
   }
 
   return manager->AsContentParent()
     ->TransmitPermissionsForPrincipal(aPrincipal);
 }
 
+NS_IMETHODIMP
+TabParent::GetHasBeforeUnload(bool* aResult)
+{
+  *aResult = mHasBeforeUnload;
+  return NS_OK;
+}
+
 class LayerTreeUpdateRunnable final
   : public mozilla::Runnable
 {
   uint64_t mLayersId;
   uint64_t mEpoch;
   bool mActive;
 
 public:
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -165,16 +165,19 @@ public:
 
   virtual mozilla::ipc::IPCResult RecvEvent(const RemoteDOMEvent& aEvent) override;
 
   virtual mozilla::ipc::IPCResult RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) override;
 
   virtual mozilla::ipc::IPCResult
   RecvAccessKeyNotHandled(const WidgetKeyboardEvent& aEvent) override;
 
+  virtual mozilla::ipc::IPCResult
+  RecvSetHasBeforeUnload(const bool& aHasBeforeUnload) override;
+
   virtual mozilla::ipc::IPCResult RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
                                                              PRenderFrameParent* aRenderFrame,
                                                              const nsString& aURL,
                                                              const nsString& aName,
                                                              const nsString& aFeatures,
                                                              bool* aOutWindowOpened,
                                                              TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                                              uint64_t* aLayersId,
@@ -757,16 +760,20 @@ private:
   // If this flag is set, then the tab's layers will be preserved even when
   // the tab's docshell is inactive.
   bool mPreserveLayers;
 
   // True if this TabParent has had its layer tree sent to the compositor
   // at least once.
   bool mHasPresented;
 
+  // True if at least one window hosted in the TabChild has added a
+  // beforeunload event listener.
+  bool mHasBeforeUnload;
+
 public:
   static TabParent* GetTabParentFromLayersId(uint64_t aLayersId);
 };
 
 struct MOZ_STACK_CLASS TabParent::AutoUseNewTab final
 {
 public:
   AutoUseNewTab(TabParent* aNewTab, nsCString* aURLToLoad)
--- a/dom/mathml/nsMathMLElement.h
+++ b/dom/mathml/nsMathMLElement.h
@@ -73,17 +73,18 @@ public:
 
   static void MapMathMLAttributesInto(const nsMappedAttributes* aAttributes, 
                                       mozilla::GenericSpecifiedValues* aGenericData);
   
   virtual nsresult GetEventTargetParent(
                      mozilla::EventChainPreVisitor& aVisitor) override;
   virtual nsresult PostHandleEvent(
                      mozilla::EventChainPostVisitor& aVisitor) override;
-  nsresult Clone(mozilla::dom::NodeInfo*, nsINode**) const override;
+  nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                 bool aPreallocateChildren) const override;
   virtual mozilla::EventStates IntrinsicState() const override;
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
 
   // Set during reflow as necessary. Does a style change notification,
   // aNotify must be true.
   void SetIncrementScriptLevel(bool aIncrementScriptLevel, bool aNotify);
   bool GetIncrementScriptLevel() const {
     return mIncrementScriptLevel;
--- a/dom/svg/SVGAElement.h
+++ b/dom/svg/SVGAElement.h
@@ -36,17 +36,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGAElement, SVGAElementBase)
 
   // nsINode interface methods
   virtual nsresult GetEventTargetParent(
                      EventChainPreVisitor& aVisitor) override;
   virtual nsresult PostHandleEvent(
                      EventChainPostVisitor& aVisitor) override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // nsIContent
   virtual nsresult BindToTree(nsIDocument *aDocument, nsIContent *aParent,
                               nsIContent *aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
--- a/dom/svg/SVGAnimateElement.h
+++ b/dom/svg/SVGAnimateElement.h
@@ -26,17 +26,18 @@ protected:
   friend nsresult
     (::NS_NewSVGAnimateElement(nsIContent **aResult,
                                already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsIDOMNode
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // SVGAnimationElement
   virtual nsSMILAnimationFunction& AnimationFunction() override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/svg/SVGAnimateMotionElement.h
+++ b/dom/svg/SVGAnimateMotionElement.h
@@ -26,17 +26,18 @@ protected:
   friend nsresult
     (::NS_NewSVGAnimateMotionElement(nsIContent **aResult,
                                      already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsIDOMNode specializations
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // SVGAnimationElement
   virtual nsSMILAnimationFunction& AnimationFunction() override;
   virtual bool GetTargetAttributeName(int32_t *aNamespaceID,
                                       nsIAtom **aLocalName) const override;
 
   // nsSVGElement
   virtual nsIAtom* GetPathDataAttrName() const override {
--- a/dom/svg/SVGAnimateTransformElement.h
+++ b/dom/svg/SVGAnimateTransformElement.h
@@ -26,17 +26,18 @@ protected:
   friend nsresult
     (::NS_NewSVGAnimateTransformElement(nsIContent **aResult,
                                         already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsIDOMNode specializations
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // Element specializations
   bool ParseAttribute(int32_t aNamespaceID,
                         nsIAtom* aAttribute,
                         const nsAString& aValue,
                         nsAttrValue& aResult) override;
 
   // SVGAnimationElement
--- a/dom/svg/SVGAnimationElement.h
+++ b/dom/svg/SVGAnimationElement.h
@@ -34,17 +34,18 @@ protected:
 
 public:
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGAnimationElement,
                                            SVGAnimationElementBase)
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override = 0;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override = 0;
 
   // nsIContent specializations
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
 
   virtual nsresult UnsetAttr(int32_t aNamespaceID, nsIAtom* aAttribute,
--- a/dom/svg/SVGCircleElement.h
+++ b/dom/svg/SVGCircleElement.h
@@ -31,17 +31,18 @@ public:
   virtual bool HasValidDimensions() const override;
 
   // SVGGeometryElement methods:
   virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
                                  const Matrix& aToBoundsSpace,
                                  const Matrix* aToNonScalingStrokeSpace = nullptr) override;
   virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> Cx();
   already_AddRefed<SVGAnimatedLength> Cy();
   already_AddRefed<SVGAnimatedLength> R();
 
 protected:
 
--- a/dom/svg/SVGClipPathElement.h
+++ b/dom/svg/SVGClipPathElement.h
@@ -26,17 +26,18 @@ class SVGClipPathElement final : public 
 
 protected:
   friend nsresult (::NS_NewSVGClipPathElement(nsIContent **aResult,
                                               already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   explicit SVGClipPathElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedEnumeration> ClipPathUnits();
 
 protected:
 
   enum { CLIPPATHUNITS };
   nsSVGEnum mEnumAttributes[1];
--- a/dom/svg/SVGComponentTransferFunctionElement.h
+++ b/dom/svg/SVGComponentTransferFunctionElement.h
@@ -96,17 +96,18 @@ class SVGFEFuncRElement : public SVGComp
     nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 protected:
   explicit SVGFEFuncRElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : SVGComponentTransferFunctionElement(aNodeInfo) {}
 
 public:
   virtual int32_t GetChannel() override { return 0; }
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult NS_NewSVGFEFuncGElement(
@@ -121,17 +122,18 @@ class SVGFEFuncGElement : public SVGComp
     nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 protected:
   explicit SVGFEFuncGElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : SVGComponentTransferFunctionElement(aNodeInfo) {}
 
 public:
   virtual int32_t GetChannel() override { return 1; }
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult NS_NewSVGFEFuncBElement(
@@ -146,17 +148,18 @@ class SVGFEFuncBElement : public SVGComp
     nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 protected:
   explicit SVGFEFuncBElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : SVGComponentTransferFunctionElement(aNodeInfo) {}
 
 public:
   virtual int32_t GetChannel() override { return 2; }
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult NS_NewSVGFEFuncAElement(
@@ -171,17 +174,18 @@ class SVGFEFuncAElement : public SVGComp
     nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 protected:
   explicit SVGFEFuncAElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : SVGComponentTransferFunctionElement(aNodeInfo) {}
 
 public:
   virtual int32_t GetChannel() override { return 3; }
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGComponentTransferFunctionElement_h
--- a/dom/svg/SVGDefsElement.h
+++ b/dom/svg/SVGDefsElement.h
@@ -22,15 +22,16 @@ protected:
                                           already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   explicit SVGDefsElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsIContent
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGDefsElement_h
--- a/dom/svg/SVGDescElement.h
+++ b/dom/svg/SVGDescElement.h
@@ -23,16 +23,17 @@ class SVGDescElement final : public SVGD
 protected:
   friend nsresult (::NS_NewSVGDescElement(nsIContent **aResult,
                                           already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   explicit SVGDescElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGDescElement_h
 
--- a/dom/svg/SVGDocument.cpp
+++ b/dom/svg/SVGDocument.cpp
@@ -46,23 +46,24 @@ SVGDocument::InsertChildAt(nsIContent* a
     // loaded by then.
     EnsureNonSVGUserAgentStyleSheetsLoaded();
   }
 
   return XMLDocument::InsertChildAt(aKid, aIndex, aNotify);
 }
 
 nsresult
-SVGDocument::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+SVGDocument::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                   bool aPreallocateChildren) const
 {
   NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
                "Can't import this document into another document!");
 
   RefPtr<SVGDocument> clone = new SVGDocument();
-  nsresult rv = CloneDocHelper(clone.get());
+  nsresult rv = CloneDocHelper(clone.get(), aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return CallQueryInterface(clone.get(), aResult);
 }
 
 void
 SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded()
 {
--- a/dom/svg/SVGDocument.h
+++ b/dom/svg/SVGDocument.h
@@ -26,17 +26,18 @@ public:
     : XMLDocument("image/svg+xml")
     , mHasLoadedNonSVGUserAgentStyleSheets(false)
   {
     mType = eSVG;
   }
 
   virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
                                  bool aNotify) override;
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual SVGDocument* AsSVGDocument() override {
     return this;
   }
 
 private:
   void EnsureNonSVGUserAgentStyleSheetsLoaded();
 
--- a/dom/svg/SVGEllipseElement.h
+++ b/dom/svg/SVGEllipseElement.h
@@ -31,17 +31,18 @@ public:
   virtual bool HasValidDimensions() const override;
 
   // SVGGeometryElement methods:
   virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
                                  const Matrix& aToBoundsSpace,
                                  const Matrix* aToNonScalingStrokeSpace = nullptr) override;
   virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> Cx();
   already_AddRefed<SVGAnimatedLength> Cy();
   already_AddRefed<SVGAnimatedLength> Rx();
   already_AddRefed<SVGAnimatedLength> Ry();
 
 protected:
--- a/dom/svg/SVGFEBlendElement.h
+++ b/dom/svg/SVGFEBlendElement.h
@@ -34,17 +34,18 @@ public:
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedString> In2();
   already_AddRefed<SVGAnimatedEnumeration> Mode();
 
 protected:
 
--- a/dom/svg/SVGFEColorMatrixElement.h
+++ b/dom/svg/SVGFEColorMatrixElement.h
@@ -36,17 +36,18 @@ public:
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedEnumeration> Type();
   already_AddRefed<DOMSVGAnimatedNumberList> Values();
 
  protected:
   virtual EnumAttributesInfo GetEnumInfo() override;
--- a/dom/svg/SVGFEComponentTransferElement.h
+++ b/dom/svg/SVGFEComponentTransferElement.h
@@ -35,17 +35,18 @@ public:
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) override;
 
   // nsIContent
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
 
 protected:
   virtual StringAttributesInfo GetStringInfo() override;
 
   enum { RESULT, IN1 };
--- a/dom/svg/SVGFECompositeElement.h
+++ b/dom/svg/SVGFECompositeElement.h
@@ -37,17 +37,18 @@ public:
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) override;
 
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedString> In2();
   already_AddRefed<SVGAnimatedEnumeration> Operator();
   already_AddRefed<SVGAnimatedNumber> K1();
   already_AddRefed<SVGAnimatedNumber> K2();
   already_AddRefed<SVGAnimatedNumber> K3();
--- a/dom/svg/SVGFEConvolveMatrixElement.h
+++ b/dom/svg/SVGFEConvolveMatrixElement.h
@@ -44,17 +44,18 @@ public:
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedInteger> OrderX();
   already_AddRefed<SVGAnimatedInteger> OrderY();
   already_AddRefed<DOMSVGAnimatedNumberList> KernelMatrix();
   already_AddRefed<SVGAnimatedInteger> TargetX();
   already_AddRefed<SVGAnimatedInteger> TargetY();
--- a/dom/svg/SVGFEDiffuseLightingElement.h
+++ b/dom/svg/SVGFEDiffuseLightingElement.h
@@ -32,17 +32,18 @@ public:
   virtual FilterPrimitiveDescription
     GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedNumber> SurfaceScale();
   already_AddRefed<SVGAnimatedNumber> DiffuseConstant();
   already_AddRefed<SVGAnimatedNumber> KernelUnitLengthX();
   already_AddRefed<SVGAnimatedNumber> KernelUnitLengthY();
 };
--- a/dom/svg/SVGFEDisplacementMapElement.h
+++ b/dom/svg/SVGFEDisplacementMapElement.h
@@ -35,17 +35,18 @@ public:
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedString> In2();
   already_AddRefed<SVGAnimatedNumber> Scale();
   already_AddRefed<SVGAnimatedEnumeration> XChannelSelector();
   already_AddRefed<SVGAnimatedEnumeration> YChannelSelector();
 
--- a/dom/svg/SVGFEDistantLightElement.h
+++ b/dom/svg/SVGFEDistantLightElement.h
@@ -29,17 +29,18 @@ protected:
   }
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   virtual AttributeMap ComputeLightAttributes(nsSVGFilterInstance* aInstance) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedNumber> Azimuth();
   already_AddRefed<SVGAnimatedNumber> Elevation();
 
 protected:
   virtual NumberAttributesInfo GetNumberInfo() override;
 
--- a/dom/svg/SVGFEDropShadowElement.h
+++ b/dom/svg/SVGFEDropShadowElement.h
@@ -40,17 +40,18 @@ public:
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo >& aSources) override;
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedNumber> Dx();
   already_AddRefed<SVGAnimatedNumber> Dy();
   already_AddRefed<SVGAnimatedNumber> StdDeviationX();
   already_AddRefed<SVGAnimatedNumber> StdDeviationY();
   void SetStdDeviation(float stdDeviationX, float stdDeviationY);
--- a/dom/svg/SVGFEFloodElement.h
+++ b/dom/svg/SVGFEFloodElement.h
@@ -36,17 +36,18 @@ public:
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual bool ProducesSRGB() override { return true; }
 
   virtual StringAttributesInfo GetStringInfo() override;
 
   enum { RESULT };
   nsSVGString mStringAttributes[1];
--- a/dom/svg/SVGFEGaussianBlurElement.h
+++ b/dom/svg/SVGFEGaussianBlurElement.h
@@ -36,17 +36,18 @@ public:
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo >& aSources) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedNumber> StdDeviationX();
   already_AddRefed<SVGAnimatedNumber> StdDeviationY();
   void SetStdDeviation(float stdDeviationX, float stdDeviationY);
 
 protected:
--- a/dom/svg/SVGFEImageElement.h
+++ b/dom/svg/SVGFEImageElement.h
@@ -50,17 +50,18 @@ public:
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual bool OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
                                nsIPrincipal* aReferencePrincipal) override;
 
   // nsIContent
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify) override;
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
   virtual EventStates IntrinsicState() const override;
--- a/dom/svg/SVGFEMergeElement.h
+++ b/dom/svg/SVGFEMergeElement.h
@@ -33,17 +33,18 @@ public:
     GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) override;
 
   // nsIContent
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 protected:
   virtual StringAttributesInfo GetStringInfo() override;
 
   enum { RESULT };
   nsSVGString mStringAttributes[1];
   static StringInfo sStringInfo[1];
 };
 
--- a/dom/svg/SVGFEMergeNodeElement.h
+++ b/dom/svg/SVGFEMergeNodeElement.h
@@ -24,17 +24,18 @@ class SVGFEMergeNodeElement : public SVG
 protected:
   explicit SVGFEMergeNodeElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : SVGFEMergeNodeElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
 
   const nsSVGString* GetIn1() { return &mStringAttributes[IN1]; }
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
--- a/dom/svg/SVGFEMorphologyElement.h
+++ b/dom/svg/SVGFEMorphologyElement.h
@@ -37,17 +37,18 @@ public:
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedEnumeration> Operator();
   already_AddRefed<SVGAnimatedNumber> RadiusX();
   already_AddRefed<SVGAnimatedNumber> RadiusY();
   void SetRadius(float rx, float ry);
 
--- a/dom/svg/SVGFEOffsetElement.h
+++ b/dom/svg/SVGFEOffsetElement.h
@@ -36,17 +36,18 @@ public:
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
   already_AddRefed<SVGAnimatedNumber> Dx();
   already_AddRefed<SVGAnimatedNumber> Dy();
 
 protected:
   virtual NumberAttributesInfo GetNumberInfo() override;
--- a/dom/svg/SVGFEPointLightElement.h
+++ b/dom/svg/SVGFEPointLightElement.h
@@ -29,17 +29,18 @@ protected:
   }
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   virtual AttributeMap ComputeLightAttributes(nsSVGFilterInstance* aInstance) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedNumber> X();
   already_AddRefed<SVGAnimatedNumber> Y();
   already_AddRefed<SVGAnimatedNumber> Z();
 
 protected:
   virtual NumberAttributesInfo GetNumberInfo() override;
--- a/dom/svg/SVGFESpecularLightingElement.h
+++ b/dom/svg/SVGFESpecularLightingElement.h
@@ -26,17 +26,18 @@ class SVGFESpecularLightingElement : pub
 protected:
   explicit SVGFESpecularLightingElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : SVGFESpecularLightingElementBase(aNodeInfo)
   {
   }
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual FilterPrimitiveDescription
     GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
--- a/dom/svg/SVGFESpotLightElement.h
+++ b/dom/svg/SVGFESpotLightElement.h
@@ -30,17 +30,18 @@ protected:
   }
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   virtual AttributeMap ComputeLightAttributes(nsSVGFilterInstance* aInstance) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedNumber> X();
   already_AddRefed<SVGAnimatedNumber> Y();
   already_AddRefed<SVGAnimatedNumber> Z();
   already_AddRefed<SVGAnimatedNumber> PointsAtX();
   already_AddRefed<SVGAnimatedNumber> PointsAtY();
   already_AddRefed<SVGAnimatedNumber> PointsAtZ();
--- a/dom/svg/SVGFETileElement.h
+++ b/dom/svg/SVGFETileElement.h
@@ -36,17 +36,18 @@ public:
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
   virtual void GetSourceImageNames(nsTArray<nsSVGStringInfo>& aSources) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> In1();
 
 protected:
   virtual StringAttributesInfo GetStringInfo() override;
 
   enum { RESULT, IN1 };
--- a/dom/svg/SVGFETurbulenceElement.h
+++ b/dom/svg/SVGFETurbulenceElement.h
@@ -39,17 +39,18 @@ public:
     GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedNumber> BaseFrequencyX();
   already_AddRefed<SVGAnimatedNumber> BaseFrequencyY();
   already_AddRefed<SVGAnimatedInteger> NumOctaves();
   already_AddRefed<SVGAnimatedNumber> Seed();
   already_AddRefed<SVGAnimatedEnumeration> StitchTiles();
   already_AddRefed<SVGAnimatedEnumeration> Type();
--- a/dom/svg/SVGFilterElement.h
+++ b/dom/svg/SVGFilterElement.h
@@ -33,17 +33,18 @@ class SVGFilterElement : public SVGFilte
 protected:
   friend nsresult (::NS_NewSVGFilterElement(nsIContent **aResult,
                                             already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   explicit SVGFilterElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsIContent
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
   // Invalidate users of this filter
   void Invalidate();
 
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const override;
 
--- a/dom/svg/SVGForeignObjectElement.h
+++ b/dom/svg/SVGForeignObjectElement.h
@@ -36,17 +36,18 @@ public:
   virtual bool HasValidDimensions() const override;
 
   // nsIContent interface
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X();
   already_AddRefed<SVGAnimatedLength> Y();
   already_AddRefed<SVGAnimatedLength> Width();
   already_AddRefed<SVGAnimatedLength> Height();
 
 protected:
--- a/dom/svg/SVGGElement.h
+++ b/dom/svg/SVGGElement.h
@@ -22,15 +22,16 @@ protected:
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
   friend nsresult (::NS_NewSVGGElement(nsIContent **aResult,
                                        already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // nsIContent
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGGElement_h
--- a/dom/svg/SVGGradientElement.h
+++ b/dom/svg/SVGGradientElement.h
@@ -43,17 +43,18 @@ class SVGGradientElement : public SVGGra
 {
   friend class ::nsSVGGradientFrame;
 
 protected:
   explicit SVGGradientElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override = 0;
 
 public:
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override = 0;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override = 0;
 
   // nsIContent
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
   virtual nsSVGAnimatedTransformList*
     GetAnimatedTransformList(uint32_t aFlags = 0) override;
   virtual nsIAtom* GetTransformListAttrName() const override {
     return nsGkAtoms::gradientTransform;
@@ -93,17 +94,18 @@ class SVGLinearGradientElement : public 
     (::NS_NewSVGLinearGradientElement(nsIContent** aResult,
                                       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 protected:
   explicit SVGLinearGradientElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X1();
   already_AddRefed<SVGAnimatedLength> Y1();
   already_AddRefed<SVGAnimatedLength> X2();
   already_AddRefed<SVGAnimatedLength> Y2();
 
 protected:
@@ -126,17 +128,18 @@ class SVGRadialGradientElement : public 
     (::NS_NewSVGRadialGradientElement(nsIContent** aResult,
                                       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 protected:
   explicit SVGRadialGradientElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> Cx();
   already_AddRefed<SVGAnimatedLength> Cy();
   already_AddRefed<SVGAnimatedLength> R();
   already_AddRefed<SVGAnimatedLength> Fx();
   already_AddRefed<SVGAnimatedLength> Fy();
 protected:
--- a/dom/svg/SVGImageElement.cpp
+++ b/dom/svg/SVGImageElement.cpp
@@ -309,19 +309,19 @@ SVGImageElement::GetPreserveAspectRatio(
 nsSVGElement::StringAttributesInfo
 SVGImageElement::GetStringInfo()
 {
   return StringAttributesInfo(mStringAttributes, sStringInfo,
                               ArrayLength(sStringInfo));
 }
 
 nsresult
-SVGImageElement::CopyInnerTo(Element* aDest)
+SVGImageElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren)
 {
   if (aDest->OwnerDoc()->IsStaticDocument()) {
     CreateStaticImageClone(static_cast<SVGImageElement*>(aDest));
   }
-  return SVGImageElementBase::CopyInnerTo(aDest);
+  return SVGImageElementBase::CopyInnerTo(aDest, aPreallocateChildren);
 }
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/svg/SVGImageElement.h
+++ b/dom/svg/SVGImageElement.h
@@ -60,19 +60,20 @@ public:
   virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
                                  const Matrix& aToBoundsSpace,
                                  const Matrix* aToNonScalingStrokeSpace = nullptr) override;
   virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
 
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
-  nsresult CopyInnerTo(mozilla::dom::Element* aDest);
+  nsresult CopyInnerTo(mozilla::dom::Element* aDest, bool aPreallocateChildren);
 
   void MaybeLoadSVGImage();
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X();
   already_AddRefed<SVGAnimatedLength> Y();
   already_AddRefed<SVGAnimatedLength> Width();
   already_AddRefed<SVGAnimatedLength> Height();
--- a/dom/svg/SVGLineElement.h
+++ b/dom/svg/SVGLineElement.h
@@ -38,17 +38,18 @@ public:
   virtual bool IsMarkable() override { return true; }
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) override;
   virtual void GetAsSimplePath(SimplePath* aSimplePath) override;
   virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
   virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
                                  const Matrix& aToBoundsSpace,
                                  const Matrix* aToNonScalingStrokeSpace = nullptr) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X1();
   already_AddRefed<SVGAnimatedLength> Y1();
   already_AddRefed<SVGAnimatedLength> X2();
   already_AddRefed<SVGAnimatedLength> Y2();
 
 protected:
--- a/dom/svg/SVGMPathElement.h
+++ b/dom/svg/SVGMPathElement.h
@@ -37,17 +37,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGMPathElement,
                                            SVGMPathElementBase)
 
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
 
   // nsIContent interface
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
 
   virtual nsresult UnsetAttr(int32_t aNamespaceID, nsIAtom* aAttribute,
                              bool aNotify) override;
   // Element specializations
--- a/dom/svg/SVGMarkerElement.h
+++ b/dom/svg/SVGMarkerElement.h
@@ -122,17 +122,18 @@ public:
 
   // public helpers
   gfx::Matrix GetMarkerTransform(float aStrokeWidth,
                                  float aX, float aY, float aAutoAngle,
                                  bool aIsStart);
   nsSVGViewBoxRect GetViewBoxRect();
   gfx::Matrix GetViewBoxTransform();
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   nsSVGOrientType* GetOrientType() { return &mOrientType; }
 
   // Returns the value of svg.marker-improvements.enabled.
   static bool MarkerImprovementsPrefEnabled();
 
   // WebIDL
   already_AddRefed<SVGAnimatedRect> ViewBox();
--- a/dom/svg/SVGMaskElement.h
+++ b/dom/svg/SVGMaskElement.h
@@ -30,17 +30,18 @@ class SVGMaskElement final : public SVGM
 protected:
   friend nsresult (::NS_NewSVGMaskElement(nsIContent **aResult,
                                           already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   explicit SVGMaskElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsIContent interface
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedEnumeration> MaskUnits();
   already_AddRefed<SVGAnimatedEnumeration> MaskContentUnits();
--- a/dom/svg/SVGMetadataElement.h
+++ b/dom/svg/SVGMetadataElement.h
@@ -24,15 +24,16 @@ protected:
   friend nsresult (::NS_NewSVGMetadataElement(nsIContent **aResult,
                                               already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   explicit SVGMetadataElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
   nsresult Init();
 
 public:
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGMetadataElement_h
--- a/dom/svg/SVGPathElement.h
+++ b/dom/svg/SVGPathElement.h
@@ -53,17 +53,18 @@ public:
   /**
    * This returns a path without the extra little line segments that
    * ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps.
    * See the comment for that function for more info on that.
    */
   virtual already_AddRefed<Path> GetOrBuildPathForMeasuring() override;
 
   // nsIContent interface
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual SVGAnimatedPathSegList* GetAnimPathSegList() override {
     return &mD;
   }
 
   virtual nsIAtom* GetPathDataAttrName() const override {
     return nsGkAtoms::d;
   }
--- a/dom/svg/SVGPatternElement.h
+++ b/dom/svg/SVGPatternElement.h
@@ -38,17 +38,18 @@ protected:
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const override;
 
   virtual mozilla::nsSVGAnimatedTransformList*
     GetAnimatedTransformList(uint32_t aFlags = 0) override;
   virtual nsIAtom* GetTransformListAttrName() const override {
     return nsGkAtoms::patternTransform;
--- a/dom/svg/SVGPolygonElement.h
+++ b/dom/svg/SVGPolygonElement.h
@@ -26,15 +26,16 @@ protected:
   friend nsresult (::NS_NewSVGPolygonElement(nsIContent **aResult,
                                              already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // SVGGeometryElement methods:
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) override;
   virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGPolygonElement_h
--- a/dom/svg/SVGPolylineElement.h
+++ b/dom/svg/SVGPolylineElement.h
@@ -25,15 +25,16 @@ protected:
   friend nsresult (::NS_NewSVGPolylineElement(nsIContent **aResult,
                                               already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
   // SVGGeometryElement methods:
   virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
 
 public:
   // nsIContent interface
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGPolylineElement_h
--- a/dom/svg/SVGRectElement.h
+++ b/dom/svg/SVGRectElement.h
@@ -32,17 +32,18 @@ public:
 
   // SVGGeometryElement methods:
   virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
                                  const Matrix& aToBoundsSpace,
                                  const Matrix* aToNonScalingStrokeSpace = nullptr) override;
   virtual void GetAsSimplePath(SimplePath* aSimplePath) override;
   virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder = nullptr) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X();
   already_AddRefed<SVGAnimatedLength> Y();
   already_AddRefed<SVGAnimatedLength> Height();
   already_AddRefed<SVGAnimatedLength> Width();
   already_AddRefed<SVGAnimatedLength> Rx();
   already_AddRefed<SVGAnimatedLength> Ry();
--- a/dom/svg/SVGSVGElement.cpp
+++ b/dom/svg/SVGSVGElement.cpp
@@ -187,25 +187,26 @@ SVGSVGElement::SVGSVGElement(already_Add
 {
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 // From NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSVGElement)
 nsresult
-SVGSVGElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+SVGSVGElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                     bool aPreallocateChildren) const
 {
   *aResult = nullptr;
   already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
   SVGSVGElement *it = new SVGSVGElement(ni, NOT_FROM_PARSER);
 
   nsCOMPtr<nsINode> kungFuDeathGrip = it;
   nsresult rv1 = it->Init();
-  nsresult rv2 = const_cast<SVGSVGElement*>(this)->CopyInnerTo(it);
+  nsresult rv2 = const_cast<SVGSVGElement*>(this)->CopyInnerTo(it, aPreallocateChildren);
   if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
     kungFuDeathGrip.swap(*aResult);
   }
 
   return NS_FAILED(rv1) ? rv1 : rv2;
 }
 
 
--- a/dom/svg/SVGSVGElement.h
+++ b/dom/svg/SVGSVGElement.h
@@ -234,17 +234,18 @@ public:
    */
   void ChildrenOnlyTransformChanged(uint32_t aFlags = 0);
 
   // This services any pending notifications for the transform on on this root
   // <svg> node needing to be recalculated.  (Only applicable in
   // SVG-as-an-image documents.)
   virtual void FlushImageTransformInvalidation();
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // Returns true IFF our attributes are currently overridden by a <view>
   // element and that element's ID matches the passed-in string.
   bool IsOverriddenBy(const nsAString &aViewID) const {
     return mCurrentViewID && mCurrentViewID->Equals(aViewID);
   }
 
   svgFloatSize GetViewportSize() const {
--- a/dom/svg/SVGScriptElement.cpp
+++ b/dom/svg/SVGScriptElement.cpp
@@ -51,26 +51,27 @@ SVGScriptElement::SVGScriptElement(alrea
 SVGScriptElement::~SVGScriptElement()
 {
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 nsresult
-SVGScriptElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+SVGScriptElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                        bool aPreallocateChildren) const
 {
   *aResult = nullptr;
 
   already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
   SVGScriptElement* it = new SVGScriptElement(ni, NOT_FROM_PARSER);
 
   nsCOMPtr<nsINode> kungFuDeathGrip = it;
   nsresult rv1 = it->Init();
-  nsresult rv2 = const_cast<SVGScriptElement*>(this)->CopyInnerTo(it);
+  nsresult rv2 = const_cast<SVGScriptElement*>(this)->CopyInnerTo(it, aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv1, rv1);
   NS_ENSURE_SUCCESS(rv2, rv2);
 
   // The clone should be marked evaluated if we are.
   it->mAlreadyStarted = mAlreadyStarted;
   it->mLineNumber = mLineNumber;
   it->mMalformed = mMalformed;
 
--- a/dom/svg/SVGScriptElement.h
+++ b/dom/svg/SVGScriptElement.h
@@ -56,17 +56,18 @@ public:
                               bool aCompileEventHandlers) override;
   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify) override;
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   void GetType(nsAString & aType);
   void SetType(const nsAString & aType, ErrorResult& rv);
   void GetCrossOrigin(nsAString & aCrossOrigin);
   void SetCrossOrigin(const nsAString & aCrossOrigin, ErrorResult& aError);
   already_AddRefed<SVGAnimatedString> Href();
 
--- a/dom/svg/SVGSetElement.h
+++ b/dom/svg/SVGSetElement.h
@@ -26,17 +26,18 @@ protected:
 
   friend nsresult (::NS_NewSVGSetElement(nsIContent **aResult,
                                          already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsIDOMNode
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // SVGAnimationElement
   virtual nsSMILAnimationFunction& AnimationFunction() override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/svg/SVGStopElement.h
+++ b/dom/svg/SVGStopElement.h
@@ -25,17 +25,18 @@ protected:
                                           already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   explicit SVGStopElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedNumber> Offset();
 
 protected:
 
   virtual NumberAttributesInfo GetNumberInfo() override;
   nsSVGNumber2 mOffset;
--- a/dom/svg/SVGStyleElement.h
+++ b/dom/svg/SVGStyleElement.h
@@ -54,17 +54,18 @@ public:
                            bool aNotify) override;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) override;
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   // WebIDL
--- a/dom/svg/SVGSwitchElement.h
+++ b/dom/svg/SVGSwitchElement.h
@@ -42,17 +42,18 @@ public:
   // nsINode
   virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
                                  bool aNotify) override;
   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
 
   // nsIContent
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 private:
   void UpdateActiveChild()
   { mActiveChild = FindActiveChild(); }
   nsIContent* FindActiveChild() const;
 
   // only this child will be displayed
   nsCOMPtr<nsIContent> mActiveChild;
 };
--- a/dom/svg/SVGSymbolElement.h
+++ b/dom/svg/SVGSymbolElement.h
@@ -33,17 +33,18 @@ protected:
 public:
   // interfaces:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedRect> ViewBox();
   already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
 
   // SVGTests
   bool IsInChromeDoc() const override;
 
--- a/dom/svg/SVGTSpanElement.h
+++ b/dom/svg/SVGTSpanElement.h
@@ -24,17 +24,18 @@ protected:
                                            already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   explicit SVGTSpanElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual EnumAttributesInfo GetEnumInfo() override;
   virtual LengthAttributesInfo GetLengthInfo() override;
 
   nsSVGEnum mEnumAttributes[1];
   virtual nsSVGEnum* EnumAttributes() override
     { return mEnumAttributes; }
--- a/dom/svg/SVGTextElement.h
+++ b/dom/svg/SVGTextElement.h
@@ -25,17 +25,18 @@ protected:
 
   friend nsresult (::NS_NewSVGTextElement(nsIContent **aResult,
                                           already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
 protected:
   virtual EnumAttributesInfo GetEnumInfo() override;
   virtual LengthAttributesInfo GetLengthInfo() override;
 
   nsSVGEnum mEnumAttributes[1];
   virtual nsSVGEnum* EnumAttributes() override
     { return mEnumAttributes; }
--- a/dom/svg/SVGTextPathElement.h
+++ b/dom/svg/SVGTextPathElement.h
@@ -41,17 +41,18 @@ protected:
                                               already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   explicit SVGTextPathElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> StartOffset();
   already_AddRefed<SVGAnimatedEnumeration> Method();
   already_AddRefed<SVGAnimatedEnumeration> Spacing();
   already_AddRefed<SVGAnimatedString> Href();
 
  protected:
--- a/dom/svg/SVGTitleElement.h
+++ b/dom/svg/SVGTitleElement.h
@@ -35,17 +35,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual nsresult BindToTree(nsIDocument *aDocument, nsIContent *aParent,
                               nsIContent *aBindingParent,
                               bool aCompileEventHandlers) override;
 
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
--- a/dom/svg/SVGTransformableElement.h
+++ b/dom/svg/SVGTransformableElement.h
@@ -25,17 +25,18 @@ struct SVGBoundingBoxOptions;
 
 class SVGTransformableElement : public nsSVGElement
 {
 public:
   explicit SVGTransformableElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : nsSVGElement(aNodeInfo) {}
   virtual ~SVGTransformableElement() {}
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override = 0;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override = 0;
 
   // WebIDL
   already_AddRefed<SVGAnimatedTransformList> Transform();
   nsSVGElement* GetNearestViewportElement();
   nsSVGElement* GetFarthestViewportElement();
   already_AddRefed<SVGIRect> GetBBox(const SVGBoundingBoxOptions& aOptions, 
                                      ErrorResult& rv);
   already_AddRefed<SVGMatrix> GetCTM();
--- a/dom/svg/SVGUseElement.cpp
+++ b/dom/svg/SVGUseElement.cpp
@@ -84,25 +84,26 @@ SVGUseElement::~SVGUseElement()
 {
   UnlinkSource();
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 nsresult
-SVGUseElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+SVGUseElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                     bool aPreallocateChildren) const
 {
   *aResult = nullptr;
   already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
   SVGUseElement *it = new SVGUseElement(ni);
 
   nsCOMPtr<nsINode> kungFuDeathGrip(it);
   nsresult rv1 = it->Init();
-  nsresult rv2 = const_cast<SVGUseElement*>(this)->CopyInnerTo(it);
+  nsresult rv2 = const_cast<SVGUseElement*>(this)->CopyInnerTo(it, aPreallocateChildren);
 
   // SVGUseElement specific portion - record who we cloned from
   it->mOriginal = const_cast<SVGUseElement*>(this);
 
   if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
     kungFuDeathGrip.swap(*aResult);
   }
 
--- a/dom/svg/SVGUseElement.h
+++ b/dom/svg/SVGUseElement.h
@@ -63,17 +63,18 @@ public:
 
   // nsSVGElement specializations:
   virtual gfxMatrix PrependLocalTransformsTo(
     const gfxMatrix &aMatrix,
     SVGTransformTypes aWhich = eAllTransforms) const override;
   virtual bool HasValidDimensions() const override;
 
   // nsIContent interface
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> Href();
   already_AddRefed<SVGAnimatedLength> X();
   already_AddRefed<SVGAnimatedLength> Y();
   already_AddRefed<SVGAnimatedLength> Width();
   already_AddRefed<SVGAnimatedLength> Height();
--- a/dom/svg/SVGViewElement.h
+++ b/dom/svg/SVGViewElement.h
@@ -37,17 +37,18 @@ protected:
   friend class SVGSVGElement;
   friend class ::nsSVGOuterSVGFrame;
   explicit SVGViewElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   friend nsresult (::NS_NewSVGViewElement(nsIContent **aResult,
                                           already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   // WebIDL
   uint16_t ZoomAndPan() { return mEnumAttributes[ZOOMANDPAN].GetAnimValue(); }
   void SetZoomAndPan(uint16_t aZoomAndPan, ErrorResult& rv);
   already_AddRefed<SVGAnimatedRect> ViewBox();
   already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
   already_AddRefed<DOMSVGStringList> ViewTarget();
 
--- a/dom/svg/nsSVGElement.h
+++ b/dom/svg/nsSVGElement.h
@@ -78,17 +78,18 @@ protected:
   explicit nsSVGElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   friend nsresult NS_NewSVGElement(mozilla::dom::Element **aResult,
                                    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
   nsresult Init();
   virtual ~nsSVGElement();
 
 public:
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_MUST_OVERRIDE override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const MOZ_MUST_OVERRIDE override;
 
   typedef mozilla::SVGNumberList SVGNumberList;
   typedef mozilla::SVGAnimatedNumberList SVGAnimatedNumberList;
   typedef mozilla::SVGUserUnitList SVGUserUnitList;
   typedef mozilla::SVGAnimatedLengthList SVGAnimatedLengthList;
   typedef mozilla::SVGAnimatedPointList SVGAnimatedPointList;
   typedef mozilla::SVGAnimatedPathSegList SVGAnimatedPathSegList;
   typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
--- a/dom/svg/nsSVGFilters.h
+++ b/dom/svg/nsSVGFilters.h
@@ -77,17 +77,18 @@ public:
 
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
   // nsSVGElement interface
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override = 0;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override = 0;
 
   virtual bool HasValidDimensions() const override;
 
   bool IsNodeOfType(uint32_t aFlags) const override
     { return !(aFlags & ~(eCONTENT | eFILTER)); }
 
   virtual nsSVGString& GetResultImageName() = 0;
   // Return a list of all image names used as sources. Default is to
@@ -154,17 +155,18 @@ typedef nsSVGElement SVGFEUnstyledElemen
 
 class SVGFEUnstyledElement : public SVGFEUnstyledElementBase
 {
 protected:
   explicit SVGFEUnstyledElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : SVGFEUnstyledElementBase(aNodeInfo) {}
 
 public:
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override = 0;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override = 0;
 
   // returns true if changes to the attribute should cause us to
   // repaint the filter
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const = 0;
 };
 
 //------------------------------------------------------------
new file mode 100644
--- /dev/null
+++ b/dom/tests/browser/beforeunload_test_page.html
@@ -0,0 +1,92 @@
+<!doctype html>
+<html>
+<body>
+
+<p>
+  There are currently <span id="totalInnerHandlers">0</span> beforeunload handlers registered in this frame.
+</p>
+<p>
+  There are currently <span id="totalOuterHandlers">0</span> beforeunload handlers registered on my subframe.
+</p>
+
+<iframe src="about:blank" id="subframe"></iframe>
+
+<script>
+  this.BeforeUnloader = {
+    _innerEventHandlers: [],
+    _outerEventHandlers: [],
+
+    get $totalInner() {
+      delete this.$totalInner;
+      return this.$totalInner = document.getElementById("totalInnerHandlers");
+    },
+
+    get $totalOuter() {
+      delete this.$totalOuter;
+      return this.$totalOuter = document.getElementById("totalOuterHandlers");
+    },
+
+    get $subframe() {
+      delete this.$subframe;
+      return this.$subframe = document.getElementById("subframe");
+    },
+
+    pushInner(howMany) {
+      for (let i = 0; i < howMany; ++i) {
+        let func = () => {};
+        this._innerEventHandlers.push(func);
+        addEventListener("beforeunload", func);
+      }
+
+      this.$totalInner.textContent = this._innerEventHandlers.length;
+    },
+
+    popInner(howMany) {
+      for (let i = 0; i < howMany; ++i) {
+        let func = this._innerEventHandlers.pop();
+        if (func) {
+          removeEventListener("beforeunload", func);
+        }
+      }
+
+      this.$totalInner.textContent = this._innerEventHandlers.length;
+    },
+
+    pushOuter(howMany) {
+      if (!this.$subframe.parentNode) {
+        throw new Error("Subframe I'm holding a reference to detached!");
+      }
+
+      for (let i = 0; i < howMany; ++i) {
+        let func = () => {};
+        this._outerEventHandlers.push(func);
+        this.$subframe.contentWindow.addEventListener("beforeunload", func);
+      }
+
+      this.$totalOuter.textContent = this._outerEventHandlers.length;
+    },
+
+    popOuter(howMany) {
+      if (!this.$subframe.parentNode) {
+        throw new Error("Subframe I'm holding a reference to detached!");
+      }
+
+      for (let i = 0; i < howMany; ++i) {
+        let func = this._outerEventHandlers.pop();
+        if (func) {
+          this.$subframe.contentWindow.removeEventListener("beforeunload", func);
+        }
+      }
+
+      this.$totalOuter.textContent = this._outerEventHandlers.length;
+    },
+
+    reset() {
+      this.popInner(this._innerEventHandlers.length);
+      this.popOuter(this._outerEventHandlers.length);
+    }
+  };
+</script>
+
+</body>
+</html>
\ No newline at end of file
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -37,16 +37,20 @@ support-files =
 [browser_ConsoleAPI_originAttributes.js]
 [browser_ConsoleAPITests.js]
 skip-if = e10s
 [browser_ConsoleStorageAPITests.js]
 [browser_ConsoleStoragePBTest_perwindowpb.js]
 [browser_focus_steal_from_chrome.js]
 [browser_focus_steal_from_chrome_during_mousedown.js]
 [browser_frame_elements.js]
+[browser_hasbeforeunload.js]
+support-files =
+  beforeunload_test_page.html
+run-if = e10s
 [browser_largeAllocation_win32.js]
 skip-if = !e10s || os != "win" || processor != "x86" # Large-Allocation requires e10s
 [browser_largeAllocation_non_win32.js]
 skip-if = !e10s || (os == "win" && processor == "x86") # Large-Allocation requires e10s
 [browser_localStorage_e10s.js]
 skip-if = !e10s # This is a test of e10s functionality.
 [browser_localStorage_privatestorageevent.js]
 [browser_test__content.js]
--- a/dom/tests/browser/browser_beforeunload_between_chrome_content.js
+++ b/dom/tests/browser/browser_beforeunload_between_chrome_content.js
@@ -3,23 +3,25 @@ const TEST_URL = "http://www.example.com
 function pageScript() {
   window.addEventListener("beforeunload", function (event) {
     var str = "Leaving?";
     event.returnValue = str;
     return str;
   }, true);
 }
 
-function frameScript() {
-  content.window.addEventListener("beforeunload", function (event) {
-    sendAsyncMessage("Test:OnBeforeUnloadReceived");
-    var str = "Leaving?";
-    event.returnValue = str;
-    return str;
-  }, true);
+function injectBeforeUnload(browser) {
+  return ContentTask.spawn(browser, null, function*() {
+    content.window.addEventListener("beforeunload", function (event) {
+      sendAsyncMessage("Test:OnBeforeUnloadReceived");
+      var str = "Leaving?";
+      event.returnValue = str;
+      return str;
+    }, true);
+  });
 }
 
 // Wait for onbeforeunload dialog, and dismiss it immediately.
 function awaitAndCloseBeforeUnloadDialog(doStayOnPage) {
   return new Promise(resolve => {
     function onDialogShown(node) {
       Services.obs.removeObserver(onDialogShown, "tabmodal-dialog-loaded");
       let button = doStayOnPage ? node.ui.button1 : node.ui.button0;
@@ -44,35 +46,34 @@ add_task(function* () {
     beforeUnloadCount++;
   });
 
   // Open a content page.
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
   let browser = tab.linkedBrowser;
 
   ok(browser.isRemoteBrowser, "Browser should be remote.");
-  browser.messageManager.loadFrameScript(
-    "data:,(" + frameScript.toString() + ")();", true);
 
+  yield injectBeforeUnload(browser);
   // Navigate to a chrome page.
   let dialogShown1 = awaitAndCloseBeforeUnloadDialog(false);
   yield BrowserTestUtils.loadURI(browser, "about:support");
   yield Promise.all([
     dialogShown1,
     BrowserTestUtils.browserLoaded(browser)
   ]);
+
   is(beforeUnloadCount, 1, "Should have received one beforeunload event.");
   ok(!browser.isRemoteBrowser, "Browser should not be remote.");
 
   // Go back to content page.
   ok(gBrowser.webNavigation.canGoBack, "Should be able to go back.");
   gBrowser.goBack();
   yield BrowserTestUtils.browserLoaded(browser);
-  browser.messageManager.loadFrameScript(
-    "data:,(" + frameScript.toString() + ")();", true);
+  yield injectBeforeUnload(browser);
 
   // Test that going forward triggers beforeunload prompt as well.
   ok(gBrowser.webNavigation.canGoForward, "Should be able to go forward.");
   let dialogShown2 = awaitAndCloseBeforeUnloadDialog(false);
   gBrowser.goForward();
   yield Promise.all([
     dialogShown2,
     BrowserTestUtils.browserLoaded(browser)
new file mode 100644
--- /dev/null
+++ b/dom/tests/browser/browser_hasbeforeunload.js
@@ -0,0 +1,822 @@
+"use strict";
+
+const PAGE_URL =
+  "http://example.com/browser/dom/tests/browser/beforeunload_test_page.html";
+
+/**
+ * Adds 1 or more inert beforeunload event listeners in this browser.
+ * By default, will target the top-level content window, but callers
+ * can specify the index of a subframe to target. See prepareSubframes
+ * for an idea of how the subframes are structured.
+ *
+ * @param {<xul:browser>} browser
+ *        The browser to add the beforeunload event listener in.
+ * @param {int} howMany
+ *        How many beforeunload event listeners to add. Note that these
+ *        beforeunload event listeners are inert and will not actually
+ *        prevent the host window from navigating.
+ * @param {optional int} frameDepth
+ *        The depth of the frame to add the event listener to. Defaults
+ *        to 0, which is the top-level content window.
+ * @return {Promise}
+ */
+function addBeforeUnloadListeners(browser, howMany = 1, frameDepth = 0) {
+  return controlFrameAt(browser, frameDepth, {
+    name: "AddBeforeUnload",
+    howMany,
+  });
+}
+
+/**
+ * Adds 1 or more inert beforeunload event listeners in this browser on
+ * a particular subframe. By default, this will target the first subframe
+ * under the top-level content window, but callers can specify the index
+ * of a subframe to target. See prepareSubframes for an idea of how the
+ * subframes are structured.
+ *
+ * Note that this adds the beforeunload event listener on the "outer" window,
+ * by doing:
+ *
+ * iframe.addEventListener("beforeunload", ...);
+ *
+ * @param {<xul:browser>} browser
+ *        The browser to add the beforeunload event listener in.
+ * @param {int} howMany
+ *        How many beforeunload event listeners to add. Note that these
+ *        beforeunload event listeners are inert and will not actually
+ *        prevent the host window from navigating.
+ * @param {optional int} frameDepth
+ *        The depth of the frame to add the event listener to. Defaults
+ *        to 1, which is the first subframe inside the top-level content
+ *        window. Setting this to 0 will throw.
+ * @return {Promise}
+ */
+function addOuterBeforeUnloadListeners(browser, howMany = 1, frameDepth = 1) {
+  if (frameDepth == 0) {
+    throw new Error("When adding a beforeunload listener on an outer " +
+                    "window, the frame you're targeting needs to be at " +
+                    "depth > 0.")
+  }
+
+  return controlFrameAt(browser, frameDepth, {
+    name: "AddOuterBeforeUnload",
+    howMany,
+  });
+}
+
+/**
+ * Removes 1 or more inert beforeunload event listeners in this browser.
+ * This assumes that addBeforeUnloadListeners has been called previously
+ * for the target frame.
+ *
+ * By default, will target the top-level content window, but callers
+ * can specify the index of a subframe to target. See prepareSubframes
+ * for an idea of how the subframes are structured.
+ *
+ * @param {<xul:browser>} browser
+ *        The browser to remove the beforeunload event listener from.
+ * @param {int} howMany
+ *        How many beforeunload event listeners to remove.
+ * @param {optional int} frameDepth
+ *        The depth of the frame to remove the event listener from. Defaults
+ *        to 0, which is the top-level content window.
+ * @return {Promise}
+ */
+function removeBeforeUnloadListeners(browser, howMany = 1, frameDepth = 0) {
+  return controlFrameAt(browser, frameDepth, {
+    name: "RemoveBeforeUnload",
+    howMany,
+  });
+}
+
+/**
+ * Removes 1 or more inert beforeunload event listeners in this browser on
+ * a particular subframe. By default, this will target the first subframe
+ * under the top-level content window, but callers can specify the index
+ * of a subframe to target. See prepareSubframes for an idea of how the
+ * subframes are structured.
+ *
+ * Note that this removes the beforeunload event listener on the "outer" window,
+ * by doing:
+ *
+ * iframe.removeEventListener("beforeunload", ...);
+ *
+ * @param {<xul:browser>} browser
+ *        The browser to remove the beforeunload event listener from.
+ * @param {int} howMany
+ *        How many beforeunload event listeners to remove.
+ * @param {optional int} frameDepth
+ *        The depth of the frame to remove the event listener from. Defaults
+ *        to 1, which is the first subframe inside the top-level content
+ *        window. Setting this to 0 will throw.
+ * @return {Promise}
+ */
+function removeOuterBeforeUnloadListeners(browser, howMany = 1, frameDepth = 1) {
+  if (frameDepth == 0) {
+    throw new Error("When removing a beforeunload listener from an outer " +
+                    "window, the frame you're targeting needs to be at " +
+                    "depth > 0.")
+  }
+
+  return controlFrameAt(browser, frameDepth, {
+    name: "RemoveOuterBeforeUnload",
+    howMany,
+  });
+}
+
+/**
+ * Navigates a content window to a particular URL and waits for it to
+ * finish loading that URL.
+ *
+ * By default, will target the top-level content window, but callers
+ * can specify the index of a subframe to target. See prepareSubframes
+ * for an idea of how the subframes are structured.
+ *
+ * @param {<xul:browser>} browser
+ *        The browser that will have the navigation occur within it.
+ * @param {string} url
+ *        The URL to send the content window to.
+ * @param {optional int} frameDepth
+ *        The depth of the frame to navigate. Defaults to 0, which is
+ *        the top-level content window.
+ * @return {Promise}
+ */
+function navigateSubframe(browser, url, frameDepth = 0) {
+  let navigatePromise = controlFrameAt(browser, frameDepth, {
+    name: "Navigate",
+    url,
+  });
+  let subframeLoad = BrowserTestUtils.browserLoaded(browser, true);
+  return Promise.all([navigatePromise, subframeLoad]);
+}
+
+/**
+ * Removes the <iframe> from a content window pointed at PAGE_URL.
+ *
+ * By default, will target the top-level content window, but callers
+ * can specify the index of a subframe to target. See prepareSubframes
+ * for an idea of how the subframes are structured.
+ *
+ * @param {<xul:browser>} browser
+ *        The browser that will have removal occur within it.
+ * @param {optional int} frameDepth
+ *        The depth of the frame that will have the removal occur within
+ *        it. Defaults to 0, which is the top-level content window, meaning
+ *        that the first subframe will be removed.
+ * @return {Promise}
+ */
+function removeSubframeFrom(browser, frameDepth = 0) {
+  return controlFrameAt(browser, frameDepth, {
+    name: "RemoveSubframe",
+  });
+}
+
+/**
+ * Sends a command to a frame pointed at PAGE_URL. There are utility
+ * functions defined in this file that call this function. You should
+ * use those instead.
+ *
+ * @param {<xul:browser>} browser
+ *        The browser to send the command to.
+ * @param {int} frameDepth
+ *        The depth of the frame that we'll send the command to. 0 means
+ *        sending it to the top-level content window.
+ * @param {object} command
+ *        An object with the following structure:
+ *
+ *        {
+ *          name: (string),
+ *          <arbitrary arguments to send with the command>
+ *        }
+ *
+ *        Here are the commands that can be sent:
+ *
+ *        AddBeforeUnload
+ *          {int} howMany
+ *          How many beforeunload event listeners to add.
+ *
+ *        AddOuterBeforeUnload
+ *          {int} howMany
+ *          How many beforeunload event listeners to add to
+ *          the iframe in the document at this depth.
+ *
+ *        RemoveBeforeUnload
+ *          {int} howMany
+ *          How many beforeunload event listeners to remove.
+ *
+ *        RemoveOuterBeforeUnload
+ *          {int} howMany
+ *          How many beforeunload event listeners to remove from
+ *          the iframe in the document at this depth.
+ *
+ *        Navigate
+ *          {string} url
+ *          The URL to send the frame to.
+ *
+ *        RemoveSubframe
+ *
+ * @return {Promise}
+ */
+function controlFrameAt(browser, frameDepth, command) {
+  return ContentTask.spawn(browser, { frameDepth, command }, function*(args) {
+    Cu.import("resource://testing-common/TestUtils.jsm", this);
+
+    let { command: contentCommand, frameDepth: contentFrameDepth } = args;
+
+    let targetContent = content;
+    let targetSubframe = content.document.getElementById("subframe");
+
+    // We want to not only find the frame that maps to the
+    // target frame depth that we've been given, but we also want
+    // to count the total depth so that if a middle frame is removed
+    // or navigated, then we know how many outer-window-destroyed
+    // observer notifications to expect.
+    let currentContent = targetContent;
+    let currentSubframe = targetSubframe;
+
+    let depth = 0;
+
+    do {
+      currentContent = currentSubframe.contentWindow;
+      currentSubframe = currentContent.document.getElementById("subframe");
+      depth++;
+      if (depth == contentFrameDepth) {
+        targetContent = currentContent;
+        targetSubframe = currentSubframe;
+      }
+    } while (currentSubframe);
+
+    switch (contentCommand.name) {
+      case "AddBeforeUnload": {
+        let BeforeUnloader = targetContent.wrappedJSObject.BeforeUnloader;
+        Assert.ok(BeforeUnloader, "Found BeforeUnloader in the test page.");
+        BeforeUnloader.pushInner(contentCommand.howMany);
+        break;
+      }
+      case "AddOuterBeforeUnload": {
+        let BeforeUnloader = targetContent.wrappedJSObject.BeforeUnloader;
+        Assert.ok(BeforeUnloader, "Found BeforeUnloader in the test page.");
+        BeforeUnloader.pushOuter(contentCommand.howMany);
+        break;
+      }
+      case "RemoveBeforeUnload": {
+        let BeforeUnloader = targetContent.wrappedJSObject.BeforeUnloader;
+        Assert.ok(BeforeUnloader, "Found BeforeUnloader in the test page.");
+        BeforeUnloader.popInner(contentCommand.howMany);
+        break;
+      }
+      case "RemoveOuterBeforeUnload": {
+        let BeforeUnloader = targetContent.wrappedJSObject.BeforeUnloader;
+        Assert.ok(BeforeUnloader, "Found BeforeUnloader in the test page.");
+        BeforeUnloader.popOuter(contentCommand.howMany);
+        break;
+      }
+      case "Navigate": {
+        // How many frames are going to be destroyed when we do this? We
+        // need to wait for that many window destroyed notifications.
+        targetContent.location = contentCommand.url;
+
+        let destroyedOuterWindows = depth - contentFrameDepth;
+        if (destroyedOuterWindows) {
+          yield TestUtils.topicObserved("outer-window-destroyed", () => {
+            destroyedOuterWindows--;
+            return !destroyedOuterWindows;
+          });
+        }
+        break;
+      }
+      case "RemoveSubframe": {
+        let subframe = targetContent.document.getElementById("subframe");
+        Assert.ok(subframe, "Found subframe at frame depth of " + contentFrameDepth);
+        subframe.remove();
+
+        let destroyedOuterWindows = depth - contentFrameDepth;
+        if (destroyedOuterWindows) {
+          yield TestUtils.topicObserved("outer-window-destroyed", () => {
+            destroyedOuterWindows--;
+            return !destroyedOuterWindows;
+          });
+        }
+        break;
+      }
+    }
+  });
+}
+
+/**
+ * Sets up a structure where a page at PAGE_URL will host an
+ * <iframe> also pointed at PAGE_URL, and does this repeatedly
+ * until we've achieved the desired frame depth. Note that this
+ * will cause the top-level browser to reload, and wipe out any
+ * previous changes to the DOM under it.
+ *
+ * @param {<xul:browser>} browser
+ *        The browser in which we'll load our structure at the
+ *        top level.
+ * @param {Array<object>} options
+ *        Set-up options for each subframe. The following properties
+ *        are accepted:
+ *
+ *        {string} sandboxAttributes
+ *          The value to set the sandbox attribute to. If null, no sandbox
+ *          attribute will be set (and any pre-existing sandbox attributes)
+ *          on the <iframe> will be removed.
+ *
+ *        The number of entries on the options Array corresponds to how many
+ *        subframes are under the top-level content window.
+ *
+ *        Example:
+ *
+ *        yield prepareSubframes(browser, [
+ *          { sandboxAttributes: null },
+ *          { sandboxAttributes: "allow-modals" },
+ *        ]);
+ *
+ *        This would create the following structure:
+ *
+ *        <top-level content window at PAGE_URL>
+ *        |
+ *        |--> <iframe at PAGE_URL, no sandbox attributes>
+ *             |
+ *             |--> <iframe at PAGE_URL, sandbox="allow-modals">
+ *
+ * @return {Promise}
+ */
+function* prepareSubframes(browser, options) {
+  browser.reload();
+  yield BrowserTestUtils.browserLoaded(browser);
+
+  yield ContentTask.spawn(browser, { options, PAGE_URL }, function*(args) {
+    let { options: allSubframeOptions, PAGE_URL: contentPageURL } = args;
+    function loadBeforeUnloadHelper(doc, subframeOptions) {
+      let subframe = doc.getElementById("subframe");
+      subframe.remove();
+      if (subframeOptions.sandboxAttributes === null) {
+        subframe.removeAttribute("sandbox");
+      } else {
+        subframe.setAttribute("sandbox", subframeOptions.sandboxAttributes);
+      }
+      doc.body.appendChild(subframe);
+      subframe.contentWindow.location = contentPageURL;
+      return ContentTaskUtils.waitForEvent(subframe, "load").then(() => {
+        return subframe.contentDocument;
+      });
+    }
+
+    let currentDoc = content.document;
+    for (let subframeOptions of allSubframeOptions) {
+      currentDoc = yield loadBeforeUnloadHelper(currentDoc, subframeOptions);
+    }
+  });
+}
+
+/**
+ * Ensures that a browser's nsITabParent hasBeforeUnload attribute
+ * is set to the expected value.
+ *
+ * @param {<xul:browser>} browser
+ *        The browser whose nsITabParent we will check.
+ * @param {bool} expected
+ *        True if hasBeforeUnload is expected to be true.
+ */
+function assertHasBeforeUnload(browser, expected) {
+  Assert.equal(browser.frameLoader.tabParent.hasBeforeUnload,
+               expected);
+}
+
+/**
+ * Tests that the nsITabParent hasBeforeUnload attribute works under
+ * a number of different scenarios on inner windows. At a high-level,
+ * we test that hasBeforeUnload works properly during page / iframe
+ * navigation, or when an <iframe> with a beforeunload listener on its
+ * inner window is removed from the DOM.
+ */
+add_task(function* test_inner_window_scenarios() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: PAGE_URL,
+  }, function*(browser) {
+    Assert.ok(browser.isRemoteBrowser,
+              "This test only makes sense with out of process browsers.");
+    assertHasBeforeUnload(browser, false);
+
+    // Test the simple case on the top-level window by adding a single
+    // beforeunload event listener on the inner window and then removing
+    // it.
+    yield addBeforeUnloadListeners(browser);
+    assertHasBeforeUnload(browser, true);
+    yield removeBeforeUnloadListeners(browser);
+    assertHasBeforeUnload(browser, false);
+
+    // Now let's add several beforeunload listeners, and
+    // ensure that we only set hasBeforeUnload to false once
+    // the last listener is removed.
+    yield addBeforeUnloadListeners(browser, 3);
+    assertHasBeforeUnload(browser, true);
+    yield removeBeforeUnloadListeners(browser); // 2 left...
+    assertHasBeforeUnload(browser, true);
+    yield removeBeforeUnloadListeners(browser); // 1 left...
+    assertHasBeforeUnload(browser, true);
+    yield removeBeforeUnloadListeners(browser); // None left!
+
+    assertHasBeforeUnload(browser, false);
+
+    // Now let's have the top-level content window navigate
+    // away with a beforeunload listener set, and ensure
+    // that we clear the hasBeforeUnload value.
+    yield addBeforeUnloadListeners(browser, 5);
+    yield navigateSubframe(browser, "http://example.com");
+    assertHasBeforeUnload(browser, false);
+
+    // Now send the page back to the test page for
+    // the next few tests.
+    browser.loadURI(PAGE_URL);
+    yield BrowserTestUtils.browserLoaded(browser);
+
+    // We want to test hasBeforeUnload works properly with
+    // beforeunload event listeners in <iframe> elements too.
+    // We prepare a structure like this with 3 content windows
+    // to exercise:
+    //
+    // <top-level content window at PAGE_URL> (TOP)
+    // |
+    // |--> <iframe at PAGE_URL> (MIDDLE)
+    //      |
+    //      |--> <iframe at PAGE_URL> (BOTTOM)
+    //
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: null, },
+      { sandboxAttributes: null, },
+    ]);
+    // These constants are just to make it easier to know which
+    // frame we're referring to without having to remember the
+    // exact indices.
+    const TOP = 0;
+    const MIDDLE = 1;
+    const BOTTOM = 2;
+
+    // We should initially start with hasBeforeUnload set to false.
+    assertHasBeforeUnload(browser, false);
+
+    // Tests that if there are beforeunload event listeners on
+    // all levels of our window structure, that we only set
+    // hasBeforeUnload to false once the last beforeunload
+    // listener has been unset.
+    yield addBeforeUnloadListeners(browser, 2, MIDDLE);
+    assertHasBeforeUnload(browser, true);
+    yield addBeforeUnloadListeners(browser, 1, TOP);
+    assertHasBeforeUnload(browser, true);
+    yield addBeforeUnloadListeners(browser, 5, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+
+    yield removeBeforeUnloadListeners(browser, 1, TOP);
+    assertHasBeforeUnload(browser, true);
+    yield removeBeforeUnloadListeners(browser, 5, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+    yield removeBeforeUnloadListeners(browser, 2, MIDDLE);
+    assertHasBeforeUnload(browser, false);
+
+    // Tests that if a beforeunload event listener is set on
+    // an iframe that navigates away to a page without a
+    // beforeunload listener, that hasBeforeUnload is set
+    // to false.
+    yield addBeforeUnloadListeners(browser, 5, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+
+    yield navigateSubframe(browser, "http://example.com", BOTTOM);
+    assertHasBeforeUnload(browser, false);
+
+    // Reset our window structure now.
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: null, },
+      { sandboxAttributes: null, },
+    ]);
+
+    // This time, add beforeunload event listeners to both the
+    // MIDDLE and BOTTOM frame, and then navigate the MIDDLE
+    // away. This should set hasBeforeUnload to false.
+    yield addBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield addBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+    yield navigateSubframe(browser, "http://example.com", MIDDLE);
+    assertHasBeforeUnload(browser, false);
+
+    // Tests that if the MIDDLE and BOTTOM frames have beforeunload
+    // event listeners, and if we remove the BOTTOM <iframe> and the
+    // MIDDLE <iframe>, that hasBeforeUnload is set to false.
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: null, },
+      { sandboxAttributes: null, },
+    ]);
+    yield addBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield addBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+    yield removeSubframeFrom(browser, MIDDLE);
+    assertHasBeforeUnload(browser, true);
+    yield removeSubframeFrom(browser, TOP);
+    assertHasBeforeUnload(browser, false);
+
+    // Tests that if the MIDDLE and BOTTOM frames have beforeunload
+    // event listeners, and if we remove just the MIDDLE <iframe>, that
+    // hasBeforeUnload is set to false.
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: null, },
+      { sandboxAttributes: null, },
+    ]);
+    yield addBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield addBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+    yield removeSubframeFrom(browser, TOP);
+    assertHasBeforeUnload(browser, false);
+
+    // Test that two sandboxed iframes, _without_ the allow-modals
+    // permission, do not result in the hasBeforeUnload attribute
+    // being set to true when beforeunload event listeners are added.
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: "allow-scripts", },
+      { sandboxAttributes: "allow-scripts", },
+    ]);
+
+    yield addBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield addBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, false);
+
+    yield removeBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield removeBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, false);
+
+    // Test that two sandboxed iframes, both with the allow-modals
+    // permission, cause the hasBeforeUnload attribute to be set
+    // to true when beforeunload event listeners are added.
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: "allow-scripts allow-modals", },
+      { sandboxAttributes: "allow-scripts allow-modals", },
+    ]);
+
+    yield addBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield addBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+
+    yield removeBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+    yield removeBeforeUnloadListeners(browser, 3, MIDDLE);
+    assertHasBeforeUnload(browser, false);
+  });
+});
+
+/**
+ * Tests that the nsITabParent hasBeforeUnload attribute works under
+ * a number of different scenarios on outer windows. Very similar to
+ * the above set of tests, except that we add the beforeunload listeners
+ * to the iframe DOM nodes instead of the inner windows.
+ */
+add_task(function* test_outer_window_scenarios() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: PAGE_URL,
+  }, function*(browser) {
+    Assert.ok(browser.isRemoteBrowser,
+              "This test only makes sense with out of process browsers.");
+    assertHasBeforeUnload(browser, false);
+
+    // We want to test hasBeforeUnload works properly with
+    // beforeunload event listeners in <iframe> elements.
+    // We prepare a structure like this with 3 content windows
+    // to exercise:
+    //
+    // <top-level content window at PAGE_URL> (TOP)
+    // |
+    // |--> <iframe at PAGE_URL> (MIDDLE)
+    //      |
+    //      |--> <iframe at PAGE_URL> (BOTTOM)
+    //
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: null, },
+      { sandboxAttributes: null, },
+    ]);
+
+    // These constants are just to make it easier to know which
+    // frame we're referring to without having to remember the
+    // exact indices.
+    const TOP = 0;
+    const MIDDLE = 1;
+    const BOTTOM = 2;
+
+    // Test the simple case on the top-level window by adding a single
+    // beforeunload event listener on the outer window of the iframe
+    // in the TOP document.
+    yield addOuterBeforeUnloadListeners(browser);
+    assertHasBeforeUnload(browser, true);
+
+    yield removeOuterBeforeUnloadListeners(browser);
+    assertHasBeforeUnload(browser, false);
+
+    // Now let's add several beforeunload listeners, and
+    // ensure that we only set hasBeforeUnload to false once
+    // the last listener is removed.
+    yield addOuterBeforeUnloadListeners(browser, 3);
+    assertHasBeforeUnload(browser, true);
+    yield removeOuterBeforeUnloadListeners(browser); // 2 left...
+    assertHasBeforeUnload(browser, true);
+    yield removeOuterBeforeUnloadListeners(browser); // 1 left...
+    assertHasBeforeUnload(browser, true);
+    yield removeOuterBeforeUnloadListeners(browser); // None left!
+
+    assertHasBeforeUnload(browser, false);
+
+    // Now let's have the top-level content window navigate away
+    // with a beforeunload listener set on the outer window of the
+    // iframe inside it, and ensure that we clear the hasBeforeUnload
+    // value.
+    yield addOuterBeforeUnloadListeners(browser, 5);
+    yield navigateSubframe(browser, "http://example.com", TOP);
+    assertHasBeforeUnload(browser, false);
+
+    // Now send the page back to the test page for
+    // the next few tests.
+    browser.loadURI(PAGE_URL);
+    yield BrowserTestUtils.browserLoaded(browser);
+
+    // We should initially start with hasBeforeUnload set to false.
+    assertHasBeforeUnload(browser, false);
+
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: null, },
+      { sandboxAttributes: null, },
+    ]);
+
+    // Tests that if there are beforeunload event listeners on
+    // all levels of our window structure, that we only set
+    // hasBeforeUnload to false once the last beforeunload
+    // listener has been unset.
+    yield addOuterBeforeUnloadListeners(browser, 3, MIDDLE);
+    assertHasBeforeUnload(browser, true);
+    yield addOuterBeforeUnloadListeners(browser, 7, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+
+    yield removeOuterBeforeUnloadListeners(browser, 7, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+    yield removeOuterBeforeUnloadListeners(browser, 3, MIDDLE);
+    assertHasBeforeUnload(browser, false);
+
+    // Tests that if a beforeunload event listener is set on
+    // an iframe that navigates away to a page without a
+    // beforeunload listener, that hasBeforeUnload is set
+    // to false. We're setting the event listener on the
+    // outer window on the <iframe> in the MIDDLE, which
+    // itself contains the BOTTOM frame it our structure.
+    yield addOuterBeforeUnloadListeners(browser, 5, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+
+    // Now navigate that BOTTOM frame.
+    yield navigateSubframe(browser, "http://example.com", BOTTOM);
+    assertHasBeforeUnload(browser, false);
+
+    // Reset our window structure now.
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: null, },
+      { sandboxAttributes: null, },
+    ]);
+
+    // This time, add beforeunload event listeners to the outer
+    // windows for MIDDLE and BOTTOM. Then navigate the MIDDLE
+    // frame. This should set hasBeforeUnload to false.
+    yield addOuterBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield addOuterBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+    yield navigateSubframe(browser, "http://example.com", MIDDLE);
+    assertHasBeforeUnload(browser, false);
+
+    // Adds beforeunload event listeners to the outer windows of
+    // MIDDLE and BOTOTM, and then removes those iframes. Removing
+    // both iframes should set hasBeforeUnload to false.
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: null, },
+      { sandboxAttributes: null, },
+    ]);
+    yield addOuterBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield addOuterBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+    yield removeSubframeFrom(browser, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+    yield removeSubframeFrom(browser, MIDDLE);
+    assertHasBeforeUnload(browser, false);
+
+    // Adds beforeunload event listeners to the outer windows of MIDDLE
+    // and BOTTOM, and then removes just the MIDDLE iframe (which will
+    // take the bottom one with it). This should set hasBeforeUnload to
+    // false.
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: null, },
+      { sandboxAttributes: null, },
+    ]);
+    yield addOuterBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield addOuterBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+    yield removeSubframeFrom(browser, TOP);
+    assertHasBeforeUnload(browser, false);
+
+    // Test that two sandboxed iframes, _without_ the allow-modals
+    // permission, do not result in the hasBeforeUnload attribute
+    // being set to true when beforeunload event listeners are added
+    // to the outer windows. Note that this requires the
+    // allow-same-origin permission, otherwise a cross-origin
+    // security exception is thrown.
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: "allow-same-origin allow-scripts", },
+      { sandboxAttributes: "allow-same-origin allow-scripts", },
+    ]);
+
+    yield addOuterBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield addOuterBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, false);
+
+    yield removeOuterBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield removeOuterBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, false);
+
+    // Test that two sandboxed iframes, both with the allow-modals
+    // permission, cause the hasBeforeUnload attribute to be set
+    // to true when beforeunload event listeners are added. Note
+    // that this requires the allow-same-origin permission,
+    // otherwise a cross-origin security exception is thrown.
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: "allow-same-origin allow-scripts allow-modals", },
+      { sandboxAttributes: "allow-same-origin allow-scripts allow-modals", },
+    ]);
+
+    yield addOuterBeforeUnloadListeners(browser, 3, MIDDLE);
+    yield addOuterBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+
+    yield removeOuterBeforeUnloadListeners(browser, 1, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+    yield removeOuterBeforeUnloadListeners(browser, 3, MIDDLE);
+    assertHasBeforeUnload(browser, false);
+  });
+});
+
+/**
+ * Tests hasBeforeUnload behaviour when beforeunload event listeners
+ * are added on both inner and outer windows.
+ */
+add_task(function* test_mixed_inner_and_outer_window_scenarios() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: PAGE_URL,
+  }, function*(browser) {
+    Assert.ok(browser.isRemoteBrowser,
+              "This test only makes sense with out of process browsers.");
+    assertHasBeforeUnload(browser, false);
+
+    // We want to test hasBeforeUnload works properly with
+    // beforeunload event listeners in <iframe> elements.
+    // We prepare a structure like this with 3 content windows
+    // to exercise:
+    //
+    // <top-level content window at PAGE_URL> (TOP)
+    // |
+    // |--> <iframe at PAGE_URL> (MIDDLE)
+    //      |
+    //      |--> <iframe at PAGE_URL> (BOTTOM)
+    //
+    yield prepareSubframes(browser, [
+      { sandboxAttributes: null, },
+      { sandboxAttributes: null, },
+    ]);
+
+    // These constants are just to make it easier to know which
+    // frame we're referring to without having to remember the
+    // exact indices.
+    const TOP = 0;
+    const MIDDLE = 1;
+    const BOTTOM = 2;
+
+    yield addBeforeUnloadListeners(browser, 1, TOP);
+    assertHasBeforeUnload(browser, true);
+    yield addBeforeUnloadListeners(browser, 2, MIDDLE);
+    assertHasBeforeUnload(browser, true);
+    yield addBeforeUnloadListeners(browser, 5, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+
+    yield addOuterBeforeUnloadListeners(browser, 3, MIDDLE);
+    assertHasBeforeUnload(browser, true);
+    yield addOuterBeforeUnloadListeners(browser, 7, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+
+    yield removeBeforeUnloadListeners(browser, 5, BOTTOM);
+    assertHasBeforeUnload(browser, true);
+
+    yield removeBeforeUnloadListeners(browser, 2, MIDDLE);
+    assertHasBeforeUnload(browser, true);
+
+    yield removeOuterBeforeUnloadListeners(browser, 3, MIDDLE);
+    assertHasBeforeUnload(browser, true);
+
+    yield removeBeforeUnloadListeners(browser, 1, TOP);
+    assertHasBeforeUnload(browser, true);
+
+    yield removeOuterBeforeUnloadListeners(browser, 7, BOTTOM);
+    assertHasBeforeUnload(browser, false);
+  });
+});
--- a/dom/xbl/XBLChildrenElement.h
+++ b/dom/xbl/XBLChildrenElement.h
@@ -28,17 +28,18 @@ public:
     : nsXMLElement(aNodeInfo)
   {
   }
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsINode interface methods
-  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
   // nsIContent interface methods
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) override;
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
--- a/dom/xml/XMLDocument.cpp
+++ b/dom/xml/XMLDocument.cpp
@@ -602,23 +602,24 @@ XMLDocument::EndLoad()
 XMLDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
 {
   nsDocument::DocAddSizeOfExcludingThis(aWindowSizes);
 }
 
 // nsIDOMDocument interface
 
 nsresult
-XMLDocument::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+XMLDocument::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                   bool aPreallocateChildren) const
 {
   NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
                "Can't import this document into another document!");
 
   RefPtr<XMLDocument> clone = new XMLDocument();
-  nsresult rv = CloneDocHelper(clone);
+  nsresult rv = CloneDocHelper(clone, aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // State from XMLDocument
   clone->mAsync = mAsync;
   clone->mIsPlainDocument = mIsPlainDocument;
 
   return CallQueryInterface(clone.get(), aResult);
 }
--- a/dom/xml/XMLDocument.h
+++ b/dom/xml/XMLDocument.h
@@ -46,17 +46,18 @@ public:
 
   virtual void EndLoad() override;
 
   // nsIDOMXMLDocument
   NS_DECL_NSIDOMXMLDOCUMENT
 
   virtual nsresult Init() override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual void DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const override;
   // DocAddSizeOfIncludingThis is inherited from nsIDocument.
 
 
   // WebIDL API
   bool Load(const nsAString& aUrl, CallerType aCallerType, ErrorResult& aRv);
   bool Async() const
--- a/dom/xml/nsXMLElement.h
+++ b/dom/xml/nsXMLElement.h
@@ -26,17 +26,18 @@ public:
 
   // nsIDOMNode
   NS_FORWARD_NSIDOMNODE_TO_NSINODE
 
   // nsIDOMElement
   NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
 
   // nsINode interface methods
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                         bool aPreallocateChildren) const override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
 protected:
   virtual ~nsXMLElement() {}
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -1867,17 +1867,18 @@ XULDocument::RemoveElementFromRefMap(Ele
 }
 
 //----------------------------------------------------------------------
 //
 // nsIDOMNode interface
 //
 
 nsresult
-XULDocument::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+XULDocument::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                   bool aPreallocateChildren) const
 {
     // We don't allow cloning of a XUL document
     *aResult = nullptr;
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 }
 
 
 //----------------------------------------------------------------------
--- a/dom/xul/XULDocument.h
+++ b/dom/xul/XULDocument.h
@@ -133,17 +133,18 @@ public:
     NS_IMETHOD SetTemplateBuilderFor(nsIContent* aContent,
                                      nsIXULTemplateBuilder* aBuilder) override;
     NS_IMETHOD GetTemplateBuilderFor(nsIContent* aContent,
                                      nsIXULTemplateBuilder** aResult) override;
     NS_IMETHOD OnPrototypeLoadDone(bool aResumeWalk) override;
     bool OnDocumentParserError() override;
 
     // nsINode interface overrides
-    virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+    virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                           bool aPreallocateChildren) const override;
 
     // nsIDOMNode interface
     NS_FORWARD_NSIDOMNODE_TO_NSINODE
 
     // nsIDOMDocument interface
     using nsDocument::CreateElement;
     using nsDocument::CreateElementNS;
     NS_FORWARD_NSIDOMDOCUMENT(XMLDocument::)
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -352,32 +352,37 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION
     NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIFrameLoaderOwner,
                                    new nsXULElementTearoff(this))
 NS_INTERFACE_MAP_END_INHERITING(nsStyledElement)
 
 //----------------------------------------------------------------------
 // nsIDOMNode interface
 
 nsresult
-nsXULElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
+nsXULElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                    bool aPreallocateChildren) const
 {
     *aResult = nullptr;
 
     RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
     RefPtr<nsXULElement> element = new nsXULElement(ni.forget());
 
+    nsresult rv = element->mAttrsAndChildren.EnsureCapacityToClone(mAttrsAndChildren,
+                                                                   aPreallocateChildren);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     // XXX TODO: set up RDF generic builder n' stuff if there is a
     // 'datasources' attribute? This is really kind of tricky,
     // because then we'd need to -selectively- copy children that
     // -weren't- generated from RDF. Ugh. Forget it.
 
     // Note that we're _not_ copying mControllers.
 
     uint32_t count = mAttrsAndChildren.AttrCount();
-    nsresult rv = NS_OK;
+    rv = NS_OK;
     for (uint32_t i = 0; i < count; ++i) {
         const nsAttrName* originalName = mAttrsAndChildren.AttrNameAt(i);
         const nsAttrValue* originalValue = mAttrsAndChildren.AttrAt(i);
         nsAttrValue attrValue;
 
         // Style rules need to be cloned.
         if (originalValue->Type() == nsAttrValue::eCSSDeclaration) {
             DeclarationBlock* decl = originalValue->GetCSSDeclarationValue();
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -409,17 +409,18 @@ public:
     using nsStyledElement::GetParentElement;
 
     // nsIDOMElement
     NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
 
     // nsIDOMXULElement
     NS_DECL_NSIDOMXULELEMENT
 
-    virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
+    virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                           bool aPreallocateChildren) const override;
     virtual mozilla::EventStates IntrinsicState() const override;
 
     nsresult GetFrameLoaderXPCOM(nsIFrameLoader** aFrameLoader);
     void PresetOpenerWindow(mozIDOMWindowProxy* aWindow, ErrorResult& aRv);
     nsresult SetIsPrerendered();
 
     virtual void RecompileScriptEventListeners() override;
 
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -1287,16 +1287,23 @@ public:
     : nsBlockFrame(aContext),
       mComboBox(aComboBox)
   {}
 
   // Need this so that line layout knows that this block's inline size
   // depends on the available inline size.
   virtual nsIAtom* GetType() const override;
 
+#ifdef DEBUG_FRAME_DUMP
+  nsresult GetFrameName(nsAString& aResult) const override
+  {
+    return MakeFrameName(NS_LITERAL_STRING("ComboboxDisplay"), aResult);
+  }
+#endif
+
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
     return nsBlockFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplacedContainsBlock));
   }
 
   virtual void Reflow(nsPresContext*           aPresContext,
                           ReflowOutput&     aDesiredSize,
@@ -1367,18 +1374,17 @@ nsComboboxControlFrame::CreateFrameForDi
   // Get PresShell
   nsIPresShell *shell = PresContext()->PresShell();
   StyleSetHandle styleSet = shell->StyleSet();
 
   // create the style contexts for the anonymous block frame and text frame
   RefPtr<nsStyleContext> styleContext;
   styleContext = styleSet->
     ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozDisplayComboboxControlFrame,
-                                       mStyleContext,
-                                       nsStyleSet::eSkipParentDisplayBasedStyleFixup);
+                                       mStyleContext);
 
   RefPtr<nsStyleContext> textStyleContext;
   textStyleContext =
     styleSet->ResolveStyleForText(mDisplayContent, mStyleContext);
 
   // Start by creating our anonymous block frame
   mDisplayFrame = new (shell) nsComboboxDisplayFrame(styleContext, this);
   mDisplayFrame->Init(mContent, this, nullptr);
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -207,23 +207,18 @@ already_AddRefed<nsStyleContext>
 ServoStyleSet::GetContext(already_AddRefed<ServoComputedValues> aComputedValues,
                           nsStyleContext* aParentContext,
                           nsIAtom* aPseudoTag,
                           CSSPseudoElementType aPseudoType,
                           Element* aElementForAnimation)
 {
   // XXXbholley: nsStyleSet does visited handling here.
 
-  // XXXbholley: Figure out the correct thing to pass here. Does this fixup
-  // duplicate something that servo already does?
-  // See bug 1344914.
-  bool skipFixup = false;
-
   RefPtr<nsStyleContext> result = NS_NewStyleContext(aParentContext, mPresContext, aPseudoTag,
-                                                     aPseudoType, Move(aComputedValues), skipFixup);
+                                                     aPseudoType, Move(aComputedValues));
 
   // Set the body color on the pres context. See nsStyleSet::GetContext
   if (aElementForAnimation &&
       aElementForAnimation->IsHTMLElement(nsGkAtoms::body) &&
       aPseudoType == CSSPseudoElementType::NotPseudo &&
       mPresContext->CompatibilityMode() == eCompatibility_NavQuirks) {
     nsIDocument* doc = aElementForAnimation->GetUncomposedDoc();
     if (doc && doc->GetBodyElement() == aElementForAnimation) {
@@ -464,28 +459,25 @@ ServoStyleSet::ResolveTransientStyle(Ele
 already_AddRefed<ServoComputedValues>
 ServoStyleSet::ResolveTransientServoStyle(Element* aElement,
                                           nsIAtom* aPseudoTag)
 {
   PreTraverseSync();
   return ResolveStyleLazily(aElement, aPseudoTag);
 }
 
-// aFlags is an nsStyleSet flags bitfield
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
-                                                  nsStyleContext* aParentContext,
-                                                  uint32_t aFlags)
+                                                  nsStyleContext* aParentContext)
 {
   MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
              !nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag));
 
-  MOZ_ASSERT(aFlags == 0 ||
-             aFlags == nsStyleSet::eSkipParentDisplayBasedStyleFixup);
-  bool skipFixup = aFlags & nsStyleSet::eSkipParentDisplayBasedStyleFixup;
+  bool skipFixup =
+    nsCSSAnonBoxes::AnonBoxSkipsParentDisplayBasedStyleFixup(aPseudoTag);
 
   const ServoComputedValues* parentStyle =
     aParentContext ? aParentContext->StyleSource().AsServoComputedValues()
                    : nullptr;
   RefPtr<ServoComputedValues> computedValues =
     Servo_ComputedValues_GetForAnonymousBox(parentStyle, aPseudoTag, skipFixup,
                                             mRawSet.get()).Consume();
 #ifdef DEBUG
@@ -493,21 +485,18 @@ ServoStyleSet::ResolveInheritingAnonymou
     nsString pseudo;
     aPseudoTag->ToString(pseudo);
     NS_ERROR(nsPrintfCString("stylo: could not get anon-box: %s",
              NS_ConvertUTF16toUTF8(pseudo).get()).get());
     MOZ_CRASH();
   }
 #endif
 
-  // FIXME(bz, bug 1344914) We should really GetContext here and make skipFixup
-  // work there.
-  return NS_NewStyleContext(aParentContext, mPresContext, aPseudoTag,
-                            CSSPseudoElementType::InheritingAnonBox,
-                            computedValues.forget(), skipFixup);
+  return GetContext(computedValues.forget(), aParentContext, aPseudoTag,
+                    CSSPseudoElementType::InheritingAnonBox, nullptr);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag)
 {
   MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
              nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag));
   MOZ_ASSERT(aPseudoTag != nsCSSAnonBoxes::pageContent,
@@ -520,17 +509,19 @@ ServoStyleSet::ResolveNonInheritingAnony
     nsCSSAnonBoxes::NonInheritingTypeForPseudoTag(aPseudoTag);
   RefPtr<nsStyleContext>& cache = mNonInheritingStyleContexts[type];
   if (cache) {
     RefPtr<nsStyleContext> retval = cache;
     return retval.forget();
   }
 
   // We always want to skip parent-based display fixup here.  It never makes
-  // sense for non-inheriting anonymous boxes.
+  // sense for non-inheriting anonymous boxes.  (Static assertions in
+  // nsCSSAnonBoxes.cpp ensure that all non-inheriting non-anonymous boxes
+  // are indeed annotated as skipping this fixup.)
   MOZ_ASSERT(!nsCSSAnonBoxes::IsNonInheritingAnonBox(nsCSSAnonBoxes::viewport),
              "viewport needs fixup to handle blockifying it");
   RefPtr<ServoComputedValues> computedValues =
     Servo_ComputedValues_GetForAnonymousBox(nullptr, aPseudoTag, true,
                                             mRawSet.get()).Consume();
 #ifdef DEBUG
   if (!computedValues) {
     nsString pseudo;
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -169,22 +169,20 @@ public:
 
   // Similar to ResolveTransientStyle() but returns ServoComputedValues.
   // Unlike ResolveServoStyle() this function calls PreTraverseSync().
   already_AddRefed<ServoComputedValues>
   ResolveTransientServoStyle(dom::Element* aElement, nsIAtom* aPseudoTag);
 
   // Get a style context for an anonymous box.  aPseudoTag is the pseudo-tag to
   // use and must be non-null.  It must be an anon box, and must be one that
-  // inherits style from the given aParentContext.  aFlags is an nsStyleSet
-  // flags bitfield.
+  // inherits style from the given aParentContext.
   already_AddRefed<nsStyleContext>
   ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
-                                     nsStyleContext* aParentContext,
-                                     uint32_t aFlags = 0);
+                                     nsStyleContext* aParentContext);
 
   // Get a style context for an anonymous box that does not inherit style from
   // anything.  aPseudoTag is the pseudo-tag to use and must be non-null.  It
   // must be an anon box, and must be a non-inheriting one.
   already_AddRefed<nsStyleContext>
   ResolveNonInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag);
 
   // manage the set of style sheets in the style set
--- a/layout/style/StyleSetHandle.h
+++ b/layout/style/StyleSetHandle.h
@@ -132,18 +132,17 @@ public:
     ResolveStyleForPlaceholder();
     inline already_AddRefed<nsStyleContext>
     ResolvePseudoElementStyle(dom::Element* aParentElement,
                               mozilla::CSSPseudoElementType aType,
                               nsStyleContext* aParentContext,
                               dom::Element* aPseudoElement);
     inline already_AddRefed<nsStyleContext>
     ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
-                                       nsStyleContext* aParentContext,
-                                       uint32_t aFlags = 0);
+                                       nsStyleContext* aParentContext);
     inline already_AddRefed<nsStyleContext>
     ResolveNonInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag);
     inline nsresult AppendStyleSheet(SheetType aType, StyleSheet* aSheet);
     inline nsresult PrependStyleSheet(SheetType aType, StyleSheet* aSheet);
     inline nsresult RemoveStyleSheet(SheetType aType, StyleSheet* aSheet);
     inline nsresult ReplaceSheets(SheetType aType,
                            const nsTArray<RefPtr<StyleSheet>>& aNewSheets);
     inline nsresult InsertStyleSheetBefore(SheetType aType,
--- a/layout/style/StyleSetHandleInlines.h
+++ b/layout/style/StyleSetHandleInlines.h
@@ -118,24 +118,21 @@ StyleSetHandle::Ptr::ResolvePseudoElemen
                                                CSSPseudoElementType aType,
                                                nsStyleContext* aParentContext,
                                                dom::Element* aPseudoElement)
 {
   FORWARD(ResolvePseudoElementStyle, (aParentElement, aType, aParentContext,
                                       aPseudoElement));
 }
 
-// aFlags is an nsStyleSet flags bitfield
 already_AddRefed<nsStyleContext>
 StyleSetHandle::Ptr::ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
-                                                        nsStyleContext* aParentContext,
-                                                        uint32_t aFlags)
+                                                        nsStyleContext* aParentContext)
 {
-  FORWARD(ResolveInheritingAnonymousBoxStyle, (aPseudoTag, aParentContext,
-                                               aFlags));
+  FORWARD(ResolveInheritingAnonymousBoxStyle, (aPseudoTag, aParentContext));
 }
 
 already_AddRefed<nsStyleContext>
 StyleSetHandle::Ptr::ResolveNonInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag)
 {
   FORWARD(ResolveNonInheritingAnonymousBoxStyle, (aPseudoTag));
 }
 
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/1342316-1.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<html class="reftest-wait">
+<title>calc() in translate3d as base style of transform animation</title>
+<style>
+#target {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: anim 1s;
+  transform: translate3d(100px, calc(10px + 30%), 10px);
+}
+@keyframes anim {
+  to { transform: translate3d(0px, 0px, 0px); }
+}
+</style>
+<div id="target"></div>
+<script>
+document.getElementById("target").addEventListener("animationstart", () => {
+  document.documentElement.classList.remove("reftest-wait");
+});
+</script>
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -165,9 +165,10 @@ load 1315889-1.html
 load 1315894-1.html
 load 1319072-1.html
 HTTP load 1320423-1.html
 load 1321357-1.html
 load 1328535-1.html
 load 1331272.html
 HTTP load 1333001-1.html
 pref(dom.animations-api.core.enabled,true) load 1340344.html
+load 1342316-1.html
 load 1356601-1.html
--- a/layout/style/nsCSSAnonBoxList.h
+++ b/layout/style/nsCSSAnonBoxList.h
@@ -7,115 +7,122 @@
 
 /*
  * This file contains the list of nsIAtoms and their values for CSS
  * pseudo-element-ish things used internally for anonymous boxes.  It is
  * designed to be used as inline input to nsCSSAnonBoxes.cpp *only* through the
  * magic of C preprocessing.  All entries must be enclosed in the macros
  * CSS_ANON_BOX and CSS_NON_INHERITING_ANON_BOX which will have cruel and
  * unusual things done to it.  The entries should be kept in some sort of
- * logical order.  The first argument to
- * CSS_ANON_BOX/CSS_NON_INHERITING_ANON_BOX is the C++ identifier of the atom.
+ * logical order.
+ *
+ * The first argument to CSS_ANON_BOX/CSS_NON_INHERITING_ANON_BOX is the C++
+ * identifier of the atom.
+ *
  * The second argument is the string value of the atom.
  *
+ * The third argument to CSS_ANON_BOX is whether the anonymous box skips parent-
+ * based display fixups (such as blockification inside flex containers).  This
+ * is implicitly true for CSS_NON_INHERITING_ANON_BOX.
+ *
  * CSS_NON_INHERITING_ANON_BOX is used for anon boxes that never inherit style
  * from anything.  This means all their property values are the initial values
  * of those properties.
  */
 
 // OUTPUT_CLASS=nsCSSAnonBoxes
 // MACRO_NAME=CSS_ANON_BOX/CSS_NON_INHERITING_ANON_BOX
 
 #ifndef CSS_NON_INHERITING_ANON_BOX
 #  ifdef DEFINED_CSS_NON_INHERITING_ANON_BOX
 #    error "Recursive includes of nsCSSAnonBoxList.h?"
 #  endif /* DEFINED_CSS_NON_INHERITING_ANON_BOX */
-#  define CSS_NON_INHERITING_ANON_BOX CSS_ANON_BOX
+#  define CSS_NON_INHERITING_ANON_BOX(name_, value_) CSS_ANON_BOX(name_, value_, true)
 #  define DEFINED_CSS_NON_INHERITING_ANON_BOX
 #endif /* CSS_NON_INHERITING_ANON_BOX */
 
 // ::-moz-text, ::-moz-oof-placeholder, and ::-moz-first-letter-continuation are
 // non-elements which no rule will match.
-CSS_ANON_BOX(mozText, ":-moz-text")
+CSS_ANON_BOX(mozText, ":-moz-text", false)
 // placeholder frames for out of flows.  Note that :-moz-placeholder is used for
 // the pseudo-element that represents the placeholder text in <input
 // placeholder="foo">, so we need a different string here.
 CSS_NON_INHERITING_ANON_BOX(oofPlaceholder, ":-moz-oof-placeholder")
 // nsFirstLetterFrames for content outside the ::first-letter.
-CSS_ANON_BOX(firstLetterContinuation, ":-moz-first-letter-continuation")
+CSS_ANON_BOX(firstLetterContinuation, ":-moz-first-letter-continuation", false)
 
-CSS_ANON_BOX(mozBlockInsideInlineWrapper, ":-moz-block-inside-inline-wrapper")
-CSS_ANON_BOX(mozMathMLAnonymousBlock, ":-moz-mathml-anonymous-block")
-CSS_ANON_BOX(mozXULAnonymousBlock, ":-moz-xul-anonymous-block")
+CSS_ANON_BOX(mozBlockInsideInlineWrapper, ":-moz-block-inside-inline-wrapper", false)
+CSS_ANON_BOX(mozMathMLAnonymousBlock, ":-moz-mathml-anonymous-block", false)
+CSS_ANON_BOX(mozXULAnonymousBlock, ":-moz-xul-anonymous-block", false)
 
 // Framesets
 CSS_NON_INHERITING_ANON_BOX(horizontalFramesetBorder, ":-moz-hframeset-border")
 CSS_NON_INHERITING_ANON_BOX(verticalFramesetBorder, ":-moz-vframeset-border")
 
-CSS_ANON_BOX(mozLineFrame, ":-moz-line-frame")
+CSS_ANON_BOX(mozLineFrame, ":-moz-line-frame", false)
 
-CSS_ANON_BOX(buttonContent, ":-moz-button-content")
-CSS_ANON_BOX(cellContent, ":-moz-cell-content")
-CSS_ANON_BOX(dropDownList, ":-moz-dropdown-list")
-CSS_ANON_BOX(fieldsetContent, ":-moz-fieldset-content")
+CSS_ANON_BOX(buttonContent, ":-moz-button-content", false)
+CSS_ANON_BOX(cellContent, ":-moz-cell-content", false)
+CSS_ANON_BOX(dropDownList, ":-moz-dropdown-list", false)
+CSS_ANON_BOX(fieldsetContent, ":-moz-fieldset-content", false)
 CSS_NON_INHERITING_ANON_BOX(framesetBlank, ":-moz-frameset-blank")
-CSS_ANON_BOX(mozDisplayComboboxControlFrame, ":-moz-display-comboboxcontrol-frame")
-CSS_ANON_BOX(htmlCanvasContent, ":-moz-html-canvas-content")
+CSS_ANON_BOX(mozDisplayComboboxControlFrame, ":-moz-display-comboboxcontrol-frame", true)
+CSS_ANON_BOX(htmlCanvasContent, ":-moz-html-canvas-content", false)
 
-CSS_ANON_BOX(inlineTable, ":-moz-inline-table")
-CSS_ANON_BOX(table, ":-moz-table")
-CSS_ANON_BOX(tableCell, ":-moz-table-cell")
-CSS_ANON_BOX(tableColGroup, ":-moz-table-column-group")
-CSS_ANON_BOX(tableCol, ":-moz-table-column")
-CSS_ANON_BOX(tableWrapper, ":-moz-table-wrapper")
-CSS_ANON_BOX(tableRowGroup, ":-moz-table-row-group")
-CSS_ANON_BOX(tableRow, ":-moz-table-row")
+CSS_ANON_BOX(inlineTable, ":-moz-inline-table", false)
+CSS_ANON_BOX(table, ":-moz-table", false)
+CSS_ANON_BOX(tableCell, ":-moz-table-cell", false)
+CSS_ANON_BOX(tableColGroup, ":-moz-table-column-group", false)
+CSS_ANON_BOX(tableCol, ":-moz-table-column", false)
+CSS_ANON_BOX(tableWrapper, ":-moz-table-wrapper", false)
+CSS_ANON_BOX(tableRowGroup, ":-moz-table-row-group", false)
+CSS_ANON_BOX(tableRow, ":-moz-table-row", false)
 
-CSS_ANON_BOX(canvas, ":-moz-canvas")
+CSS_ANON_BOX(canvas, ":-moz-canvas", false)
 CSS_NON_INHERITING_ANON_BOX(pageBreak, ":-moz-pagebreak")
-CSS_ANON_BOX(page, ":-moz-page")
-CSS_ANON_BOX(pageContent, ":-moz-pagecontent")
-CSS_ANON_BOX(pageSequence, ":-moz-page-sequence")
-CSS_ANON_BOX(scrolledContent, ":-moz-scrolled-content")
-CSS_ANON_BOX(scrolledCanvas, ":-moz-scrolled-canvas")
-CSS_ANON_BOX(scrolledPageSequence, ":-moz-scrolled-page-sequence")
-CSS_ANON_BOX(columnContent, ":-moz-column-content")
-CSS_ANON_BOX(viewport, ":-moz-viewport")
-CSS_ANON_BOX(viewportScroll, ":-moz-viewport-scroll")
+CSS_ANON_BOX(page, ":-moz-page", false)
+CSS_ANON_BOX(pageContent, ":-moz-pagecontent", false)
+CSS_ANON_BOX(pageSequence, ":-moz-page-sequence", false)
+CSS_ANON_BOX(scrolledContent, ":-moz-scrolled-content", false)
+CSS_ANON_BOX(scrolledCanvas, ":-moz-scrolled-canvas", false)
+CSS_ANON_BOX(scrolledPageSequence, ":-moz-scrolled-page-sequence", false)
+CSS_ANON_BOX(columnContent, ":-moz-column-content", false)
+CSS_ANON_BOX(viewport, ":-moz-viewport", false)
+CSS_ANON_BOX(viewportScroll, ":-moz-viewport-scroll", false)
 
 // Inside a flex container, a contiguous run of text gets wrapped in
 // an anonymous block, which is then treated as a flex item.
-CSS_ANON_BOX(anonymousFlexItem, ":-moz-anonymous-flex-item")
+CSS_ANON_BOX(anonymousFlexItem, ":-moz-anonymous-flex-item", false)
 
 // Inside a grid container, a contiguous run of text gets wrapped in
 // an anonymous block, which is then treated as a grid item.
-CSS_ANON_BOX(anonymousGridItem, ":-moz-anonymous-grid-item")
+CSS_ANON_BOX(anonymousGridItem, ":-moz-anonymous-grid-item", false)
 
-CSS_ANON_BOX(ruby, ":-moz-ruby")
-CSS_ANON_BOX(rubyBase, ":-moz-ruby-base")
-CSS_ANON_BOX(rubyBaseContainer, ":-moz-ruby-base-container")
-CSS_ANON_BOX(rubyText, ":-moz-ruby-text")
-CSS_ANON_BOX(rubyTextContainer, ":-moz-ruby-text-container")
+CSS_ANON_BOX(ruby, ":-moz-ruby", false)
+CSS_ANON_BOX(rubyBase, ":-moz-ruby-base", false)
+CSS_ANON_BOX(rubyBaseContainer, ":-moz-ruby-base-container", false)
+CSS_ANON_BOX(rubyText, ":-moz-ruby-text", false)
+CSS_ANON_BOX(rubyTextContainer, ":-moz-ruby-text-container", false)
 
 #ifdef MOZ_XUL
-CSS_ANON_BOX(moztreecolumn, ":-moz-tree-column")
-CSS_ANON_BOX(moztreerow, ":-moz-tree-row")
-CSS_ANON_BOX(moztreeseparator, ":-moz-tree-separator")
-CSS_ANON_BOX(moztreecell, ":-moz-tree-cell")
-CSS_ANON_BOX(moztreeindentation, ":-moz-tree-indentation")
-CSS_ANON_BOX(moztreeline, ":-moz-tree-line")
-CSS_ANON_BOX(moztreetwisty, ":-moz-tree-twisty")
-CSS_ANON_BOX(moztreeimage, ":-moz-tree-image")
-CSS_ANON_BOX(moztreecelltext, ":-moz-tree-cell-text")
-CSS_ANON_BOX(moztreecheckbox, ":-moz-tree-checkbox")
-CSS_ANON_BOX(moztreeprogressmeter, ":-moz-tree-progressmeter")
-CSS_ANON_BOX(moztreedropfeedback, ":-moz-tree-drop-feedback")
+CSS_ANON_BOX(moztreecolumn, ":-moz-tree-column", false)
+CSS_ANON_BOX(moztreerow, ":-moz-tree-row", false)
+CSS_ANON_BOX(moztreeseparator, ":-moz-tree-separator", false)
+CSS_ANON_BOX(moztreecell, ":-moz-tree-cell", false)
+CSS_ANON_BOX(moztreeindentation, ":-moz-tree-indentation", false)
+CSS_ANON_BOX(moztreeline, ":-moz-tree-line", false)
+CSS_ANON_BOX(moztreetwisty, ":-moz-tree-twisty", false)
+CSS_ANON_BOX(moztreeimage, ":-moz-tree-image", false)
+CSS_ANON_BOX(moztreecelltext, ":-moz-tree-cell-text", false)
+CSS_ANON_BOX(moztreecheckbox, ":-moz-tree-checkbox", false)
+CSS_ANON_BOX(moztreeprogressmeter, ":-moz-tree-progressmeter", false)
+CSS_ANON_BOX(moztreedropfeedback, ":-moz-tree-drop-feedback", false)
 #endif
 
-CSS_ANON_BOX(mozSVGMarkerAnonChild, ":-moz-svg-marker-anon-child")
-CSS_ANON_BOX(mozSVGOuterSVGAnonChild, ":-moz-svg-outer-svg-anon-child")
-CSS_ANON_BOX(mozSVGForeignContent, ":-moz-svg-foreign-content")
-CSS_ANON_BOX(mozSVGText, ":-moz-svg-text")
+CSS_ANON_BOX(mozSVGMarkerAnonChild, ":-moz-svg-marker-anon-child", false)
+CSS_ANON_BOX(mozSVGOuterSVGAnonChild, ":-moz-svg-outer-svg-anon-child", false)
+CSS_ANON_BOX(mozSVGForeignContent, ":-moz-svg-foreign-content", false)
+CSS_ANON_BOX(mozSVGText, ":-moz-svg-text", false)
 
 #ifdef DEFINED_CSS_NON_INHERITING_ANON_BOX
 #  undef DEFINED_CSS_NON_INHERITING_ANON_BOX
 #  undef CSS_NON_INHERITING_ANON_BOX
 #endif /* DEFINED_CSS_NON_INHERITING_ANON_BOX */
--- a/layout/style/nsCSSAnonBoxes.cpp
+++ b/layout/style/nsCSSAnonBoxes.cpp
@@ -9,36 +9,36 @@
 
 #include "nsCSSAnonBoxes.h"
 #include "nsAtomListUtils.h"
 #include "nsStaticAtom.h"
 
 using namespace mozilla;
 
 // define storage for all atoms
-#define CSS_ANON_BOX(_name, _value) \
-  nsICSSAnonBoxPseudo* nsCSSAnonBoxes::_name;
+#define CSS_ANON_BOX(name_, value_, skips_fixup_) \
+  nsICSSAnonBoxPseudo* nsCSSAnonBoxes::name_;
 #include "nsCSSAnonBoxList.h"
 #undef CSS_ANON_BOX
 
-#define CSS_ANON_BOX(name_, value_) \
+#define CSS_ANON_BOX(name_, value_, skips_fixup_) \
   NS_STATIC_ATOM_BUFFER(name_##_buffer, value_)
 #include "nsCSSAnonBoxList.h"
 #undef CSS_ANON_BOX
 
 static const nsStaticAtom CSSAnonBoxes_info[] = {
   // Put the non-inheriting anon boxes first, so we can index into them easily.
-#define CSS_ANON_BOX(name_, value_) /* nothing */
+#define CSS_ANON_BOX(name_, value_, skips_fixup_) /* nothing */
 #define CSS_NON_INHERITING_ANON_BOX(name_, value_) \
   NS_STATIC_ATOM(name_##_buffer, (nsIAtom**)&nsCSSAnonBoxes::name_),
 #include "nsCSSAnonBoxList.h"
 #undef CSS_NON_INHERITING_ANON_BOX
 #undef CSS_ANON_BOX
 
-#define CSS_ANON_BOX(name_, value_)                                   \
+#define CSS_ANON_BOX(name_, value_, skips_fixup_) \
   NS_STATIC_ATOM(name_##_buffer, (nsIAtom**)&nsCSSAnonBoxes::name_),
 #define CSS_NON_INHERITING_ANON_BOX(name_, value_) /* nothing */
 #include "nsCSSAnonBoxList.h"
 #undef CSS_NON_INHERITING_ANON_BOX
 #undef CSS_ANON_BOX
 };
 
 void nsCSSAnonBoxes::AddRefAtoms()
--- a/layout/style/nsCSSAnonBoxes.h
+++ b/layout/style/nsCSSAnonBoxes.h
@@ -24,46 +24,64 @@ public:
   static bool IsTreePseudoElement(nsIAtom* aPseudo);
 #endif
   static bool IsNonElement(nsIAtom* aPseudo)
   {
     return aPseudo == mozText || aPseudo == oofPlaceholder ||
            aPseudo == firstLetterContinuation;
   }
 
-#define CSS_ANON_BOX(_name, _value) static nsICSSAnonBoxPseudo* _name;
+#define CSS_ANON_BOX(_name, _value, _skips_fixup) static nsICSSAnonBoxPseudo* _name;
 #include "nsCSSAnonBoxList.h"
 #undef CSS_ANON_BOX
 
   typedef uint8_t NonInheritingBase;
   enum class NonInheriting : NonInheritingBase {
-#define CSS_ANON_BOX(_name, _value) /* nothing */
+#define CSS_ANON_BOX(_name, _value, _skips_fixup) /* nothing */
 #define CSS_NON_INHERITING_ANON_BOX(_name, _value) _name,
 #include "nsCSSAnonBoxList.h"
 #undef CSS_NON_INHERITING_ANON_BOX
 #undef CSS_ANON_BOX
     _Count
   };
 
   // Be careful using this: if we have a lot of non-inheriting anon box types it
   // might not be very fast.  We may want to think of ways to handle that
   // (e.g. by moving to an enum instead of an atom, like we did for
   // pseudo-elements, or by adding a new value of the pseudo-element enum for
   // non-inheriting anon boxes or something).
   static bool IsNonInheritingAnonBox(nsIAtom* aPseudo)
   {
     return
-#define CSS_ANON_BOX(_name, _value) /* nothing */
+#define CSS_ANON_BOX(_name, _value, _skips_fixup) /* nothing */
 #define CSS_NON_INHERITING_ANON_BOX(_name, _value) _name == aPseudo ||
 #include "nsCSSAnonBoxList.h"
 #undef CSS_NON_INHERITING_ANON_BOX
 #undef CSS_ANON_BOX
       false;
   }
 
+  // Returns whether the given anonymous box skips parent display-based style
+  // fixups.  Must only be called with an inheriting anonymous box.  (All
+  // non-inheriting anonymous boxes skip this fixup, since it doesn't make
+  // sense to perform the fixup with no inherited styles.)
+  static bool AnonBoxSkipsParentDisplayBasedStyleFixup(nsIAtom* aPseudo)
+  {
+    MOZ_ASSERT(!IsNonInheritingAnonBox(aPseudo),
+               "only call this for inheriting anonymous boxes");
+    return
+#define CSS_ANON_BOX(name_, value_, skips_fixup_) \
+      (skips_fixup_ && name_ == aPseudo) ||
+#define CSS_NON_INHERITING_ANON_BOX(_name, _value) /* nothing */
+#include "nsCSSAnonBoxList.h"
+#undef CSS_NON_INHERITING_ANON_BOX
+#undef CSS_ANON_BOX
+      false;
+  }
+
   // Get the NonInheriting type for a given pseudo tag.  The pseudo tag must
   // test true for IsNonInheritingAnonBox.
   static NonInheriting NonInheritingTypeForPseudoTag(nsIAtom* aPseudo);
 
   // Get the atom for a given non-inheriting anon box type.  aBoxType must be <
   // NonInheriting::_Count.
   static nsIAtom* GetNonInheritingPseudoAtom(NonInheriting aBoxType);
 };
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -868,17 +868,17 @@ nsCSSValue::GetCalcValue() const
     result.mLength = rootValue.GetFloatValue();
     result.mPercent = 0.0f;
     result.mHasPercent = false;
   } else {
     MOZ_ASSERT(rootValue.GetUnit() == eCSSUnit_Calc_Plus,
                "Calc unit should be eCSSUnit_Calc_Plus");
 
     const nsCSSValue::Array *calcPlusArray = rootValue.GetArrayValue();
-    MOZ_ASSERT(array->Count() == 2,
+    MOZ_ASSERT(calcPlusArray->Count() == 2,
                "eCSSUnit_Calc_Plus should have a 2-length array");
 
     const nsCSSValue& length = calcPlusArray->Item(0);
     const nsCSSValue& percent = calcPlusArray->Item(1);
     MOZ_ASSERT(length.GetUnit() == eCSSUnit_Pixel,
                "The first value should be eCSSUnit_Pixel");
     MOZ_ASSERT(percent.GetUnit() == eCSSUnit_Percent,
                "The first value should be eCSSUnit_Percent");
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -121,37 +121,40 @@ nsStyleContext::nsStyleContext(nsStyleCo
       r2 = r2->GetParent();
     NS_ASSERTION(r1 == r2, "must be in the same rule tree as parent");
 #endif
   } else {
     PresContext()->PresShell()->StyleSet()->RootStyleContextAdded();
   }
 
   mSource.AsGeckoRuleNode()->SetUsedDirectly(); // before ApplyStyleFixups()!
-  FinishConstruction(aSkipParentDisplayBasedStyleFixup);
+  FinishConstruction();
+  ApplyStyleFixups(aSkipParentDisplayBasedStyleFixup);
 }
 
 nsStyleContext::nsStyleContext(nsStyleContext* aParent,
                                nsPresContext* aPresContext,
                                nsIAtom* aPseudoTag,
                                CSSPseudoElementType aPseudoType,
-                               already_AddRefed<ServoComputedValues> aComputedValues,
-                               bool aSkipParentDisplayBasedStyleFixup)
+                               already_AddRefed<ServoComputedValues> aComputedValues)
   : nsStyleContext(aParent, OwningStyleContextSource(Move(aComputedValues)),
                    aPseudoTag, aPseudoType)
 {
 #ifdef MOZ_STYLO
   mPresContext = aPresContext;
 #endif
 
-  FinishConstruction(aSkipParentDisplayBasedStyleFixup);
+  FinishConstruction();
+
+  // No need to call ApplyStyleFixups here, since fixups are handled by Servo when
+  // producing the ServoComputedValues.
 }
 
 void
-nsStyleContext::FinishConstruction(bool aSkipParentDisplayBasedStyleFixup)
+nsStyleContext::FinishConstruction()
 {
   // This check has to be done "backward", because if it were written the
   // more natural way it wouldn't fail even when it needed to.
   static_assert((UINT64_MAX >> NS_STYLE_CONTEXT_TYPE_SHIFT) >=
                  static_cast<CSSPseudoElementTypeBase>(
                    CSSPseudoElementType::MAX),
                 "pseudo element bits no longer fit in a uint64_t");
   MOZ_ASSERT(!mSource.IsNull());
@@ -164,23 +167,20 @@ nsStyleContext::FinishConstruction(bool 
 
   mNextSibling = this;
   mPrevSibling = this;
   if (mParent) {
     mParent->AddChild(this);
   }
 
   SetStyleBits();
-  if (!mSource.IsServoComputedValues()) {
-    ApplyStyleFixups(aSkipParentDisplayBasedStyleFixup);
-  }
 
   #define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
-  NS_ASSERTION(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
-               "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
+  static_assert(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
+                "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
   #undef eStyleStruct_LastItem
 }
 
 nsStyleContext::~nsStyleContext()
 {
   NS_ASSERTION((nullptr == mChild) && (nullptr == mEmptyChild), "destructing context with children");
   MOZ_ASSERT_IF(mSource.IsServoComputedValues(), !mCachedResetData);
 
@@ -1389,23 +1389,22 @@ NS_NewStyleContext(nsStyleContext* aPare
   return context.forget();
 }
 
 already_AddRefed<nsStyleContext>
 NS_NewStyleContext(nsStyleContext* aParentContext,
                    nsPresContext* aPresContext,
                    nsIAtom* aPseudoTag,
                    CSSPseudoElementType aPseudoType,
-                   already_AddRefed<ServoComputedValues> aComputedValues,
-                   bool aSkipParentDisplayBasedStyleFixup)
+                   already_AddRefed<ServoComputedValues> aComputedValues)
 {
   RefPtr<nsStyleContext> context =
     new (aPresContext)
     nsStyleContext(aParentContext, aPresContext, aPseudoTag, aPseudoType,
-                   Move(aComputedValues), aSkipParentDisplayBasedStyleFixup);
+                   Move(aComputedValues));
   return context.forget();
 }
 
 nsIPresShell*
 nsStyleContext::Arena()
 {
   return PresContext()->PresShell();
 }
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -85,18 +85,17 @@ public:
                  bool aSkipParentDisplayBasedStyleFixup);
 
   // Version of the above that takes a ServoComputedValues instead of a Gecko
   // nsRuleNode.
   nsStyleContext(nsStyleContext* aParent,
                  nsPresContext* aPresContext,
                  nsIAtom* aPseudoTag,
                  mozilla::CSSPseudoElementType aPseudoType,
-                 already_AddRefed<ServoComputedValues> aComputedValues,
-                 bool aSkipParentDisplayBasedStyleFixup);
+                 already_AddRefed<ServoComputedValues> aComputedValues);
 
   void* operator new(size_t sz, nsPresContext* aPresContext);
   void Destroy();
 
   // These two methods are for use by ArenaRefPtr.
   static mozilla::ArenaObjectID ArenaObjectID()
   {
     return mozilla::eArenaObjectID_nsStyleContext;
@@ -546,25 +545,27 @@ private:
 
   // Delegated Helper constructor.
   nsStyleContext(nsStyleContext* aParent,
                  mozilla::OwningStyleContextSource&& aSource,
                  nsIAtom* aPseudoTag,
                  mozilla::CSSPseudoElementType aPseudoType);
 
   // Helper post-contruct hook.
-  void FinishConstruction(bool aSkipParentDisplayBasedStyleFixup);
+  void FinishConstruction();
 
   void AddChild(nsStyleContext* aChild);
   void RemoveChild(nsStyleContext* aChild);
 
   void* GetUniqueStyleData(const nsStyleStructID& aSID);
   void* CreateEmptyStyleData(const nsStyleStructID& aSID);
 
   void SetStyleBits();
+
+  // Only called for Gecko-backed nsStyleContexts.
   void ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup);
 
   const void* StyleStructFromServoComputedValues(nsStyleStructID aSID) {
     switch (aSID) {
 #define STYLE_STRUCT(name_, checkdata_cb_)                                    \
       case eStyleStruct_##name_:                                              \
         return Servo_GetStyle##name_(mSource.AsServoComputedValues());
 #include "nsStyleStructList.h"
@@ -806,12 +807,11 @@ NS_NewStyleContext(nsStyleContext* aPare
                    nsRuleNode* aRuleNode,
                    bool aSkipParentDisplayBasedStyleFixup);
 
 already_AddRefed<nsStyleContext>
 NS_NewStyleContext(nsStyleContext* aParentContext,
                    nsPresContext* aPresContext,
                    nsIAtom* aPseudoTag,
                    mozilla::CSSPseudoElementType aPseudoType,
-                   already_AddRefed<ServoComputedValues> aComputedValues,
-                   bool aSkipParentDisplayBasedStyleFixup);
+                   already_AddRefed<ServoComputedValues> aComputedValues);
 
 #endif
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -2078,18 +2078,17 @@ nsStyleSet::ProbePseudoElementStyle(Elem
     }
   }
 
   return result.forget();
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
-                                               nsStyleContext* aParentContext,
-                                               uint32_t aFlags)
+                                               nsStyleContext* aParentContext)
 {
   NS_ENSURE_FALSE(mInShutdown, nullptr);
 
 #ifdef DEBUG
     bool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
                      !nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag)
 #ifdef MOZ_XUL
                  && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag)
@@ -2118,19 +2117,24 @@ nsStyleSet::ResolveInheritingAnonymousBo
         importantRules.AppendElement(importantRule);
       }
     }
     for (uint32_t i = 0, i_end = importantRules.Length(); i != i_end; ++i) {
       ruleWalker.Forward(importantRules[i]);
     }
   }
 
+  uint32_t flags = eNoFlags;
+  if (nsCSSAnonBoxes::AnonBoxSkipsParentDisplayBasedStyleFixup(aPseudoTag)) {
+    flags |= eSkipParentDisplayBasedStyleFixup;
+  }
+
   return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
                     aPseudoTag, CSSPseudoElementType::InheritingAnonBox,
-                    nullptr, aFlags);
+                    nullptr, flags);
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ResolveNonInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag)
 {
   NS_ENSURE_FALSE(mInShutdown, nullptr);
 
 #ifdef DEBUG
@@ -2436,21 +2440,24 @@ nsStyleSet::ReparentStyleContext(nsStyle
   }
 
   if (pseudoType == CSSPseudoElementType::NotPseudo ||
       pseudoType == CSSPseudoElementType::before ||
       pseudoType == CSSPseudoElementType::after) {
     flags |= eDoAnimation;
   }
 
-  if (aElement && aElement->IsRootOfAnonymousSubtree()) {
+  if ((aElement && aElement->IsRootOfAnonymousSubtree()) ||
+      (aStyleContext->IsAnonBox() &&
+       nsCSSAnonBoxes::AnonBoxSkipsParentDisplayBasedStyleFixup(
+         aStyleContext->GetPseudo()))) {
     // For anonymous subtree roots, don't tweak "display" value based on whether
     // or not the parent is styled as a flex/grid container. (If the parent
     // has anonymous-subtree kids, then we know it's not actually going to get
-    // a flex/grid container frame, anyway.)
+    // a flex/grid container frame, anyway.)  Same for certain anonymous boxes.
     flags |= eSkipParentDisplayBasedStyleFixup;
   }
 
   return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
                     pseudoTag, pseudoType,
                     aElement, flags);
 }
 
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -255,18 +255,17 @@ class nsStyleSet final
   already_AddRefed<nsStyleContext>
   ProbePseudoElementStyle(mozilla::dom::Element* aParentElement,
                           mozilla::CSSPseudoElementType aType,
                           nsStyleContext* aParentContext,
                           TreeMatchContext& aTreeMatchContext,
                           mozilla::dom::Element* aPseudoElement = nullptr);
 
   /**
-   * Bit-flags that can be passed to ResolveInheritingAnonymousBoxStyle and
-   * GetContext in their parameter 'aFlags'.
+   * Bit-flags that can be passed to GetContext in its parameter 'aFlags'.
    */
   enum {
     eNoFlags =          0,
     eIsLink =           1 << 0,
     eIsVisitedLink =    1 << 1,
     eDoAnimation =      1 << 2,
 
     // Indicates that we should skip the flex/grid item specific chunk of
@@ -274,22 +273,20 @@ class nsStyleSet final
     // or "display: grid" but we can tell we're not going to honor that (e.g. if
     // it's the outer frame of a button widget, and we're the inline frame for
     // the button's label).
     eSkipParentDisplayBasedStyleFixup = 1 << 3
   };
 
   // Get a style context for an anonymous box.  aPseudoTag is the pseudo-tag to
   // use and must be non-null.  It must be an anon box, and must be one that
-  // inherits style from the given aParentContext.  aFlags will be forwarded to
-  // a GetContext call internally.
+  // inherits style from the given aParentContext.
   already_AddRefed<nsStyleContext>
   ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
-                                     nsStyleContext* aParentContext,
-                                     uint32_t aFlags = eNoFlags);
+                                     nsStyleContext* aParentContext);
 
   // Get a style context for an anonymous box that does not inherit style from
   // anything.  aPseudoTag is the pseudo-tag to use and must be non-null.  It
   // must be an anon box, and must be a non-inheriting one.
   already_AddRefed<nsStyleContext>
   ResolveNonInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag);
 
 #ifdef MOZ_XUL
--- a/layout/style/test/test_keyframes_vendor_prefix.html
+++ b/layout/style/test/test_keyframes_vendor_prefix.html
@@ -67,59 +67,53 @@ var isStylo = false;
 // block.
 try {
   isStylo = SpecialPowers.getBoolPref('layout.css.servo.enabled');
 } catch(e) {
 }
 
 test(function(t) {
   addStyle(t,
-    { 'dummy': '', // XXX bug 1336863 hackaround: a single insertRule is broken
-                   // on stylo.
-      '@-webkit-keyframes anim': 'from,to { color: rgb(0, 255, 0); }' });
+    { '@-webkit-keyframes anim': 'from,to { color: rgb(0, 255, 0); }' });
 
   var div = addDiv(t, { style: 'animation: anim 100s' });
 
   assert_equals(getComputedStyle(div).color, 'rgb(0, 255, 0)');
 }, '-webkit- prefix keyframes');
 
 test(function(t) {
   addStyle(t,
-    { 'dummy': '', // XXX bug 1336863 hackaround, as above.
-      '@-moz-keyframes anim': 'from,to { color: rgb(0, 255, 0); }' });
+    { '@-moz-keyframes anim': 'from,to { color: rgb(0, 255, 0); }' });
 
   var div = addDiv(t, { style: 'animation: anim 100s' });
 
   assert_equals(getComputedStyle(div).color, 'rgb(0, 255, 0)');
 }, '-moz- prefix keyframes');
 
 test(function(t) {
   addStyle(t,
-    { 'dummy': '', // XXX bug 1336863 hackaround, as above.
-      '@-WEBKIT-keyframes anim': 'from,to { color: rgb(0, 255, 0); }' });
+    { '@-WEBKIT-keyframes anim': 'from,to { color: rgb(0, 255, 0); }' });
 
   var div = addDiv(t, { style: 'animation: anim 100s' });
 
   assert_equals(getComputedStyle(div).color, 'rgb(0, 255, 0)');
 }, '-WEBKIT- prefix keyframes');
 
 test(function(t) {
   addStyle(t,
-    { 'dummy': '', // XXX bug 1336863 hackaround, as above.
-      '@-MOZ-keyframes anim': 'from,to { color: rgb(0, 255, 0); }' });
+    { '@-MOZ-keyframes anim': 'from,to { color: rgb(0, 255, 0); }' });
 
   var div = addDiv(t, { style: 'animation: anim 100s' });
 
   assert_equals(getComputedStyle(div).color, 'rgb(0, 255, 0)');
 }, '-MOZ- prefix keyframes');
 
 test(function(t) {
   addStyle(t,
-    { 'dummy': '', // XXX bug 1336863 hackaround, as above.
-      '@-webkit-KEYFRAMES anim': 'from,to { color: rgb(0, 255, 0); }' });
+    { '@-webkit-KEYFRAMES anim': 'from,to { color: rgb(0, 255, 0); }' });
 
   var div = addDiv(t, { style: 'animation: anim 100s' });
 
   assert_equals(getComputedStyle(div).color, 'rgb(0, 255, 0)');
 }, '-webkit- prefix KEYFRAMES');
 
 test(function(t) {
   if (!isStylo) {
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -7211,16 +7211,23 @@
   "MEDIA_DECODING_PROCESS_CRASH": {
     "alert_emails": ["bwu@mozilla.com", "jolin@mozilla.com", "jacheng@mozilla.com"],
     "expires_in_version": "57",
     "kind": "count",
     "bug_numbers": [1297556, 1257777],
     "description": "Records a value each time Fennec remote decoding process crashes unexpected while decoding media content.",
     "releaseChannelCollection": "opt-out"
   },
+  "MEDIA_EME_SECURE_CONTEXT": {
+    "alert_emails": ["cpearce@mozilla.com"],
+    "expires_in_version": "60",
+    "kind": "boolean",
+    "description": "Reports whether a navigator.requestMediaKeySystemAccess() was called in a secure context (i.e. on an origin served over HTTPS) or not.",
+    "bug_numbers": [1360438]
+  },
   "VIDEO_MFT_OUTPUT_NULL_SAMPLES": {
     "alert_emails": ["cpearce@mozilla.com"],
     "expires_in_version": "53",
     "kind": "enumerated",
     "n_values": 10,
     "description": "Does the WMF video decoder return success but null output? 0 = playback successful, 1 = excessive null output but able to decode some frames, 2 = excessive null output and gave up, 3 = null output but recovered, 4 = non-excessive null output without being able to decode frames.",
     "bug_numbers": [1176071]
   },
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -2491,16 +2491,55 @@ extends="chrome://global/content/binding
               url: params,
             }
           }
 
           return action;
         ]]></body>
       </method>
     </implementation>
+
+    <handlers>
+      <!--
+        This overrides listitem's mousedown handler because we want to set the
+        selected item even when the shift or accel keys are pressed.
+      -->
+      <handler event="mousedown"><![CDATA[
+        // Call this.control only once since it's not a simple getter.
+        let control = this.control;
+        if (!control || control.disabled) {
+          return;
+        }
+        if (!this.selected) {
+          control.selectItem(this);
+        }
+        control.currentItem = this;
+      ]]></handler>
+
+      <handler event="mouseover"><![CDATA[
+        // The point of implementing this handler is to allow drags to change
+        // the selected item.  If the user mouses down on an item, it becomes
+        // selected.  If they then drag the mouse to another item, select it.
+        // Handle all three primary mouse buttons: right, left, and wheel, since
+        // all three change the selection on mousedown.
+        let mouseDown = event.buttons & 0b111;
+        if (!mouseDown) {
+          return;
+        }
+        // Call this.control only once since it's not a simple getter.
+        let control = this.control;
+        if (!control || control.disabled) {
+          return;
+        }
+        if (!this.selected) {
+          control.selectItem(this);
+        }
+        control.currentItem = this;
+      ]]></handler>
+    </handlers>
   </binding>
 
   <binding id="autocomplete-tree" extends="chrome://global/content/bindings/tree.xml#tree">
     <content>
       <children includes="treecols"/>
       <xul:treerows class="autocomplete-treerows tree-rows" xbl:inherits="hidescrollbar" flex="1">
         <children/>
       </xul:treerows>
--- a/toolkit/content/widgets/remote-browser.xml
+++ b/toolkit/content/widgets/remote-browser.xml
@@ -297,16 +297,23 @@
           });
         ]]>
         </body>
       </method>
 
       <method name="permitUnload">
         <body>
         <![CDATA[
+          let { frameLoader } = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
+          let tabParent = frameLoader.tabParent;
+
+          if (!tabParent.hasBeforeUnload) {
+            return { permitUnload: true, timedOut: false };
+          }
+
           const kTimeout = 5000;
 
           let finished = false;
           let responded = false;
           let permitUnload;
           let id = this._permitUnloadId++;
           let mm = this.messageManager;
           let Services = Components.utils.import("resource://gre/modules/Services.jsm", {}).Services;