merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 05 Apr 2016 16:51:53 +0200
changeset 347760 17a0ded9bb99c05c25729c306b91771483109067
parent 347708 f0110e77e9f7b40ba80b3640ea7cd038398b8eee (current diff)
parent 347759 9b307318175cf1864f30a5d31e6494fb356a7c45 (diff)
child 347761 64b5b5ae0c8d95e774c9d90ac4daea231c94ad65
child 347773 98a2f0b4690a92095f16295bbfa976572bd2a25c
child 347790 3eab512a3623dd34bed09af80abd27f6e4399225
child 347800 8f95a9cf394d0f4c888b1b5385308f02d3554bc5
child 347802 5e9deab3e66f8fec68704fe695726fc74993d51e
child 347804 57fae266bb52b23bdd8e715564f5d418b0f18497
child 347805 92bd23624ec78edf7ff4f4314e0974a629b8a851
child 347815 6be96fec76e394fd7b20ce48631fc4ae81101390
child 347817 a9fe8d39cea0c098b22264b6cfe4480db36b5a6f
child 347818 b5dc2e7fed5711d604f82d38e8cc2c317839462c
child 347831 6ececf99646cfc793d97135a4b01c4c6833f4bf9
child 347840 e563995cdc5dcc908a55b776f8d1a8ed4b190332
child 347846 d740790c015dba28b64b39c947b38a07b61cf6dc
child 347901 a235bfcc8c411169b82420c503775c1a3e7edad5
child 347990 0ae85e2b5a1470e61724a050d44492e62f4e396a
child 348191 e5a54ebba7785136d4af3d19096b8a6567731830
child 348536 9673a94b75c7c6e282b9dff6881ffebfb3b59718
child 348661 f54bd1df298f15fdff4211952b0cfc524d23dd0b
child 348952 1ab97ec1674f3e39554b5c277df1eb50120883a6
push id14653
push userolivier@olivieryiptong.com
push dateTue, 05 Apr 2016 19:21:01 +0000
reviewersmerge
milestone48.0a1
merge mozilla-inbound to mozilla-central a=merge
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -2514,30 +2514,16 @@ Accessible::LastRelease()
     NS_ASSERTION(!mDoc,
                  "A Shutdown() impl forgot to call its parent's Shutdown?");
   }
   // ... then die.
   delete this;
 }
 
 void
-Accessible::CacheChildren()
-{
-  NS_ENSURE_TRUE_VOID(Document());
-
-  AutoTreeMutation mt(this);
-  TreeWalker walker(this);
-  Accessible* child = nullptr;
-  while ((child = walker.Next()) && AppendChild(child)) {
-    mt.AfterInsertion(child);
-  }
-  mt.Done();
-}
-
-void
 Accessible::TestChildCache(Accessible* aCachedChild) const
 {
 #ifdef DEBUG
   int32_t childCount = mChildren.Length();
   if (childCount == 0) {
     NS_ASSERTION(IsChildrenFlag(eChildrenUninitialized),
                  "No children but initialized!");
     return;
@@ -2550,31 +2536,16 @@ Accessible::TestChildCache(Accessible* a
       break;
   }
 
   NS_ASSERTION(child == aCachedChild,
                "[TestChildCache] cached accessible wasn't found. Wrong accessible tree!");
 #endif
 }
 
-void
-Accessible::EnsureChildren()
-{
-  NS_ASSERTION(!IsDefunct(), "Caching children for defunct accessible!");
-
-  if (!IsChildrenFlag(eChildrenUninitialized))
-    return;
-
-  // State is embedded children until text leaf accessible is appended.
-  SetChildrenFlag(eEmbeddedChildren); // Prevent reentry
-  if (KidsFromDOM()) {
-    CacheChildren();
-  }
-}
-
 Accessible*
 Accessible::GetSiblingAtOffset(int32_t aOffset, nsresult* aError) const
 {
   if (!mParent || mIndexInParent == -1) {
     if (aError)
       *aError = NS_ERROR_UNEXPECTED;
 
     return nullptr;
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -371,21 +371,16 @@ public:
 
   /**
    * Set the ARIA role map entry for a new accessible.
    */
   void SetRoleMapEntry(const nsRoleMapEntry* aRoleMapEntry)
     { mRoleMapEntry = aRoleMapEntry; }
 
   /**
-   * Cache children if necessary.
-   */
-  void EnsureChildren();
-
-  /**
    * Append/insert/remove a child. Return true if operation was successful.
    */
   bool AppendChild(Accessible* aChild)
     { return InsertChildAt(mChildren.Length(), aChild); }
   virtual bool InsertChildAt(uint32_t aIndex, Accessible* aChild);
 
   bool InsertAfter(Accessible* aNewChild, Accessible* aRefChild)
   {
@@ -979,21 +974,16 @@ protected:
   // Initializing, cache and tree traverse methods
 
   /**
    * Destroy the object.
    */
   void LastRelease();
 
   /**
-   * Cache accessible children.
-   */
-  virtual void CacheChildren();
-
-  /**
    * Set accessible parent and index in parent.
    */
   void BindToParent(Accessible* aParent, uint32_t aIndexInParent);
   void UnbindFromParent();
 
   /**
    * Return sibling accessible at the given offset.
    */
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -1901,16 +1901,26 @@ HyperTextAccessible::RemoveChild(Accessi
   int32_t childIndex = aAccessible->IndexInParent();
   int32_t count = mOffsets.Length() - childIndex;
   if (count > 0)
     mOffsets.RemoveElementsAt(childIndex, count);
 
   return Accessible::RemoveChild(aAccessible);
 }
 
+bool
+HyperTextAccessible::InsertChildAt(uint32_t aIndex, Accessible* aChild)
+{
+  int32_t count = mOffsets.Length() - aIndex;
+  if (count > 0 ) {
+    mOffsets.RemoveElementsAt(aIndex, count);
+  }
+  return Accessible::InsertChildAt(aIndex, aChild);
+}
+
 Relation
 HyperTextAccessible::RelationByType(RelationType aType)
 {
   Relation rel = Accessible::RelationByType(aType);
 
   switch (aType) {
     case RelationType::NODE_CHILD_OF:
       if (HasOwnContent() && mContent->IsMathMLElement()) {
--- a/accessible/generic/HyperTextAccessible.h
+++ b/accessible/generic/HyperTextAccessible.h
@@ -57,16 +57,17 @@ public:
   virtual nsIAtom* LandmarkRole() const override;
   virtual int32_t GetLevelInternal() override;
   virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
   virtual mozilla::a11y::role NativeRole() override;
   virtual uint64_t NativeState() override;
 
   virtual void Shutdown() override;
   virtual bool RemoveChild(Accessible* aAccessible) override;
+  virtual bool InsertChildAt(uint32_t aIndex, Accessible* aChild) override;
   virtual Relation RelationByType(RelationType aType) override;
 
   // HyperTextAccessible (static helper method)
 
   // Convert content offset to rendered text offset
   nsresult ContentToRenderedOffset(nsIFrame *aFrame, int32_t aContentOffset,
                                    uint32_t *aRenderedOffset) const;
 
--- a/accessible/html/HTMLListAccessible.cpp
+++ b/accessible/html/HTMLListAccessible.cpp
@@ -126,29 +126,16 @@ HTMLLIAccessible::UpdateBullet(bool aHas
     mBullet = nullptr;
   }
   mt.Done();
 
   mDoc->FireDelayedEvent(reorderEvent);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// HTMLLIAccessible: Accessible protected
-
-void
-HTMLLIAccessible::CacheChildren()
-{
-  if (mBullet)
-    AppendChild(mBullet);
-
-  // Cache children from subtree.
-  AccessibleWrap::CacheChildren();
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // HTMLListBulletAccessible
 ////////////////////////////////////////////////////////////////////////////////
 HTMLListBulletAccessible::
   HTMLListBulletAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   LeafAccessible(aContent, aDoc)
 {
   mStateFlags |= eSharedNode;
 }
--- a/accessible/html/HTMLListAccessible.h
+++ b/accessible/html/HTMLListAccessible.h
@@ -55,19 +55,16 @@ public:
 
   // HTMLLIAccessible
   HTMLListBulletAccessible* Bullet() const { return mBullet; }
   void UpdateBullet(bool aHasBullet);
 
 protected:
   virtual ~HTMLLIAccessible() { }
 
-  // Accessible
-  virtual void CacheChildren() override;
-
 private:
   RefPtr<HTMLListBulletAccessible> mBullet;
 };
 
 
 /**
  * Used for bullet of HTML list item element (for example, HTML li).
  */
--- a/accessible/html/HTMLTableAccessible.cpp
+++ b/accessible/html/HTMLTableAccessible.cpp
@@ -907,17 +907,17 @@ HTMLTableAccessible::HasDescendant(const
     return true;
 
   // If we found more than one node then return true not depending on
   // aAllowEmpty flag.
   // XXX it might be dummy but bug 501375 where we changed this addresses
   // performance problems only. Note, currently 'aAllowEmpty' flag is used for
   // caption element only. On another hand we create accessible object for
   // the first entry of caption element (see
-  // HTMLTableAccessible::CacheChildren).
+  // HTMLTableAccessible::InsertChildAt).
   return !!elements->Item(1);
 }
 
 bool
 HTMLTableAccessible::IsProbablyLayoutTable()
 {
   // Implement a heuristic to determine if table is most likely used for layout
   // XXX do we want to look for rowspan or colspan, especialy that span all but a couple cells
--- a/accessible/tests/mochitest/text/a11y.ini
+++ b/accessible/tests/mochitest/text/a11y.ini
@@ -1,15 +1,16 @@
 [DEFAULT]
 support-files = doc.html
   !/accessible/tests/mochitest/*.js
 
 [test_atcaretoffset.html]
 [test_charboundary.html]
 [test_doc.html]
+[test_dynamic.html]
 [test_general.xul]
 [test_gettext.html]
 [test_hypertext.html]
 [test_lineboundary.html]
 [test_passwords.html]
 [test_selection.html]
 [test_wordboundary.html]
 [test_words.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/text/test_dynamic.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>nsIAccessibleText getText related function tests for tree mutations</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../text.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+    function insertBefore(aId, aEl, aTextBefore, aTextAfter, aStartIdx, aEndIdx)
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, aId)
+      ];
+
+      this.invoke = function insertBefore_invoke()
+      {
+        testText(aId, 0, -1, aTextBefore);
+        getNode(aId).insertBefore(aEl, getNode(aId).firstChild);
+      }
+
+      this.finalCheck = function insertBefore_finalCheck()
+      {
+        testText(aId, aStartIdx, aEndIdx, aTextAfter);
+      }
+
+      this.getID = function insertTextBefore_getID() {
+        return "insert " + prettyName(aEl) + " before";
+      }
+    }
+
+    function insertTextBefore(aId, aTextBefore, aText)
+    {
+      var el = document.createTextNode(aText);
+      this.__proto__ = new insertBefore(aId, el, aTextBefore,
+                                        aText + aTextBefore, 0, -1)
+    }
+
+    function insertImgBefore(aId, aTextBefore)
+    {
+      var el = document.createElement("img");
+      el.setAttribute("src", "../moz.png");
+      el.setAttribute("alt", "mozilla");
+
+      this.__proto__ = new insertBefore(aId, el, aTextBefore,
+                                        kEmbedChar + aTextBefore, 0, -1)
+    }
+
+    function insertTextBefore2(aId)
+    {
+      var el = document.createTextNode("hehe");
+      this.__proto__ = new insertBefore(aId, el, "ho", "ho", 4, -1)
+    }
+
+    var gQueue = null;
+    function doTest()
+    {
+      gQueue = new eventQueue();
+      gQueue.push(new insertTextBefore("c1", "ho", "ha"));
+      gQueue.push(new insertImgBefore("c1", "haho"));
+      gQueue.push(new insertImgBefore("c2", kEmbedChar));
+      gQueue.push(new insertTextBefore2("c3"));
+      gQueue.invoke(); // will call SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="c1">ho</div>
+  <div id="c2"><img src="../moz.png" alt="mozilla"></div>
+  <div id="c3">ho</div>
+</body>
+</html>
--- a/accessible/xul/XULElementAccessibles.cpp
+++ b/accessible/xul/XULElementAccessibles.cpp
@@ -116,28 +116,16 @@ XULLabelAccessible::UpdateLabelValue(con
                       NS_ConvertUTF16toUTF8(aValue).get());
     logging::MsgEnd();
   }
 #endif
 
   TextUpdater::Run(mDoc, mValueTextLeaf, aValue);
 }
 
-void
-XULLabelAccessible::CacheChildren()
-{
-  if (mValueTextLeaf) {
-    AppendChild(mValueTextLeaf);
-    return;
-  }
-
-  // Cache children from subtree.
-  AccessibleWrap::CacheChildren();
-}
-
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULLabelTextLeafAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 role
 XULLabelTextLeafAccessible::NativeRole()
 {
--- a/accessible/xul/XULElementAccessibles.h
+++ b/accessible/xul/XULElementAccessibles.h
@@ -28,17 +28,16 @@ public:
   virtual uint64_t NativeState() override;
   virtual Relation RelationByType(RelationType aType) override;
 
   void UpdateLabelValue(const nsString& aValue);
 
 protected:
   // Accessible
   virtual ENameValueFlag NativeName(nsString& aName) override;
-  virtual void CacheChildren() override;
 
 private:
   RefPtr<XULLabelTextLeafAccessible> mValueTextLeaf;
 };
 
 inline XULLabelAccessible*
 Accessible::AsXULLabel()
 {
--- a/browser/base/content/abouthome/aboutHome.js
+++ b/browser/base/content/abouthome/aboutHome.js
@@ -22,30 +22,35 @@ const DATABASE_VERSION = 1;
 const DATABASE_STORAGE = "persistent";
 const SNIPPETS_OBJECTSTORE_NAME = "snippets";
 var searchText;
 
 // This global tracks if the page has been set up before, to prevent double inits
 var gInitialized = false;
 var gObserver = new MutationObserver(function (mutations) {
   for (let mutation of mutations) {
+    // The addition of the restore session button changes our width:
+    if (mutation.attributeName == "session") {
+      fitToWidth();
+    }
     if (mutation.attributeName == "snippetsVersion") {
       if (!gInitialized) {
         ensureSnippetsMapThen(loadSnippets);
         gInitialized = true;
       }
       return;
     }
   }
 });
 
 window.addEventListener("pageshow", function () {
   // Delay search engine setup, cause browser.js::BrowserOnAboutPageLoad runs
   // later and may use asynchronous getters.
   window.gObserver.observe(document.documentElement, { attributes: true });
+  window.gObserver.observe(document.getElementById("launcher"), { attributes: true });
   fitToWidth();
   setupSearch();
   window.addEventListener("resize", fitToWidth);
 
   // Ask chrome to update snippets.
   var event = new CustomEvent("AboutHomeLoad", {bubbles:true});
   document.dispatchEvent(event);
 });
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -560,16 +560,24 @@ var FullScreen = {
   hideNavToolbox: function (aAnimate = false) {
     if (this._isChromeCollapsed || !this._safeToCollapse())
       return;
 
     this._fullScrToggler.hidden = false;
 
     if (aAnimate && gPrefService.getBoolPref("browser.fullscreen.animate")) {
       gNavToolbox.setAttribute("fullscreenShouldAnimate", true);
+      // Hide the fullscreen toggler until the transition ends.
+      let listener = () => {
+        gNavToolbox.removeEventListener("transitionend", listener, true);
+        if (this._isChromeCollapsed)
+          this._fullScrToggler.hidden = false;
+      };
+      gNavToolbox.addEventListener("transitionend", listener, true);
+      this._fullScrToggler.hidden = true;
     }
 
     gNavToolbox.style.marginTop =
       -gNavToolbox.getBoundingClientRect().height + "px";
     this._isChromeCollapsed = true;
     MousePosTracker.removeListener(this);
   },
 
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -658,22 +658,18 @@ window[chromehidden~="toolbar"] toolbar:
 
 #historySwipeAnimationNextPage {
   background-image: -moz-element(#historySwipeAnimationNextPageSnapshot);
 }
 
 /*  Full Screen UI */
 
 #fullscr-toggler {
-  top: 0;
-  left: 0;
-  width: 100%;
   height: 1px;
-  position: fixed;
-  z-index: 2147483647;
+  background: black;
 }
 
 html|*#fullscreen-warning {
   position: fixed;
   z-index: 2147483647 !important;
   visibility: visible;
   transition: transform 300ms ease-in;
   /* To center the warning box horizontally,
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1043,16 +1043,18 @@
       <toolbarbutton id="fullscreen-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      observes="View:FullScreen"
                      type="checkbox"
                      label="&fullScreenCmd.label;"
                      tooltip="dynamic-shortcut-tooltip"/>
     </toolbarpalette>
   </toolbox>
 
+  <hbox id="fullscr-toggler" hidden="true"/>
+
   <deck id="content-deck" flex="1">
     <hbox flex="1" id="browser">
       <vbox id="browser-border-start" hidden="true" layer="true"/>
       <vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">
         <sidebarheader id="sidebar-header" align="center">
           <label id="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/>
           <image id="sidebar-throbber"/>
           <toolbarbutton class="close-icon tabbable" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="SidebarUI.hide();"/>
@@ -1166,12 +1168,9 @@
   </svg:svg>
 
 </vbox>
 # <iframe id="tab-view"> is dynamically appended as the 2nd child of #tab-view-deck.
 #     Introducing the iframe dynamically, as needed, was found to be better than
 #     starting with an empty iframe here in browser.xul from a Ts standpoint.
 </deck>
 
-# Put it at the very end to make sure it is not covered by anything.
-<hbox id="fullscr-toggler" hidden="true"/>
-
 </window>
--- a/browser/extensions/loop/run-all-loop-tests.sh
+++ b/browser/extensions/loop/run-all-loop-tests.sh
@@ -32,17 +32,17 @@ TESTS="
   browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
   browser/base/content/test/general/browser_parsable_css.js
 "
 
 # Due to bug 1209463, we need to split these up and run them individually to
 # ensure we stop and report that there's an error.
 for test in $TESTS
 do
-  ./mach mochitest $test
+  ./mach mochitest --disable-e10s $test
   # UITour & get user media aren't compatible with e10s currenly.
   if [ "$1" != "--skip-e10s" ] && \
      [ "$test" != "browser/components/uitour/test/browser_UITour_loop.js" ] && \
      [ "$test" != "browser/base/content/test/general/browser_devices_get_user_media_about_urls.js" ];
   then
-    ./mach mochitest --e10s $test
+    ./mach mochitest $test
   fi
 done
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -625,19 +625,18 @@ WebGLFramebuffer::FramebufferTexture2D(G
 
     if (tex) {
         if (!tex->HasEverBeenBound()) {
             mContext->ErrorInvalidOperation("framebufferTexture2D: the texture"
                                             " is not the name of a texture.");
             return;
         }
 
-        bool isTexture2D = tex->Target() == LOCAL_GL_TEXTURE_2D;
-        bool isTexTarget2D = texImageTarget == LOCAL_GL_TEXTURE_2D;
-        if (isTexture2D != isTexTarget2D) {
+        const TexTarget destTexTarget = TexImageTargetToTexTarget(texImageTarget);
+        if (tex->Target() != destTexTarget) {
             mContext->ErrorInvalidOperation("framebufferTexture2D: Mismatched"
                                             " texture and texture target.");
             return;
         }
     }
 
     RefPtr<WebGLTexture> tex_ = tex; // Bug 1201275
     const auto fnAttach = [this, &tex_, texImageTarget, level](GLenum attachment) {
--- a/dom/html/VideoDocument.cpp
+++ b/dom/html/VideoDocument.cpp
@@ -28,18 +28,17 @@ public:
                                      nsIContentSink*     aSink = nullptr);
   virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject);
 
 protected:
 
   // Sets document <title> to reflect the file name and description.
   void UpdateTitle(nsIChannel* aChannel);
 
-  nsresult CreateSyntheticVideoDocument(nsIChannel* aChannel,
-                                        nsIStreamListener** aListener);
+  nsresult CreateSyntheticVideoDocument();
 
   RefPtr<MediaDocumentStreamListener> mStreamListener;
 };
 
 nsresult
 VideoDocument::StartDocumentLoad(const char*         aCommand,
                                  nsIChannel*         aChannel,
                                  nsILoadGroup*       aLoadGroup,
@@ -49,47 +48,49 @@ VideoDocument::StartDocumentLoad(const c
                                  nsIContentSink*     aSink)
 {
   nsresult rv =
     MediaDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer,
                                      aDocListener, aReset, aSink);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mStreamListener = new MediaDocumentStreamListener(this);
-
-  // Create synthetic document
-  rv = CreateSyntheticVideoDocument(aChannel,
-      getter_AddRefs(mStreamListener->mNextStream));
-  NS_ENSURE_SUCCESS(rv, rv);
-
   NS_ADDREF(*aDocListener = mStreamListener);
   return rv;
 }
 
 void
 VideoDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
 {
   // Set the script global object on the superclass before doing
   // anything that might require it....
   MediaDocument::SetScriptGlobalObject(aScriptGlobalObject);
 
   if (aScriptGlobalObject) {
+    if (!GetRootElement()) {
+      // Create synthetic document
+#ifdef DEBUG
+      nsresult rv =
+#endif
+        CreateSyntheticVideoDocument();
+      NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic video document");
+    }
+
     if (!nsContentUtils::IsChildOfSameType(this) &&
         GetReadyStateEnum() != nsIDocument::READYSTATE_COMPLETE) {
       LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelVideoDocument.css"));
       LinkStylesheet(NS_LITERAL_STRING("chrome://global/skin/media/TopLevelVideoDocument.css"));
       LinkScript(NS_LITERAL_STRING("chrome://global/content/TopLevelVideoDocument.js"));
     }
     BecomeInteractive();
   }
 }
 
 nsresult
-VideoDocument::CreateSyntheticVideoDocument(nsIChannel* aChannel,
-                                            nsIStreamListener** aListener)
+VideoDocument::CreateSyntheticVideoDocument()
 {
   // make our generic document
   nsresult rv = MediaDocument::CreateSyntheticDocument();
   NS_ENSURE_SUCCESS(rv, rv);
 
   Element* body = GetBodyElement();
   if (!body) {
     NS_WARNING("no body on video document!");
@@ -104,18 +105,19 @@ VideoDocument::CreateSyntheticVideoDocum
 
   RefPtr<HTMLMediaElement> element =
     static_cast<HTMLMediaElement*>(NS_NewHTMLVideoElement(nodeInfo.forget(),
                                                           NOT_FROM_PARSER));
   if (!element)
     return NS_ERROR_OUT_OF_MEMORY;
   element->SetAutoplay(true);
   element->SetControls(true);
-  element->LoadWithChannel(aChannel, aListener);
-  UpdateTitle(aChannel);
+  element->LoadWithChannel(mChannel,
+                           getter_AddRefs(mStreamListener->mNextStream));
+  UpdateTitle(mChannel);
 
   if (nsContentUtils::IsChildOfSameType(this)) {
     // Video documents that aren't toplevel should fill their frames and
     // not have margins
     element->SetAttr(kNameSpaceID_None, nsGkAtoms::style,
         NS_LITERAL_STRING("position:absolute; top:0; left:0; width:100%; height:100%"),
         true);
   }
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1196,19 +1196,21 @@ ContentParent::CreateBrowserOrApp(const 
         // DeallocPBrowserParent() releases this ref.
         tp.forget().take(), tabId,
         aContext.AsIPCTabContext(),
         chromeFlags,
         constructorSender->ChildID(),
         constructorSender->IsForApp(),
         constructorSender->IsForBrowser());
 
-      RefPtr<TabParent> constructedTabParent = TabParent::GetFrom(browser);
-      constructedTabParent->SetOwnerElement(aFrameElement);
-      return constructedTabParent;
+      if (browser) {
+        RefPtr<TabParent> constructedTabParent = TabParent::GetFrom(browser);
+        constructedTabParent->SetOwnerElement(aFrameElement);
+        return constructedTabParent;
+      }
     }
     return nullptr;
   }
 
   // If we got here, we have an app and we're not a browser element.  ownApp
   // shouldn't be null, because we otherwise would have gone into the
   // !HasOwnApp() branch above.
   RefPtr<nsIContentParent> parent;
--- a/gfx/2d/convolver.cpp
+++ b/gfx/2d/convolver.cpp
@@ -317,23 +317,23 @@ void ConvolveVertically(const Convolutio
 }
 
 void ConvolveHorizontally(const unsigned char* src_data,
                           const ConvolutionFilter1D& filter,
                           unsigned char* out_row,
                           bool has_alpha, bool use_simd) {
   int width = filter.num_values();
   int processed = 0;
-#if defined(USE_SSE2)
+#if defined(USE_SSE2) || defined(_MIPS_ARCH_LOONGSON3A)
   int simd_width = width & ~3;
   if (use_simd && simd_width) {
     // SIMD implementation works with 4 pixels at a time.
     // Therefore we process as much as we can using SSE and then use
     // C implementation for leftovers
-    ConvolveHorizontally_SSE2(src_data, filter, out_row);
+    ConvolveHorizontally_SIMD(src_data, filter, out_row);
     processed = simd_width;
   }
 #endif
 
   if (width > processed) {
     if (has_alpha) {
       ConvolveHorizontally<true>(src_data, filter, out_row);
     } else {
--- a/gfx/2d/convolverLS3.cpp
+++ b/gfx/2d/convolverLS3.cpp
@@ -94,17 +94,18 @@ void ConvolveHorizontally_LS3(const unsi
       double src16h, src16l, mul_hih, mul_hil, mul_loh, mul_lol;
       double coeffh, coeffl, src8h, src8l, th, tl, coeff16h, coeff16l;
 
       asm volatile (
         ".set push \n\t"
         ".set arch=loongson3a \n\t"
         // Load 4 coefficients => duplicate 1st and 2nd of them for all channels.
         // [16] xx xx xx xx c3 c2 c1 c0
-        "ldc1 %[coeffl], (%[fval]) \n\t"
+        "gsldlc1 %[coeffl], 7(%[fval]) \n\t"
+        "gsldrc1 %[coeffl], (%[fval]) \n\t"
         "xor %[coeffh], %[coeffh], %[coeffh] \n\t"
         // [16] xx xx xx xx c1 c1 c0 c0
         _mm_pshuflh(coeff16, coeff, shuf_50)
         // [16] c1 c1 c1 c1 c0 c0 c0 c0
         _mm_punpcklhw(coeff16, coeff16, coeff16)
         // Load four pixels => unpack the first two pixels to 16 bits =>
         // multiply with coefficients => accumulate the convolution result.
         // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0
@@ -165,17 +166,18 @@ void ConvolveHorizontally_LS3(const unsi
     int r = filter_length & 3;
     if (r) {
       double coeffh, coeffl, th, tl, coeff16h, coeff16l;
       double src8h, src8l, src16h, src16l, mul_hih, mul_hil, mul_loh, mul_lol;
 
       asm volatile (
         ".set push \n\t"
         ".set arch=loongson3a \n\t"
-        "ldc1 %[coeffl], (%[fval]) \n\t"
+        "gsldlc1 %[coeffl], 7(%[fval]) \n\t"
+        "gsldrc1 %[coeffl], (%[fval]) \n\t"
         "xor %[coeffh], %[coeffh], %[coeffh] \n\t"
         // Mask out extra filter taps.
         "and %[coeffl], %[coeffl], %[mask] \n\t"
         _mm_pshuflh(coeff16, coeff, shuf_50)
         _mm_punpcklhw(coeff16, coeff16, coeff16)
         "gsldlc1 %[src8h], 0xf(%[rtf]) \n\t"
         "gsldrc1 %[src8h], 0x8(%[rtf]) \n\t"
         "gsldlc1 %[src8l], 0x7(%[rtf]) \n\t"
@@ -300,17 +302,18 @@ void ConvolveHorizontally4_LS3(const uns
       double src8h, src8l, src16h, src16l;
       double mul_hih, mul_hil, mul_loh, mul_lol, th, tl;
       double coeffh, coeffl, coeff16loh, coeff16lol, coeff16hih, coeff16hil;
 
       asm volatile (
         ".set push \n\t"
         ".set arch=loongson3a \n\t"
         // [16] xx xx xx xx c3 c2 c1 c0
-        "ldc1 %[coeffl], (%[fval]) \n\t"
+        "gsldlc1 %[coeffl], 7(%[fval]) \n\t"
+        "gsldrc1 %[coeffl], (%[fval]) \n\t"
         "xor %[coeffh], %[coeffh], %[coeffh] \n\t"
         // [16] xx xx xx xx c1 c1 c0 c0
         _mm_pshuflh(coeff16lo, coeff, shuf_50)
         // [16] c1 c1 c1 c1 c0 c0 c0 c0
         _mm_punpcklhw(coeff16lo, coeff16lo, coeff16lo)
         // [16] xx xx xx xx c3 c3 c2 c2
         _mm_pshuflh(coeff16hi, coeff, shuf_fa)
         // [16] c3 c3 c3 c3 c2 c2 c2 c2
@@ -369,17 +372,18 @@ void ConvolveHorizontally4_LS3(const uns
     if (r) {
       double src8h, src8l, src16h, src16l;
       double mul_hih, mul_hil, mul_loh, mul_lol, th, tl;
       double coeffh, coeffl, coeff16loh, coeff16lol, coeff16hih, coeff16hil;
 
       asm volatile (
         ".set push \n\t"
         ".set arch=loongson3a \n\t"
-        "ldc1 %[coeffl], (%[fval]) \n\t"
+        "gsldlc1 %[coeffl], 7(%[fval]) \n\t"
+        "gsldrc1 %[coeffl], (%[fval]) \n\t"
         "xor %[coeffh], %[coeffh], %[coeffh] \n\t"
         // Mask out extra filter taps.
         "and %[coeffl], %[coeffl], %[mask] \n\t"
         _mm_pshuflh(coeff16lo, coeff, shuf_50)
         /* c1 c1 c1 c1 c0 c0 c0 c0 */
         _mm_punpcklhw(coeff16lo, coeff16lo, coeff16lo)
         _mm_pshuflh(coeff16hi, coeff, shuf_fa)
         _mm_punpcklhw(coeff16hi, coeff16hi, coeff16hi)
@@ -495,17 +499,18 @@ void ConvolveVertically_LS3_impl(const C
       src = reinterpret_cast<const void*>(
           &source_data_rows[filter_y][out_x << 2]);
 
       asm volatile (
         ".set push \n\t"
         ".set arch=loongson3a \n\t"
         // Duplicate the filter coefficient 8 times.
         // [16] cj cj cj cj cj cj cj cj
-        "mtc1 %[fval], %[coeff16l] \n\t"
+        "gsldlc1 %[coeff16l], 7+%[fval] \n\t"
+        "gsldrc1 %[coeff16l], %[fval] \n\t"
         "pshufh %[coeff16l], %[coeff16l], %[zerol] \n\t"
         "mov.d %[coeff16h], %[coeff16l] \n\t"
         // Load four pixels (16 bytes) together.
         // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0
         "gsldlc1 %[src8h], 0xf(%[src]) \n\t"
         "gsldrc1 %[src8h], 0x8(%[src]) \n\t"
         "gsldlc1 %[src8l], 0x7(%[src]) \n\t"
         "gsldrc1 %[src8l], 0x0(%[src]) \n\t"
@@ -532,17 +537,17 @@ void ConvolveVertically_LS3_impl(const C
          [src8h]"=&f"(src8h), [src8l]"=&f"(src8l),
          [src16h]"=&f"(src16h), [src16l]"=&f"(src16l),
          [mul_hih]"=&f"(mul_hih), [mul_hil]"=&f"(mul_hil),
          [mul_loh]"=&f"(mul_loh), [mul_lol]"=&f"(mul_lol),
          [accum0h]"+f"(accum0h), [accum0l]"+f"(accum0l),
          [accum1h]"+f"(accum1h), [accum1l]"+f"(accum1l),
          [coeff16h]"=&f"(coeff16h), [coeff16l]"=&f"(coeff16l)
         :[zeroh]"f"(zero), [zerol]"f"(zero),
-         [fval]"r"(filter_values[filter_y]),
+         [fval]"m"(filter_values[filter_y]),
          [src]"r"(src)
       );
 
       asm volatile (
         ".set push \n\t"
         ".set arch=loongson3a \n\t"
         // [32] a2 b2 g2 r2
         _mm_punpcklhw(t, mul_lo, mul_hi)
@@ -670,17 +675,18 @@ void ConvolveVertically_LS3_impl(const C
       double src8h, src8l, src16h, src16l;
       double th, tl, mul_hih, mul_hil, mul_loh, mul_lol;
       src = reinterpret_cast<const void*>(
           &source_data_rows[filter_y][out_x<<2]);
 
       asm volatile (
         ".set push \n\t"
         ".set arch=loongson3a \n\t"
-        "mtc1 %[fval], %[coeff16l] \n\t"
+        "gsldlc1 %[coeff16l], 7+%[fval] \n\t"
+        "gsldrc1 %[coeff16l], %[fval] \n\t"
         "pshufh %[coeff16l], %[coeff16l], %[zerol] \n\t"
         "mov.d %[coeff16h], %[coeff16l] \n\t"
         // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0
         "gsldlc1 %[src8h], 0xf(%[src]) \n\t"
         "gsldrc1 %[src8h], 0x8(%[src]) \n\t"
         "gsldlc1 %[src8l], 0x7(%[src]) \n\t"
         "gsldrc1 %[src8l], 0x0(%[src]) \n\t"
         // [16] a1 b1 g1 r1 a0 b0 g0 r0
@@ -706,17 +712,17 @@ void ConvolveVertically_LS3_impl(const C
          [src16h]"=&f"(src16h), [src16l]"=&f"(src16l),
          [mul_hih]"=&f"(mul_hih), [mul_hil]"=&f"(mul_hil),
          [mul_loh]"=&f"(mul_loh), [mul_lol]"=&f"(mul_lol),
          [accum0h]"+f"(accum0h), [accum0l]"+f"(accum0l),
          [accum1h]"+f"(accum1h), [accum1l]"+f"(accum1l),
          [accum2h]"+f"(accum2h), [accum2l]"+f"(accum2l),
          [coeff16h]"=&f"(coeff16h), [coeff16l]"=&f"(coeff16l)
         :[zeroh]"f"(zero), [zerol]"f"(zero),
-         [fval]"r"(filter_values[filter_y]),
+         [fval]"m"(filter_values[filter_y]),
          [src]"r"(src)
       );
     }
 
     double t;
     asm volatile (
       ".set push \n\t"
       ".set arch=loongson3a \n\t"
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -366,17 +366,17 @@ public:
    * is returned empty, composition should be aborted.
    *
    * If aOpaque is true, then all of aInvalidRegion will be drawn to with
    * opaque content.
    */
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect* aClipRectIn,
                           const gfx::Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           gfx::Rect* aClipRectOut = nullptr,
                           gfx::Rect* aRenderBoundsOut = nullptr) = 0;
 
   /**
    * Flush the current frame to the screen and tidy up.
    */
   virtual void EndFrame() = 0;
 
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -155,43 +155,44 @@ BasicCompositor::CreateRenderTargetFromS
                                               const CompositingRenderTarget *aSource,
                                               const IntPoint &aSourcePoint)
 {
   MOZ_CRASH("GFX: Shouldn't be called!");
   return nullptr;
 }
 
 already_AddRefed<CompositingRenderTarget>
-BasicCompositor::CreateRenderTargetForWindow(const LayoutDeviceIntRect& aRect, SurfaceInitMode aInit, BufferMode aBufferMode)
+BasicCompositor::CreateRenderTargetForWindow(const LayoutDeviceIntRect& aRect, const LayoutDeviceIntRect& aClearRect, BufferMode aBufferMode)
 {
   MOZ_ASSERT(mDrawTarget);
   MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
 
   if (aRect.width * aRect.height == 0) {
     return nullptr;
   }
 
   RefPtr<BasicCompositingRenderTarget> rt;
   IntRect rect = aRect.ToUnknownRect();
 
   if (aBufferMode != BufferMode::BUFFER_NONE) {
-    RefPtr<DrawTarget> target = mWidget->CreateBackBufferDrawTarget(mDrawTarget, aRect, aInit == INIT_MODE_CLEAR);
+    RefPtr<DrawTarget> target = mWidget->CreateBackBufferDrawTarget(mDrawTarget, aRect, aClearRect);
     if (!target) {
       return nullptr;
     }
     rt = new BasicCompositingRenderTarget(target, rect);
   } else {
     IntRect windowRect = rect;
     // Adjust bounds rect to account for new origin at (0, 0).
     if (windowRect.Size() != mDrawTarget->GetSize()) {
       windowRect.ExpandToEnclose(IntPoint(0, 0));
     }
     rt = new BasicCompositingRenderTarget(mDrawTarget, windowRect);
-    if (aInit == INIT_MODE_CLEAR) {
-      mDrawTarget->ClearRect(Rect(rect - rt->GetOrigin()));
+    if (!aClearRect.IsEmpty()) {
+      IntRect clearRect = aRect.ToUnknownRect();
+      mDrawTarget->ClearRect(Rect(clearRect - rt->GetOrigin()));
     }
   }
 
   return rt.forget();
 }
 
 already_AddRefed<DataTextureSource>
 BasicCompositor::CreateDataTextureSource(TextureFlags aFlags)
@@ -469,17 +470,17 @@ BasicCompositor::ClearRect(const gfx::Re
 {
   mRenderTarget->mDrawTarget->ClearRect(aRect);
 }
 
 void
 BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
                             const gfx::Rect *aClipRectIn,
                             const gfx::Rect& aRenderBounds,
-                            bool aOpaque,
+                            const nsIntRegion& aOpaqueRegion,
                             gfx::Rect *aClipRectOut /* = nullptr */,
                             gfx::Rect *aRenderBoundsOut /* = nullptr */)
 {
   LayoutDeviceIntRect intRect(LayoutDeviceIntPoint(), mWidget->GetClientSize());
   Rect rect = Rect(0, 0, intRect.width, intRect.height);
 
   LayoutDeviceIntRegion invalidRegionSafe;
   if (mDidExternalComposition) {
@@ -517,21 +518,30 @@ BasicCompositor::BeginFrame(const nsIntR
       return;
     }
   }
 
   if (!mDrawTarget || mInvalidRect.IsEmpty()) {
     return;
   }
 
+  LayoutDeviceIntRect clearRect;
+  if (!aOpaqueRegion.IsEmpty()) {
+    LayoutDeviceIntRegion clearRegion = mInvalidRegion;
+    clearRegion.SubOut(LayoutDeviceIntRegion::FromUnknownRegion(aOpaqueRegion));
+    clearRect = clearRegion.GetBounds();
+  } else {
+    clearRect = mInvalidRect;
+  }
+
   // Setup an intermediate render target to buffer all compositing. We will
   // copy this into mDrawTarget (the widget), and/or mTarget in EndFrame()
   RefPtr<CompositingRenderTarget> target =
     CreateRenderTargetForWindow(mInvalidRect,
-                                aOpaque ? INIT_MODE_NONE : INIT_MODE_CLEAR,
+                                clearRect,
                                 bufferMode);
   if (!target) {
     if (!mTarget) {
       mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
     }
     return;
   }
   SetRenderTarget(target);
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -59,17 +59,17 @@ public:
 
   virtual already_AddRefed<CompositingRenderTarget>
   CreateRenderTargetFromSource(const gfx::IntRect &aRect,
                                const CompositingRenderTarget *aSource,
                                const gfx::IntPoint &aSourcePoint) override;
 
   virtual already_AddRefed<CompositingRenderTarget>
   CreateRenderTargetForWindow(const LayoutDeviceIntRect& aRect,
-                              SurfaceInitMode aInit,
+                              const LayoutDeviceIntRect& aClearRect,
                               BufferMode aBufferMode);
 
   virtual already_AddRefed<DataTextureSource>
   CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) override;
 
   virtual already_AddRefed<DataTextureSource>
   CreateDataTextureSourceAround(gfx::DataSourceSurface* aSurface) override;
 
@@ -92,17 +92,17 @@ public:
                         const gfx::Matrix4x4& aTransform,
                         const gfx::Rect& aVisibleRect) override;
 
   virtual void ClearRect(const gfx::Rect& aRect) override;
 
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect *aClipRectIn,
                           const gfx::Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) override;
   virtual void EndFrame() override;
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) override;
 
   virtual bool SupportsPartialTextureUpdate() override { return true; }
   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) override { return true; }
   virtual int32_t GetMaxTextureSize() const override;
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -820,16 +820,21 @@ AsyncCompositionManager::ApplyAsyncConte
   // Each layer has multiple clips. Its local clip, which must move with async
   // transforms, and its scrollframe clips, which are the clips between each
   // scrollframe and its ancestor scrollframe. Scrollframe clips include the
   // composition bounds and any other clips induced by layout.
   //
   // The final clip for the layer is the intersection of these clips.
   Maybe<ParentLayerIntRect> asyncClip = aLayer->GetClipRect();
 
+  // If we are a perspective transform ContainerLayer, apply the clip deferred
+  // from our child (if there is any) before we iterate over our frame metrics,
+  // because this clip is subject to all async transforms of this layer.
+  asyncClip = IntersectMaybeRects(asyncClip, clipDeferredFromChildren);
+
   // The transform of a mask layer is relative to the masked layer's parent
   // layer. So whenever we apply an async transform to a layer, we need to
   // apply that same transform to the layer's own mask layer.
   // A layer can also have "ancestor" mask layers for any rounded clips from
   // its ancestor scroll frames. A scroll frame mask layer only needs to be
   // async transformed for async scrolls of this scroll frame's ancestor
   // scroll frames, not for async scrolls of this scroll frame itself.
   // In the loop below, we iterate over scroll frames from inside to outside.
@@ -943,16 +948,22 @@ AsyncCompositionManager::ApplyAsyncConte
     // move with this APZC.
     if (scrollMetadata.HasClipRect()) {
       ParentLayerIntRect clip = scrollMetadata.ClipRect();
       if (aLayer->GetParent() && aLayer->GetParent()->GetTransformIsPerspective()) {
         // If our parent layer has a perspective transform, we want to apply
         // our scroll clip to it instead of to this layer (see bug 1168263).
         // A layer with a perspective transform shouldn't have multiple
         // children with FrameMetrics, nor a child with multiple FrameMetrics.
+        // (A child with multiple FrameMetrics would mean that there's *another*
+        // scrollable element between the one with the CSS perspective and the
+        // transformed element. But you'd have to use preserve-3d on the inner
+        // scrollable element in order to have the perspective apply to the
+        // transformed child, and preserve-3d is not supported on scrollable
+        // elements, so this case can't occur.)
         MOZ_ASSERT(!aClipDeferredToParent);
         aClipDeferredToParent = Some(clip);
       } else {
         asyncClip = IntersectMaybeRects(Some(clip), asyncClip);
       }
     }
 
     // Do the same for the ancestor mask layers: ancestorMaskLayers contains
@@ -967,18 +978,17 @@ AsyncCompositionManager::ApplyAsyncConte
     if (scrollMetadata.GetMaskLayerIndex()) {
       size_t maskLayerIndex = scrollMetadata.GetMaskLayerIndex().value();
       Layer* ancestorMaskLayer = aLayer->GetAncestorMaskLayerAt(maskLayerIndex);
       ancestorMaskLayers.AppendElement(ancestorMaskLayer);
     }
   }
 
   if (hasAsyncTransform || clipDeferredFromChildren) {
-    aLayer->AsLayerComposite()->SetShadowClipRect(
-        IntersectMaybeRects(asyncClip, clipDeferredFromChildren));
+    aLayer->AsLayerComposite()->SetShadowClipRect(asyncClip);
   }
 
   if (hasAsyncTransform) {
     // Apply the APZ transform on top of GetLocalTransform() here (rather than
     // GetTransform()) in case the OMTA code in SampleAnimations already set a
     // shadow transform; in that case we want to apply ours on top of that one
     // rather than clobber it.
     SetShadowTransform(aLayer,
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -477,17 +477,17 @@ LayerManagerComposite::UpdateAndRender()
   InvalidateDebugOverlay(invalid, mRenderBounds);
 
   if (!didEffectiveTransforms) {
     // The results of our drawing always go directly into a pixel buffer,
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
   }
 
-  Render(invalid);
+  Render(invalid, opaque);
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
   RenderToPresentationSurface();
 #endif
   mGeometryChanged = false;
   mWindowOverlayChanged = false;
 
   // Update cached layer tree information.
   mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
@@ -809,17 +809,17 @@ ClearLayerFlags(Layer* aLayer) {
   }
   for (Layer* child = aLayer->GetFirstChild(); child;
        child = child->GetNextSibling()) {
     ClearLayerFlags(child);
   }
 }
 
 void
-LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion)
+LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegion& aOpaqueRegion)
 {
   PROFILER_LABEL("LayerManagerComposite", "Render",
     js::ProfileEntry::Category::GRAPHICS);
 
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
@@ -895,24 +895,23 @@ LayerManagerComposite::Render(const nsIn
 
   ParentLayerIntRect clipRect;
   Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height);
   Rect actualBounds;
 
   CompositorBench(mCompositor, bounds);
 
   MOZ_ASSERT(mRoot->GetOpacity() == 1);
-  bool opaqueContent = (mRoot->GetContentFlags() & Layer::CONTENT_OPAQUE) != 0;
   if (mRoot->GetClipRect()) {
     clipRect = *mRoot->GetClipRect();
     Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
-    mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, opaqueContent, nullptr, &actualBounds);
+    mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, aOpaqueRegion, nullptr, &actualBounds);
   } else {
     gfx::Rect rect;
-    mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, opaqueContent, &rect, &actualBounds);
+    mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, aOpaqueRegion, &rect, &actualBounds);
     clipRect = ParentLayerIntRect(rect.x, rect.y, rect.width, rect.height);
   }
 
   if (actualBounds.IsEmpty()) {
     mCompositor->GetWidget()->PostRender(this);
     return;
   }
 
@@ -1156,19 +1155,17 @@ LayerManagerComposite::RenderToPresentat
   nsIntRegion opaque;
   LayerIntRegion visible;
   PostProcessLayers(mRoot, opaque, visible, Nothing());
 
   nsIntRegion invalid;
   Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight);
   Rect rect, actualBounds;
   MOZ_ASSERT(mRoot->GetOpacity() == 1);
-  bool opaqueContent = (mRoot->GetContentFlags() & Layer::CONTENT_OPAQUE) != 0;
-
-  mCompositor->BeginFrame(invalid, nullptr, bounds, opaqueContent, &rect, &actualBounds);
+  mCompositor->BeginFrame(invalid, nullptr, bounds, nsIntRegion(), &rect, &actualBounds);
 
   // The Java side of Fennec sets a scissor rect that accounts for
   // chrome such as the URL bar. Override that so that the entire frame buffer
   // is cleared.
   ScopedScissorRect scissorRect(egl, 0, 0, actualWidth, actualHeight);
   egl->fClearColor(0.0, 0.0, 0.0, 0.0);
   egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
 
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -334,17 +334,17 @@ private:
   /**
    * Update the invalid region and render it.
    */
   void UpdateAndRender();
 
   /**
    * Render the current layer tree to the active target.
    */
-  void Render(const nsIntRegion& aInvalidRegion);
+  void Render(const nsIntRegion& aInvalidRegion, const nsIntRegion& aOpaqueRegion);
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
   void RenderToPresentationSurface();
 #endif
 
   /**
    * We need to know our invalid region before we're ready to render.
    */
   void InvalidateDebugOverlay(nsIntRegion& aInvalidRegion, const gfx::IntRect& aBounds);
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -1114,17 +1114,17 @@ CompositorD3D11::DrawQuad(const gfx::Rec
     mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF);
   }
 }
 
 void
 CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
                             const Rect* aClipRectIn,
                             const Rect& aRenderBounds,
-                            bool aOpaque,
+                            const nsIntRegion& aOpaqueRegion,
                             Rect* aClipRectOut,
                             Rect* aRenderBoundsOut)
 {
   // Don't composite if we are minimised. Other than for the sake of efficency,
   // this is important because resizing our buffers when mimised will fail and
   // cause a crash when we're restored.
   NS_ASSERTION(mHwnd, "Couldn't find an HWND when initialising?");
   if (::IsIconic(mHwnd) || mDevice->GetDeviceRemovedReason() != S_OK) {
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -106,17 +106,17 @@ public:
 
   /**
    * Start a new frame. If aClipRectIn is null, sets *aClipRectOut to the
    * screen dimensions. 
    */
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect *aClipRectIn,
                           const gfx::Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) override;
 
   /**
    * Flush the current frame to the screen.
    */
   virtual void EndFrame() override;
 
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -675,17 +675,17 @@ CompositorD3D9::FailedToResetDevice() {
     gfxWarning() << "[D3D9] Unable to get a working D3D9 Compositor";
   }
 }
 
 void
 CompositorD3D9::BeginFrame(const nsIntRegion& aInvalidRegion,
                            const Rect *aClipRectIn,
                            const Rect& aRenderBounds,
-                           bool aOpaque,
+                           const nsIntRegion& aOpaqueRegion,
                            Rect *aClipRectOut,
                            Rect *aRenderBoundsOut)
 {
   MOZ_ASSERT(mDeviceManager && mSwapChain);
 
   mDeviceManager->SetupRenderState();
 
   EnsureSize();
--- a/gfx/layers/d3d9/CompositorD3D9.h
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -59,17 +59,17 @@ public:
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
                         const gfx::Matrix4x4& aTransform,
                         const gfx::Rect& aVisibleRect) override;
 
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect *aClipRectIn,
                           const gfx::Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) override;
 
   virtual void EndFrame() override;
 
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) override {}
 
   virtual void PrepareViewport(const gfx::IntSize& aSize);
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -626,17 +626,17 @@ CompositorOGL::ClearRect(const gfx::Rect
   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
 }
 
 void
 CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
                           const Rect *aClipRectIn,
                           const Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           Rect *aClipRectOut,
                           Rect *aRenderBoundsOut)
 {
   PROFILER_LABEL("CompositorOGL", "BeginFrame",
     js::ProfileEntry::Category::GRAPHICS);
 
   MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame");
 
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -397,17 +397,17 @@ private:
   virtual void ClearRect(const gfx::Rect& aRect) override;
 
   /* Start a new frame. If aClipRectIn is null and aClipRectOut is non-null,
    * sets *aClipRectOut to the screen dimensions.
    */
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect *aClipRectIn,
                           const gfx::Rect& aRenderBounds,
-                          bool aOpaque,
+                          const nsIntRegion& aOpaqueRegion,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) override;
 
   ShaderConfigOGL GetShaderConfigFor(Effect *aEffect,
                                      MaskType aMask = MaskType::MaskNone,
                                      gfx::CompositionOp aOp = gfx::CompositionOp::OP_OVER,
                                      bool aColorMatrix = false,
                                      bool aDEAAEnabled = false) const;
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -653,17 +653,17 @@ typedef void (*JSClassInternal)();
 
 struct JSClass {
     JS_CLASS_MEMBERS(JSFinalizeOp);
 
     void*               reserved[5];
 };
 
 #define JSCLASS_HAS_PRIVATE             (1<<0)  // objects have private slot
-#define JSCLASS_DELAY_METADATA_CALLBACK (1<<1)  // class's initialization code
+#define JSCLASS_DELAY_METADATA_BUILDER  (1<<1)  // class's initialization code
                                                 // will call
                                                 // SetNewObjectMetadata itself
 #define JSCLASS_PRIVATE_IS_NSISUPPORTS  (1<<3)  // private is (nsISupports*)
 #define JSCLASS_IS_DOMJSCLASS           (1<<4)  // objects are DOM
 #define JSCLASS_HAS_XRAYED_CONSTRUCTOR  (1<<5)  // if wrapped by an xray
                                                 // wrapper, the builtin
                                                 // class's constructor won't
                                                 // be unwrapped and invoked.
@@ -793,18 +793,18 @@ struct Class
     bool isProxy() const {
         return flags & JSCLASS_IS_PROXY;
     }
 
     bool isDOMClass() const {
         return flags & JSCLASS_IS_DOMJSCLASS;
     }
 
-    bool shouldDelayMetadataCallback() const {
-        return flags & JSCLASS_DELAY_METADATA_CALLBACK;
+    bool shouldDelayMetadataBuilder() const {
+        return flags & JSCLASS_DELAY_METADATA_BUILDER;
     }
 
     static size_t offsetOfFlags() { return offsetof(Class, flags); }
 
     bool specDefined()         const { return spec ? spec->defined()   : false; }
     bool specDependent()       const { return spec ? spec->dependent() : false; }
     JSProtoKey specParentKey() const { return spec ? spec->parentKey() : JSProto_Null; }
     bool specShouldDefineConstructor()
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -1560,17 +1560,17 @@ Module::profilingLabel(uint32_t funcInde
 {
     MOZ_ASSERT(dynamicallyLinked_);
     MOZ_ASSERT(profilingEnabled_);
     return funcLabels_[funcIndex].get();
 }
 
 const Class WasmModuleObject::class_ = {
     "WasmModuleObject",
-    JSCLASS_IS_ANONYMOUS | JSCLASS_DELAY_METADATA_CALLBACK |
+    JSCLASS_IS_ANONYMOUS | JSCLASS_DELAY_METADATA_BUILDER |
     JSCLASS_HAS_RESERVED_SLOTS(WasmModuleObject::RESERVED_SLOTS),
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* getProperty */
     nullptr, /* setProperty */
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1139,24 +1139,24 @@ CallFunctionWithAsyncStack(JSContext* cx
                                          JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::EXPLICIT);
     return Call(cx, UndefinedHandleValue, function,
                 JS::HandleValueArray::empty(), args.rval());
 }
 
 static bool
 EnableTrackAllocations(JSContext* cx, unsigned argc, Value* vp)
 {
-    SetObjectMetadataCallback(cx, SavedStacksMetadataCallback);
+    SetAllocationMetadataBuilder(cx, &SavedStacks::metadataBuilder);
     return true;
 }
 
 static bool
 DisableTrackAllocations(JSContext* cx, unsigned argc, Value* vp)
 {
-    SetObjectMetadataCallback(cx, nullptr);
+    SetAllocationMetadataBuilder(cx, nullptr);
     return true;
 }
 
 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
 static bool
 OOMThreadTypes(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1684,84 +1684,95 @@ DisplayName(JSContext* cx, unsigned argc
     }
 
     JSFunction* fun = &args[0].toObject().as<JSFunction>();
     JSString* str = fun->displayAtom();
     args.rval().setString(str ? str : cx->runtime()->emptyString);
     return true;
 }
 
-static JSObject*
-ShellObjectMetadataCallback(JSContext* cx, HandleObject)
+class ShellAllocationMetadataBuilder : public AllocationMetadataBuilder {
+  public:
+    ShellAllocationMetadataBuilder() : AllocationMetadataBuilder() { }
+
+    virtual JSObject* build(JSContext *cx, HandleObject,
+                            AutoEnterOOMUnsafeRegion& oomUnsafe) const override;
+
+    static const ShellAllocationMetadataBuilder metadataBuilder;
+};
+
+JSObject*
+ShellAllocationMetadataBuilder::build(JSContext* cx, HandleObject,
+                                      AutoEnterOOMUnsafeRegion& oomUnsafe) const
 {
-    AutoEnterOOMUnsafeRegion oomUnsafe;
-
     RootedObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
     if (!obj)
-        oomUnsafe.crash("ShellObjectMetadataCallback");
+        oomUnsafe.crash("ShellAllocationMetadataBuilder::build");
 
     RootedObject stack(cx, NewDenseEmptyArray(cx));
     if (!stack)
-        oomUnsafe.crash("ShellObjectMetadataCallback");
+        oomUnsafe.crash("ShellAllocationMetadataBuilder::build");
 
     static int createdIndex = 0;
     createdIndex++;
 
     if (!JS_DefineProperty(cx, obj, "index", createdIndex, 0,
                            JS_STUBGETTER, JS_STUBSETTER))
     {
-        oomUnsafe.crash("ShellObjectMetadataCallback");
+        oomUnsafe.crash("ShellAllocationMetadataBuilder::build");
     }
 
     if (!JS_DefineProperty(cx, obj, "stack", stack, 0,
                            JS_STUBGETTER, JS_STUBSETTER))
     {
-        oomUnsafe.crash("ShellObjectMetadataCallback");
+        oomUnsafe.crash("ShellAllocationMetadataBuilder::build");
     }
 
     int stackIndex = 0;
     RootedId id(cx);
     RootedValue callee(cx);
     for (NonBuiltinScriptFrameIter iter(cx); !iter.done(); ++iter) {
         if (iter.isFunctionFrame() && iter.compartment() == cx->compartment()) {
             id = INT_TO_JSID(stackIndex);
             RootedObject callee(cx, iter.callee(cx));
             if (!JS_DefinePropertyById(cx, stack, id, callee, 0,
                                        JS_STUBGETTER, JS_STUBSETTER))
             {
-                oomUnsafe.crash("ShellObjectMetadataCallback");
+                oomUnsafe.crash("ShellAllocationMetadataBuilder::build");
             }
             stackIndex++;
         }
     }
 
     return obj;
 }
 
+const ShellAllocationMetadataBuilder ShellAllocationMetadataBuilder::metadataBuilder;
+
 static bool
-EnableShellObjectMetadataCallback(JSContext* cx, unsigned argc, Value* vp)
+EnableShellAllocationMetadataBuilder(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    SetObjectMetadataCallback(cx, ShellObjectMetadataCallback);
+    SetAllocationMetadataBuilder(cx, &ShellAllocationMetadataBuilder::metadataBuilder);
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
-GetObjectMetadata(JSContext* cx, unsigned argc, Value* vp)
+GetAllocationMetadata(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1 || !args[0].isObject()) {
         JS_ReportError(cx, "Argument must be an object");
         return false;
     }
 
-    args.rval().setObjectOrNull(GetObjectMetadata(&args[0].toObject()));
+    args.rval().setObjectOrNull(GetAllocationMetadata(&args[0].toObject()));
     return true;
 }
 
 static bool
 testingFunc_bailout(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -3767,22 +3778,22 @@ gc::ZealModeHelpText),
     JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0,
 "isLazyFunction(fun)",
 "  True if fun is a lazy JSFunction."),
 
     JS_FN_HELP("isRelazifiableFunction", IsRelazifiableFunction, 1, 0,
 "isRelazifiableFunction(fun)",
 "  Ture if fun is a JSFunction with a relazifiable JSScript."),
 
-    JS_FN_HELP("enableShellObjectMetadataCallback", EnableShellObjectMetadataCallback, 0, 0,
-"enableShellObjectMetadataCallback()",
-"  Use ShellObjectMetadataCallback to supply metadata for all newly created objects."),
-
-    JS_FN_HELP("getObjectMetadata", GetObjectMetadata, 1, 0,
-"getObjectMetadata(obj)",
+    JS_FN_HELP("enableShellAllocationMetadataBuilder", EnableShellAllocationMetadataBuilder, 0, 0,
+"enableShellAllocationMetadataBuilder()",
+"  Use ShellAllocationMetadataBuilder to supply metadata for all newly created objects."),
+
+    JS_FN_HELP("getAllocationMetadata", GetAllocationMetadata, 1, 0,
+"getAllocationMetadata(obj)",
 "  Get the metadata for an object."),
 
     JS_INLINABLE_FN_HELP("bailout", testingFunc_bailout, 0, 0, TestBailout,
 "bailout()",
 "  Force a bailout out of ionmonkey (if running in ionmonkey)."),
 
     JS_FN_HELP("inJit", testingFunc_inJit, 0, 0,
 "inJit()",
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2279,19 +2279,19 @@ const ObjectOps TypedObject::objectOps_ 
         JS_NULL_CLASS_SPEC,                              \
         JS_NULL_CLASS_EXT,                               \
         &TypedObject::objectOps_                         \
     }
 
 DEFINE_TYPEDOBJ_CLASS(OutlineTransparentTypedObject, OutlineTypedObject::obj_trace, 0);
 DEFINE_TYPEDOBJ_CLASS(OutlineOpaqueTypedObject,      OutlineTypedObject::obj_trace, 0);
 DEFINE_TYPEDOBJ_CLASS(InlineTransparentTypedObject,  InlineTypedObject::obj_trace,
-                      JSCLASS_DELAY_METADATA_CALLBACK);
+                      JSCLASS_DELAY_METADATA_BUILDER);
 DEFINE_TYPEDOBJ_CLASS(InlineOpaqueTypedObject,       InlineTypedObject::obj_trace,
-                      JSCLASS_DELAY_METADATA_CALLBACK);
+                      JSCLASS_DELAY_METADATA_BUILDER);
 
 static int32_t
 LengthForType(TypeDescr& descr)
 {
     switch (descr.kind()) {
       case type::Scalar:
       case type::Reference:
       case type::Struct:
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -20,17 +20,17 @@
 using namespace js;
 using namespace js::gc;
 
 Zone * const Zone::NotOnList = reinterpret_cast<Zone*>(1);
 
 JS::Zone::Zone(JSRuntime* rt)
   : JS::shadow::Zone(rt, &rt->gc.marker),
     debuggers(nullptr),
-    suppressObjectMetadataCallback(false),
+    suppressAllocationMetadataBuilder(false),
     arenas(rt),
     types(this),
     compartments(),
     gcGrayRoots(),
     gcMallocBytes(0),
     gcMallocGCTriggered(false),
     usage(&rt->gc.usage),
     gcDelayBytes(0),
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -282,17 +282,17 @@ struct Zone : public JS::shadow::Zone,
      * When true, skip calling the metadata callback. We use this:
      * - to avoid invoking the callback recursively;
      * - to avoid observing lazy prototype setup (which confuses callbacks that
      *   want to use the types being set up!);
      * - to avoid attaching allocation stacks to allocation stack nodes, which
      *   is silly
      * And so on.
      */
-    bool suppressObjectMetadataCallback;
+    bool suppressAllocationMetadataBuilder;
 
     js::gc::ArenaLists arenas;
 
     js::TypeZone types;
 
     /* Live weakmaps in this zone. */
     mozilla::LinkedList<js::WeakMapBase> gcWeakMapList;
 
--- a/js/src/jit-test/tests/baseline/metadata-hook-on-stack.js
+++ b/js/src/jit-test/tests/baseline/metadata-hook-on-stack.js
@@ -1,16 +1,16 @@
 // JSOP_NEWOBJECT should respect the metadata hook, even if
 // it's set with scripts on the stack.
 
 function f() {
     for (var i=0; i<100; i++) {
 	if (i === 20)
-	    enableShellObjectMetadataCallback();
+	    enableShellAllocationMetadataBuilder();
 	var o = {x: 1};
 	if (i >= 20) {
-	    var md = getObjectMetadata(o);
+	    var md = getAllocationMetadata(o);
 	    assertEq(typeof md === "object" && md !== null, true);
 	    assertEq(typeof md.index, "number");
 	}
     }
 }
 f();
--- a/js/src/jit-test/tests/basic/bug951213.js
+++ b/js/src/jit-test/tests/basic/bug951213.js
@@ -1,8 +1,8 @@
 
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
 function foo(x, y) {
   this.g = x + y;
 }
 var a = 0;
 var b = { valueOf: function() Object.defineProperty(Object.prototype, 'g', {}) };
 var c = new foo(a, b);
--- a/js/src/jit-test/tests/basic/bug951346.js
+++ b/js/src/jit-test/tests/basic/bug951346.js
@@ -1,3 +1,3 @@
 
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
 eval(uneval({'-1':true}));
--- a/js/src/jit-test/tests/basic/bug951632.js
+++ b/js/src/jit-test/tests/basic/bug951632.js
@@ -1,9 +1,9 @@
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
 var g = newGlobal()
 g.eval("function f(a) { return h(); }");
 g.h = function () {
     return [1, 2, 3];
 };
-var o = getObjectMetadata(g.f(5));
+var o = getAllocationMetadata(g.f(5));
 assertEq(o.stack.length, 1);
 assertEq(o.stack[0], g.h);
--- a/js/src/jit-test/tests/basic/metadata-hook.js
+++ b/js/src/jit-test/tests/basic/metadata-hook.js
@@ -1,10 +1,10 @@
 
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
 
 function Foo() {
   this.x = 0;
   this.y = 1;
 }
 
 function hello() {
   function there() {
@@ -13,18 +13,18 @@ function hello() {
     y = [2,3,5];
     z = {a:0,b:1};
   }
   callee = there;
   callee();
 }
 hello();
 
-var wc = getObjectMetadata(w).index;
-var xc = getObjectMetadata(x).index;
-var yc = getObjectMetadata(y).index;
-var zc = getObjectMetadata(z).index;
+var wc = getAllocationMetadata(w).index;
+var xc = getAllocationMetadata(x).index;
+var yc = getAllocationMetadata(y).index;
+var zc = getAllocationMetadata(z).index;
 
 assertEq(xc > wc, true);
 assertEq(yc > xc, true);
 assertEq(zc > yc, true);
-assertEq(getObjectMetadata(x).stack[0], callee);
-assertEq(getObjectMetadata(x).stack[1], hello);
+assertEq(getAllocationMetadata(x).stack[0], callee);
+assertEq(getAllocationMetadata(x).stack[1], hello);
--- a/js/src/jit-test/tests/basic/track-allocation-sites.js
+++ b/js/src/jit-test/tests/basic/track-allocation-sites.js
@@ -12,13 +12,13 @@ const tests = [
   { name: "new Date",        object: new Date(),            line: Error().lineNumber }
 ];
 
 disableTrackAllocations();
 
 for (let { name, object, line } of tests) {
   print("Entering test: " + name);
 
-  let allocationSite = getObjectMetadata(object);
+  let allocationSite = getAllocationMetadata(object);
   print(allocationSite);
 
   assertEq(allocationSite.line, line);
 }
--- a/js/src/jit-test/tests/debug/Memory-trackingAllocationSites-03.js
+++ b/js/src/jit-test/tests/debug/Memory-trackingAllocationSites-03.js
@@ -58,17 +58,17 @@ test("Adding a new debuggee to a debugge
 
 test("Setting trackingAllocationSites to true should throw if the debugger " +
      "cannot install the allocation hooks for *every* debuggee.",
      () => {
        let d1r1 = dbg1.addDebuggee(root1);
        let d1r2 = dbg1.addDebuggee(root2);
 
        // Can't install allocation hooks for root2 with this set.
-       root2.enableShellObjectMetadataCallback();
+       root2.enableShellAllocationMetadataBuilder();
 
        assertThrowsInstanceOf(() => dbg1.memory.trackingAllocationSites = true,
                               Error);
 
        // And after it throws, its trackingAllocationSites accessor should reflect that
        // allocation site tracking is still disabled in that Debugger.
        assertEq(dbg1.memory.trackingAllocationSites, false);
        assertEq(isTrackingAllocations(root1, d1r1), false);
@@ -89,17 +89,17 @@ test("Re-enabling throws an error if we 
      "for all debuggees.",
      () => {
        dbg1.enabled = false
        dbg1.memory.trackingAllocationSites = true;
        let d1r1 = dbg1.addDebuggee(root1);
        let d1r2 = dbg1.addDebuggee(root2);
 
        // Can't install allocation hooks for root2 with this set.
-       root2.enableShellObjectMetadataCallback();
+       root2.enableShellAllocationMetadataBuilder();
 
        assertThrowsInstanceOf(() => dbg1.enabled = true,
                               Error);
 
        assertEq(dbg1.enabled, false);
        assertEq(isTrackingAllocations(root1, d1r1), false);
        assertEq(isTrackingAllocations(root2, d1r2), false);
      });
--- a/js/src/jit-test/tests/debug/bug1221378.js
+++ b/js/src/jit-test/tests/debug/bug1221378.js
@@ -3,9 +3,9 @@
 
 // To test for this regression, we need some way to make the code that collects
 // metadata about object allocations allocate an Array. Presently,
 // enableShellObjectMetadataCallback installs a callback that does this, but if
 // that hook gets removed (in production there's only ever one callback we
 // actually use), then the ability to make whatever metadata collection code
 // remains allocate an Array will cover this regression. For example, it could
 // be a flag that one can only set in debug builds from TestingFunctions.cpp.
-newGlobal().eval('enableShellObjectMetadataCallback(); Array');
+newGlobal().eval('enableShellAllocationMetadataBuilder(); Array');
--- a/js/src/jit-test/tests/gc/bug-1148383.js
+++ b/js/src/jit-test/tests/gc/bug-1148383.js
@@ -9,11 +9,11 @@ if (!opts['ion.enable'] || !opts['baseli
 function TestCase() {}
 function reportCompare () {
   var output = "";
   var testcase = new TestCase();
   testcase.reason = output;
 }
 reportCompare();
 gczeal(4, 1000);
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
 for (var i = 0; i < 10000; ++i)
   reportCompare();
--- a/js/src/jit-test/tests/gc/bug-1215678.js
+++ b/js/src/jit-test/tests/gc/bug-1215678.js
@@ -1,10 +1,10 @@
 // |jit-test| error: ReferenceError
 if (!('oomTest' in this))
     a;
 
-enableShellObjectMetadataCallback()
+enableShellAllocationMetadataBuilder()
 oomTest(() => {
   newGlobal()
 })
 gczeal(9, 1);
 a;
--- a/js/src/jit-test/tests/gc/bug-1252154.js
+++ b/js/src/jit-test/tests/gc/bug-1252154.js
@@ -1,11 +1,11 @@
 // Bug 1252154: Inline typed array objects need delayed metadata collection.
 // Shouldn't crash.
 
 if (!this.hasOwnProperty("TypedObject"))
   quit();
 
 gczeal(7,1);
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
 var T = TypedObject;
 var AT = new T.ArrayType(T.Any,10);
 var v = new AT();
--- a/js/src/jit-test/tests/gc/bug-886560.js
+++ b/js/src/jit-test/tests/gc/bug-886560.js
@@ -1,11 +1,11 @@
 // |jit-test| error: x is not defined
 
-// enableShellObjectMetadataCallback ignores its argument, because we don't
+// enableShellAllocationMetadataBuilder ignores its argument, because we don't
 // permit metadata callbacks to run JS any more, so this test may be
 // unnecessary. We'll preserve its structure just in case.
-enableShellObjectMetadataCallback(function(obj) {
+enableShellAllocationMetadataBuilder(function(obj) {
     var res = {};
     return res;
   });
 gczeal(4);
 x();
--- a/js/src/jit-test/tests/gc/bug-935022.js
+++ b/js/src/jit-test/tests/gc/bug-935022.js
@@ -1,4 +1,4 @@
 function callback(obj) {}
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
 gczeal(7);
 var statusitems = [];
--- a/js/src/jit-test/tests/gc/bug-945280.js
+++ b/js/src/jit-test/tests/gc/bug-945280.js
@@ -1,4 +1,4 @@
 gczeal(7,1);
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
 gczeal(false);
 var statusitems = [];
--- a/js/src/jit-test/tests/gc/bug-945285.js
+++ b/js/src/jit-test/tests/gc/bug-945285.js
@@ -1,3 +1,3 @@
 gczeal(11);
 function callback(obj) {}
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
--- a/js/src/jit-test/tests/gc/bug-961741.js
+++ b/js/src/jit-test/tests/gc/bug-961741.js
@@ -1,5 +1,5 @@
 function r() {
     for (var x in undefined) {}
 }
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
 r();
--- a/js/src/jit-test/tests/ion/bug1006899.js
+++ b/js/src/jit-test/tests/ion/bug1006899.js
@@ -2,17 +2,17 @@ if (!this.hasOwnProperty("TypedObject"))
   quit();
 
 this.__defineGetter__("x",
   function() {
     return this;
   }
 );
 function callback(obj) {}
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
 evaluate("\
 var { ArrayType, StructType, uint32 } = TypedObject;\
   var L = 1024;\
   var Matrix = uint32.array(L, 2);\
   var matrix = new Matrix();\
   for (var i = 0; i < L; i++)\
     matrix[i][0] = x;\
 ", { isRunOnce : true });
--- a/js/src/jit-test/tests/ion/bug1054241.js
+++ b/js/src/jit-test/tests/ion/bug1054241.js
@@ -1,12 +1,12 @@
 setJitCompilerOption("baseline.warmup.trigger", 10);
 setJitCompilerOption("ion.warmup.trigger", 20);
 
-enableShellObjectMetadataCallback();
+enableShellAllocationMetadataBuilder();
 (function(){
   for(var i = 0; i < 100; i++) {
     try{
       var a = new Array(5);
       throw 1;
     } catch(e) {}
   }
 })();
--- a/js/src/jit-test/tests/ion/bug1057598.js
+++ b/js/src/jit-test/tests/ion/bug1057598.js
@@ -1,12 +1,12 @@
-// enableShellObjectMetadataCallback ignores its argument, because we don't
+// enableShellAllocationMetadataBuilder ignores its argument, because we don't
 // permit metadata callbacks to run JS any more, so this test may be
 // unnecessary. We'll preserve its structure just in case.
-enableShellObjectMetadataCallback(function( r, ... d)  {});
+enableShellAllocationMetadataBuilder(function( r, ... d)  {});
 setJitCompilerOption("ion.warmup.trigger", 20);
 var uceFault = function (i) {
     if (i > 98)
         uceFault = function (i) { return true; };
 }
 var uceFault_str_split = eval(uneval(uceFault).replace('uceFault', 'uceFault_str_split'))
 function rstr_split(i) {
     var x = "str01234567899876543210rts".split("" + i);
--- a/js/src/jit-test/tests/ion/recover-lambdas-bug1113940.js
+++ b/js/src/jit-test/tests/ion/recover-lambdas-bug1113940.js
@@ -1,33 +1,33 @@
 
 gczeal(14);
 
 // The object metadata callback can iterate over the stack. Thus during the
 // allocation of the lambda we might inspect the stack which is still incomplete
 // because the lambda is not yet reconstructed.
 //
-// enableShellObjectMetadataCallback ignores its argument, because we don't
+// enableShellAllocationMetadataBuilder ignores its argument, because we don't
 // permit metadata callbacks to run JS any more, so this test may be
 // unnecessary. We'll preserve its structure just in case.
-enableShellObjectMetadataCallback(function() {});
+enableShellAllocationMetadataBuilder(function() {});
 function f() {
     (function() {
         '' ^ Object
     })();
 }
 x = 0;
 for (var j = 0; j < 99; ++j) {
     x += f();
 }
 
 try {
   x = true;
   // Same comment as above.
-  enableShellObjectMetadataCallback(function([x, y, z], ... Debugger) {});
+  enableShellAllocationMetadataBuilder(function([x, y, z], ... Debugger) {});
   for (var i = 0; i < 10; ++i) {
     var f = function() {
       function g() {
 	x++;
       }
       g();
     }
     f();
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -501,17 +501,17 @@ GenerateNewObjectWithTemplateCode(JSCont
 #endif
 
     Label failure;
     Register objReg = R0.scratchReg();
     Register tempReg = R1.scratchReg();
     masm.movePtr(ImmGCPtr(templateObject->group()), tempReg);
     masm.branchTest32(Assembler::NonZero, Address(tempReg, ObjectGroup::offsetOfFlags()),
                       Imm32(OBJECT_FLAG_PRE_TENURE), &failure);
-    masm.branchPtr(Assembler::NotEqual, AbsoluteAddress(cx->compartment()->addressOfMetadataCallback()),
+    masm.branchPtr(Assembler::NotEqual, AbsoluteAddress(cx->compartment()->addressOfMetadataBuilder()),
                    ImmWord(0), &failure);
     masm.createGCObject(objReg, tempReg, templateObject, gc::DefaultHeap, &failure);
     masm.tagValue(JSVAL_TYPE_OBJECT, objReg, R0);
 
     EmitReturnFromIC(masm);
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
 
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -258,19 +258,19 @@ CompileCompartment::addressOfRandomNumbe
 
 const JitCompartment*
 CompileCompartment::jitCompartment()
 {
     return compartment()->jitCompartment();
 }
 
 bool
-CompileCompartment::hasObjectMetadataCallback()
+CompileCompartment::hasAllocationMetadataBuilder()
 {
-    return compartment()->hasObjectMetadataCallback();
+    return compartment()->hasAllocationMetadataBuilder();
 }
 
 // Note: This function is thread-safe because setSingletonAsValue sets a boolean
 // variable to false, and this boolean variable has no way to be resetted to
 // true. So even if there is a concurrent write, this concurrent write will
 // always have the same value.  If there is a concurrent read, then we will
 // clone a singleton instead of using the value which is baked in the JSScript,
 // and this would be an unfortunate allocation, but this will not change the
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -112,17 +112,17 @@ class CompileCompartment
     CompileZone* zone();
     CompileRuntime* runtime();
 
     const void* addressOfEnumerators();
     const void* addressOfRandomNumberGenerator();
 
     const JitCompartment* jitCompartment();
 
-    bool hasObjectMetadataCallback();
+    bool hasAllocationMetadataBuilder();
 
     // Mirror CompartmentOptions.
     void setSingletonsAsValues();
 };
 
 class JitCompileOptions
 {
   public:
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -722,17 +722,17 @@ MacroAssembler::checkAllocatorState(Labe
     // Don't execute the inline path if gc zeal or tracing are active.
     branch32(Assembler::NotEqual,
              AbsoluteAddress(GetJitContext()->runtime->addressOfGCZealModeBits()), Imm32(0),
              fail);
 #endif
 
     // Don't execute the inline path if the compartment has an object metadata callback,
     // as the metadata to use for the object may vary between executions of the op.
-    if (GetJitContext()->compartment->hasObjectMetadataCallback())
+    if (GetJitContext()->compartment->hasAllocationMetadataBuilder())
         jump(fail);
 }
 
 // Inline version of ShouldNurseryAllocate.
 bool
 MacroAssembler::shouldNurseryAllocate(gc::AllocKind allocKind, gc::InitialHeap initialHeap)
 {
     // Note that Ion elides barriers on writes to objects known to be in the
--- a/js/src/jit/mips-shared/Architecture-mips-shared.cpp
+++ b/js/src/jit/mips-shared/Architecture-mips-shared.cpp
@@ -13,24 +13,21 @@
 
 #define HWCAP_MIPS (1 << 28)
 #define HWCAP_LOONGSON (1 << 27)
 #define HWCAP_FPU (1 << 0)
 
 namespace js {
 namespace jit {
 
-uint32_t GetMIPSFlags()
+static uint32_t
+get_mips_flags()
 {
-    static uint32_t flags = 0;
+    uint32_t flags = HWCAP_MIPS;
 
-    if (flags)
-        return flags;
-
-    flags |= HWCAP_MIPS;
 #if defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
     flags |= HWCAP_FPU;
 #else
 # ifdef __linux__
     FILE* fp = fopen("/proc/cpuinfo", "r");
     if (!fp)
         return flags;
 
@@ -42,24 +39,31 @@ uint32_t GetMIPSFlags()
         flags |= HWCAP_FPU;
     if (strstr(buf, "Loongson"))
         flags |= HWCAP_LOONGSON;
 # endif
 #endif // JS_SIMULATOR_MIPS32 || JS_SIMULATOR_MIPS64
     return flags;
 }
 
-bool hasFPU()
+static bool check_fpu()
 {
-    return js::jit::GetMIPSFlags() & HWCAP_FPU;
+    return mips_private::Flags & HWCAP_FPU;
 }
 
-bool isLoongson()
+static bool check_loongson()
 {
-    return js::jit::GetMIPSFlags() & HWCAP_LOONGSON;
+    return mips_private::Flags & HWCAP_LOONGSON;
+}
+
+namespace mips_private {
+    // Cache a local copy so we only have to read /proc/cpuinfo once.
+    uint32_t Flags = get_mips_flags();
+    bool hasFPU = check_fpu();;
+    bool isLoongson = check_loongson();
 }
 
 Registers::Code
 Registers::FromName(const char* name)
 {
     for (size_t i = 0; i < Total; i++) {
         if (strcmp(GetName(i), name) == 0)
             return Code(i);
--- a/js/src/jit/mips-shared/Architecture-mips-shared.h
+++ b/js/src/jit/mips-shared/Architecture-mips-shared.h
@@ -303,19 +303,25 @@ class FloatRegisterMIPSShared
     static uint32_t FirstBit(SetType x) {
         return mozilla::CountTrailingZeroes64(x);
     }
     static uint32_t LastBit(SetType x) {
         return 63 - mozilla::CountLeadingZeroes64(x);
     }
 };
 
-uint32_t GetMIPSFlags();
-bool hasFPU();
-bool isLoongson();
+namespace mips_private {
+    extern uint32_t Flags;
+    extern bool hasFPU;
+    extern bool isLoongson;
+}
+
+inline uint32_t GetMIPSFlags() { return mips_private::Flags; }
+inline bool hasFPU() { return mips_private::hasFPU; }
+inline bool isLoongson() { return mips_private::isLoongson; }
 
 // MIPS doesn't have double registers that can NOT be treated as float32.
 inline bool
 hasUnaliasedDouble() {
     return false;
 }
 
 // On MIPS, fn-double aliases both fn-float32 and fn+1-float32, so if you need
--- a/js/src/jsapi-tests/testSavedStacks.cpp
+++ b/js/src/jsapi-tests/testSavedStacks.cpp
@@ -11,19 +11,19 @@
 #include "builtin/TestingFunctions.h"
 #include "jsapi-tests/tests.h"
 #include "vm/ArrayObject.h"
 #include "vm/SavedStacks.h"
 
 BEGIN_TEST(testSavedStacks_withNoStack)
 {
     JSCompartment* compartment = js::GetContextCompartment(cx);
-    compartment->setObjectMetadataCallback(js::SavedStacksMetadataCallback);
+    compartment->setAllocationMetadataBuilder(&js::SavedStacks::metadataBuilder);
     JS::RootedObject obj(cx, js::NewDenseEmptyArray(cx));
-    compartment->setObjectMetadataCallback(nullptr);
+    compartment->setAllocationMetadataBuilder(nullptr);
     return true;
 }
 END_TEST(testSavedStacks_withNoStack)
 
 BEGIN_TEST(testSavedStacks_ApiDefaultValues)
 {
     js::RootedSavedFrame savedFrame(cx, nullptr);
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3269,17 +3269,17 @@ static const ClassSpec ArrayObjectClassS
     nullptr,
     array_methods,
     nullptr,
     array_proto_finish
 };
 
 const Class ArrayObject::class_ = {
     "Array",
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | JSCLASS_DELAY_METADATA_CALLBACK,
+    JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | JSCLASS_DELAY_METADATA_BUILDER,
     array_addProperty,
     nullptr, /* delProperty */
     nullptr, /* getProperty */
     nullptr, /* setProperty */
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     nullptr, /* finalize */
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -54,17 +54,17 @@ JSCompartment::JSCompartment(Zone* zone,
     warnedAboutExprClosure(false),
 #ifdef DEBUG
     firedOnNewGlobalObject(false),
 #endif
     global_(nullptr),
     enterCompartmentDepth(0),
     performanceMonitoring(runtime_),
     data(nullptr),
-    objectMetadataCallback(nullptr),
+    allocationMetadataBuilder(nullptr),
     lastAnimationTime(0),
     regExps(runtime_),
     globalWriteBarriered(false),
     detachedTypedObjects(0),
     objectMetadataState(ImmediateMetadata()),
     propertyTree(thisForCtor()),
     selfHostingScriptSource(nullptr),
     objectMetadataTable(nullptr),
@@ -868,39 +868,39 @@ JSCompartment::clearTables()
         baseShapes.clear();
     if (initialShapes.initialized())
         initialShapes.clear();
     if (savedStacks_.initialized())
         savedStacks_.clear();
 }
 
 void
-JSCompartment::setObjectMetadataCallback(js::ObjectMetadataCallback callback)
+JSCompartment::setAllocationMetadataBuilder(const js::AllocationMetadataBuilder *builder)
 {
     // Clear any jitcode in the runtime, which behaves differently depending on
     // whether there is a creation callback.
     ReleaseAllJITCode(runtime_->defaultFreeOp());
 
-    objectMetadataCallback = callback;
+    allocationMetadataBuilder = builder;
 }
 
 void
 JSCompartment::clearObjectMetadata()
 {
     js_delete(objectMetadataTable);
     objectMetadataTable = nullptr;
 }
 
 void
 JSCompartment::setNewObjectMetadata(JSContext* cx, HandleObject obj)
 {
     assertSameCompartment(cx, this, obj);
 
-    if (JSObject* metadata = objectMetadataCallback(cx, obj)) {
-        AutoEnterOOMUnsafeRegion oomUnsafe;
+    AutoEnterOOMUnsafeRegion oomUnsafe;
+    if (JSObject* metadata = allocationMetadataBuilder->build(cx, obj, oomUnsafe)) {
         assertSameCompartment(cx, metadata);
         if (!objectMetadataTable) {
             objectMetadataTable = cx->new_<ObjectWeakMap>(cx);
             if (!objectMetadataTable || !objectMetadataTable->init())
                 oomUnsafe.crash("setNewObjectMetadata");
         }
         if (!objectMetadataTable->add(cx, obj, metadata))
             oomUnsafe.crash("setNewObjectMetadata");
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -137,35 +137,35 @@ struct WrapperHasher : public DefaultHas
         return l.kind == k.kind && l.debugger == k.debugger && l.wrapped == k.wrapped;
     }
 };
 
 using WrapperMap = GCRekeyableHashMap<CrossCompartmentKey, ReadBarrieredValue,
                                       WrapperHasher, SystemAllocPolicy>;
 
 // We must ensure that all newly allocated JSObjects get their metadata
-// set. However, metadata callbacks may require the new object be in a sane
+// set. However, metadata builders may require the new object be in a sane
 // state (eg, have its reserved slots initialized so they can get the
 // sizeOfExcludingThis of the object). Therefore, for objects of certain
-// JSClasses (those marked with JSCLASS_DELAY_METADATA_CALLBACK), it is not safe
-// for the allocation paths to call the object metadata callback
+// JSClasses (those marked with JSCLASS_DELAY_METADATA_BUILDER), it is not safe
+// for the allocation paths to call the object metadata builder
 // immediately. Instead, the JSClass-specific "constructor" C++ function up the
 // stack makes a promise that it will ensure that the new object has its
 // metadata set after the object is initialized.
 //
 // To help those constructor functions keep their promise of setting metadata,
 // each compartment is in one of three states at any given time:
 //
 // * ImmediateMetadata: Allocators should set new object metadata immediately,
 //                      as usual.
 //
 // * DelayMetadata: Allocators should *not* set new object metadata, it will be
 //                  handled after reserved slots are initialized by custom code
 //                  for the object's JSClass. The newly allocated object's
-//                  JSClass *must* have the JSCLASS_DELAY_METADATA_CALLBACK flag
+//                  JSClass *must* have the JSCLASS_DELAY_METADATA_BUILDER flag
 //                  set.
 //
 // * PendingMetadata: This object has been allocated and is still pending its
 //                    metadata. This should never be the case when we begin an
 //                    allocation, as a constructor function was supposed to have
 //                    set the metadata of the previous object *before*
 //                    allocating another object.
 //
@@ -362,17 +362,17 @@ struct JSCompartment
     inline js::GlobalObject* unsafeUnbarrieredMaybeGlobal() const;
 
     inline void initGlobal(js::GlobalObject& global);
 
   public:
     void*                        data;
 
   private:
-    js::ObjectMetadataCallback   objectMetadataCallback;
+    const js::AllocationMetadataBuilder *allocationMetadataBuilder;
 
     js::SavedStacks              savedStacks_;
 
     js::WrapperMap               crossCompartmentWrappers;
 
   public:
     /* Last time at which an animation was played for a global in this compartment. */
     int64_t                      lastAnimationTime;
@@ -600,26 +600,28 @@ struct JSCompartment
     void purge();
     void clearTables();
 
     static void fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc);
     void fixupInitialShapeTable();
     void fixupAfterMovingGC();
     void fixupGlobal();
 
-    bool hasObjectMetadataCallback() const { return objectMetadataCallback; }
-    js::ObjectMetadataCallback getObjectMetadataCallback() const { return objectMetadataCallback; }
-    void setObjectMetadataCallback(js::ObjectMetadataCallback callback);
-    void forgetObjectMetadataCallback() {
-        objectMetadataCallback = nullptr;
+    bool hasAllocationMetadataBuilder() const { return allocationMetadataBuilder; }
+    const js::AllocationMetadataBuilder* getAllocationMetadataBuilder() const {
+        return allocationMetadataBuilder;
+    }
+    void setAllocationMetadataBuilder(const js::AllocationMetadataBuilder* builder);
+    void forgetAllocationMetadataBuilder() {
+        allocationMetadataBuilder = nullptr;
     }
     void setNewObjectMetadata(JSContext* cx, JS::HandleObject obj);
     void clearObjectMetadata();
-    const void* addressOfMetadataCallback() const {
-        return &objectMetadataCallback;
+    const void* addressOfMetadataBuilder() const {
+        return &allocationMetadataBuilder;
     }
 
     js::SavedStacks& savedStacks() { return savedStacks_; }
 
     void findOutgoingEdges(js::gc::ComponentFinder<JS::Zone>& finder);
 
     js::DtoaCache dtoaCache;
 
@@ -958,32 +960,32 @@ class MOZ_RAII AutoWrapperRooter : priva
 
     friend void JS::AutoGCRooter::trace(JSTracer* trc);
 
   private:
     WrapperValue value;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
-class MOZ_RAII AutoSuppressObjectMetadataCallback {
+class MOZ_RAII AutoSuppressAllocationMetadataBuilder {
     JS::Zone* zone;
     bool saved;
 
   public:
-    explicit AutoSuppressObjectMetadataCallback(ExclusiveContext* cx)
-      : AutoSuppressObjectMetadataCallback(cx->compartment()->zone())
+    explicit AutoSuppressAllocationMetadataBuilder(ExclusiveContext* cx)
+      : AutoSuppressAllocationMetadataBuilder(cx->compartment()->zone())
     { }
 
-    explicit AutoSuppressObjectMetadataCallback(JS::Zone* zone)
+    explicit AutoSuppressAllocationMetadataBuilder(JS::Zone* zone)
       : zone(zone),
-        saved(zone->suppressObjectMetadataCallback)
+        saved(zone->suppressAllocationMetadataBuilder)
     {
-        zone->suppressObjectMetadataCallback = true;
+        zone->suppressAllocationMetadataBuilder = true;
     }
 
-    ~AutoSuppressObjectMetadataCallback() {
-        zone->suppressObjectMetadataCallback = saved;
+    ~AutoSuppressAllocationMetadataBuilder() {
+        zone->suppressAllocationMetadataBuilder = saved;
     }
 };
 
 } /* namespace js */
 
 #endif /* jscompartment_h */
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -134,17 +134,17 @@ JS_NewObjectWithUniqueType(JSContext* cx
     if (!JS_SplicePrototype(cx, obj, proto))
         return nullptr;
     return obj;
 }
 
 JS_FRIEND_API(JSObject*)
 JS_NewObjectWithoutMetadata(JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto)
 {
-    AutoSuppressObjectMetadataCallback suppressMetadata(cx);
+    AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
     return JS_NewObjectWithGivenProto(cx, clasp, proto);
 }
 
 JS_FRIEND_API(JSPrincipals*)
 JS_GetCompartmentPrincipals(JSCompartment* compartment)
 {
     return compartment->principals();
 }
@@ -1229,23 +1229,23 @@ js::AutoCTypesActivityCallback::AutoCTyp
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
     if (callback)
         callback(cx, beginType);
 }
 
 JS_FRIEND_API(void)
-js::SetObjectMetadataCallback(JSContext* cx, ObjectMetadataCallback callback)
+js::SetAllocationMetadataBuilder(JSContext* cx, const AllocationMetadataBuilder *callback)
 {
-    cx->compartment()->setObjectMetadataCallback(callback);
+    cx->compartment()->setAllocationMetadataBuilder(callback);
 }
 
 JS_FRIEND_API(JSObject*)
-js::GetObjectMetadata(JSObject* obj)
+js::GetAllocationMetadata(JSObject* obj)
 {
     ObjectWeakMap* map = obj->compartment()->objectMetadataTable;
     if (map)
         return map->lookup(obj);
     return nullptr;
 }
 
 JS_FRIEND_API(bool)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -14,16 +14,17 @@
 
 #include "jsapi.h" // For JSAutoByteString.  See bug 1033916.
 #include "jsbytecode.h"
 #include "jspubtd.h"
 
 #include "js/CallArgs.h"
 #include "js/CallNonGenericMethod.h"
 #include "js/Class.h"
+#include "js/Utility.h"
 
 #if JS_STACK_GROWTH_DIRECTION > 0
 # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) < (limit)))
 #else
 # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) > (limit)))
 #endif
 
 class JSAtom;
@@ -328,17 +329,17 @@ extern JS_FRIEND_DATA(const js::ObjectOp
         objectMoved                                                     \
     }
 
 #define PROXY_CLASS_WITH_EXT(name, flags, ext)                                          \
     {                                                                                   \
         name,                                                                           \
         js::Class::NON_NATIVE |                                                         \
             JSCLASS_IS_PROXY |                                                          \
-            JSCLASS_DELAY_METADATA_CALLBACK |                                           \
+            JSCLASS_DELAY_METADATA_BUILDER |                                            \
             flags,                                                                      \
         nullptr,                 /* addProperty */                                      \
         nullptr,                 /* delProperty */                                      \
         nullptr,                 /* getProperty */                                      \
         nullptr,                 /* setProperty */                                      \
         nullptr,                 /* enumerate */                                        \
         nullptr,                 /* resolve */                                          \
         nullptr,                 /* mayResolve */                                       \
@@ -2660,30 +2661,45 @@ class MOZ_RAII JS_FRIEND_API(AutoCTypesA
     void DoEndCallback() {
         if (callback) {
             callback(cx, endType);
             callback = nullptr;
         }
     }
 };
 
-typedef JSObject*
-(* ObjectMetadataCallback)(JSContext* cx, JS::HandleObject obj);
+// Abstract base class for objects that build allocation metadata for JavaScript
+// values.
+struct AllocationMetadataBuilder {
+    AllocationMetadataBuilder() { }
+
+    // Return a metadata object for the newly constructed object |obj|, or
+    // nullptr if there's no metadata to attach.
+    //
+    // Implementations should treat all errors as fatal; there is no way to
+    // report errors from this callback. In particular, the caller provides an
+    // oomUnsafe for overriding implementations to use.
+    virtual JSObject* build(JSContext* cx, JS::HandleObject obj,
+                            AutoEnterOOMUnsafeRegion& oomUnsafe) const
+    {
+        return nullptr;
+    }
+};
 
 /**
  * Specify a callback to invoke when creating each JS object in the current
  * compartment, which may return a metadata object to associate with the
  * object.
  */
 JS_FRIEND_API(void)
-SetObjectMetadataCallback(JSContext* cx, ObjectMetadataCallback callback);
+SetAllocationMetadataBuilder(JSContext* cx, const AllocationMetadataBuilder *callback);
 
 /** Get the metadata associated with an object. */
 JS_FRIEND_API(JSObject*)
-GetObjectMetadata(JSObject* obj);
+GetAllocationMetadata(JSObject* obj);
 
 JS_FRIEND_API(bool)
 GetElementsWithAdder(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver,
                      uint32_t begin, uint32_t end, js::ElementAdder* adder);
 
 JS_FRIEND_API(bool)
 ForwardToNative(JSContext* cx, JSNative native, const JS::CallArgs& args);
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -272,37 +272,37 @@ ClassCanHaveFixedData(const Class* clasp
     // buffer's data.
     return !clasp->isNative()
         || clasp == &js::ArrayBufferObject::class_
         || js::IsTypedArrayClass(clasp);
 }
 
 // This function is meant to be called from allocation fast paths.
 //
-// If we do have an allocation metadata hook, it can cause a GC, so the object
+// If we do have an allocation metadata builder, it can cause a GC, so the object
 // must be rooted. The usual way to do this would be to make our callers pass a
 // HandleObject, but that would require them to pay the cost of rooting the
 // object unconditionally, even though collecting metadata is rare. Instead,
 // SetNewObjectMetadata's contract is that the caller must use the pointer
 // returned in place of the pointer passed. If a GC occurs, the returned pointer
 // may be the passed pointer, relocated by GC. If no GC could occur, it's just
 // passed through. We root nothing unless necessary.
 static MOZ_ALWAYS_INLINE MOZ_WARN_UNUSED_RESULT JSObject*
 SetNewObjectMetadata(ExclusiveContext* cxArg, JSObject* obj)
 {
     MOZ_ASSERT(!cxArg->compartment()->hasObjectPendingMetadata());
 
-    // The metadata callback is invoked for each object created on the main
+    // The metadata builder is invoked for each object created on the main
     // thread, except when analysis/compilation is active, to avoid recursion.
     if (JSContext* cx = cxArg->maybeJSContext()) {
-        if (MOZ_UNLIKELY((size_t)cx->compartment()->hasObjectMetadataCallback()) &&
-            !cx->zone()->suppressObjectMetadataCallback)
+        if (MOZ_UNLIKELY((size_t)cx->compartment()->hasAllocationMetadataBuilder()) &&
+            !cx->zone()->suppressAllocationMetadataBuilder)
         {
             // Don't collect metadata on objects that represent metadata.
-            AutoSuppressObjectMetadataCallback suppressMetadata(cx);
+            AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
 
             RootedObject rooted(cx, obj);
             cx->compartment()->setNewObjectMetadata(cx, rooted);
             return rooted;
         }
     }
 
     return obj;
@@ -366,17 +366,17 @@ JSObject::create(js::ExclusiveContext* c
         memset(obj->as<JSFunction>().fixedSlots(), 0, size - sizeof(js::NativeObject));
         if (kind == js::gc::AllocKind::FUNCTION_EXTENDED) {
             // SetNewObjectMetadata may gc, which will be unhappy if flags &
             // EXTENDED doesn't match the arena's AllocKind.
             obj->as<JSFunction>().setFlags(JSFunction::EXTENDED);
         }
     }
 
-    if (group->clasp()->shouldDelayMetadataCallback())
+    if (group->clasp()->shouldDelayMetadataBuilder())
         cx->compartment()->setObjectPendingMetadata(cx, obj);
     else
         obj = SetNewObjectMetadata(cx, obj);
 
     js::gc::TraceCreateObject(obj);
 
     return obj;
 }
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -672,17 +672,17 @@ ArgumentsObject::objectMovedDuringMinorG
 /*
  * The classes below collaborate to lazily reflect and synchronize actual
  * argument values, argument count, and callee function object stored in a
  * stack frame with their corresponding property values in the frame's
  * arguments object.
  */
 const Class MappedArgumentsObject::class_ = {
     "Arguments",
-    JSCLASS_DELAY_METADATA_CALLBACK |
+    JSCLASS_DELAY_METADATA_BUILDER |
     JSCLASS_HAS_RESERVED_SLOTS(MappedArgumentsObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
     JSCLASS_SKIP_NURSERY_FINALIZE |
     JSCLASS_BACKGROUND_FINALIZE,
     nullptr,                 /* addProperty */
     ArgumentsObject::obj_delProperty,
     nullptr,                 /* getProperty */
     nullptr,                 /* setProperty */
@@ -697,17 +697,17 @@ const Class MappedArgumentsObject::class
 };
 
 /*
  * Unmapped arguments is significantly less magical than mapped arguments, so
  * it is represented by a different class while sharing some functionality.
  */
 const Class UnmappedArgumentsObject::class_ = {
     "Arguments",
-    JSCLASS_DELAY_METADATA_CALLBACK |
+    JSCLASS_DELAY_METADATA_BUILDER |
     JSCLASS_HAS_RESERVED_SLOTS(UnmappedArgumentsObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
     JSCLASS_SKIP_NURSERY_FINALIZE |
     JSCLASS_BACKGROUND_FINALIZE,
     nullptr,                 /* addProperty */
     ArgumentsObject::obj_delProperty,
     nullptr,                 /* getProperty */
     nullptr,                 /* setProperty */
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -93,17 +93,17 @@ js::ToClampedIndex(JSContext* cx, Handle
 
 const Class ArrayBufferObject::protoClass = {
     "ArrayBufferPrototype",
     JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer)
 };
 
 const Class ArrayBufferObject::class_ = {
     "ArrayBuffer",
-    JSCLASS_DELAY_METADATA_CALLBACK |
+    JSCLASS_DELAY_METADATA_BUILDER |
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer) |
     JSCLASS_BACKGROUND_FINALIZE,
     nullptr,                 /* addProperty */
     nullptr,                 /* delProperty */
     nullptr,                 /* getProperty */
     nullptr,                 /* setProperty */
     nullptr,                 /* enumerate */
--- a/js/src/vm/ArrayObject-inl.h
+++ b/js/src/vm/ArrayObject-inl.h
@@ -39,17 +39,17 @@ ArrayObject::createArrayInternal(Exclusi
 {
     // Create a new array and initialize everything except for its elements.
     MOZ_ASSERT(shape && group);
     MOZ_ASSERT(group->clasp() == shape->getObjectClass());
     MOZ_ASSERT(group->clasp() == &ArrayObject::class_);
     MOZ_ASSERT_IF(group->clasp()->finalize, heap == gc::TenuredHeap);
     MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(),
                   heap == js::gc::TenuredHeap);
-    MOZ_ASSERT(group->clasp()->shouldDelayMetadataCallback());
+    MOZ_ASSERT(group->clasp()->shouldDelayMetadataBuilder());
 
     // Arrays can use their fixed slots to store elements, so can't have shapes
     // which allow named properties to be stored in the fixed slots.
     MOZ_ASSERT(shape->numFixedSlots() == 0);
 
     size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan(), group->clasp());
     JSObject* obj = Allocate<JSObject>(cx, kind, nDynamicSlots, heap, group->clasp());
     if (!obj)
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2425,18 +2425,18 @@ Debugger::updateObservesAsmJSOnDebuggees
 }
 
 
 /*** Allocations Tracking *************************************************************************/
 
 /* static */ bool
 Debugger::cannotTrackAllocations(const GlobalObject& global)
 {
-    auto existingCallback = global.compartment()->getObjectMetadataCallback();
-    return existingCallback && existingCallback != SavedStacksMetadataCallback;
+    auto existingCallback = global.compartment()->getAllocationMetadataBuilder();
+    return existingCallback && existingCallback != &SavedStacks::metadataBuilder;
 }
 
 /* static */ bool
 Debugger::isObservedByDebuggerTrackingAllocations(const GlobalObject& debuggee)
 {
     if (auto* v = debuggee.getDebuggers()) {
         for (auto p = v->begin(); p != v->end(); p++) {
             if ((*p)->trackingAllocationSites && (*p)->enabled) {
@@ -2456,33 +2456,33 @@ Debugger::addAllocationsTracking(JSConte
     MOZ_ASSERT(isObservedByDebuggerTrackingAllocations(*debuggee));
 
     if (Debugger::cannotTrackAllocations(*debuggee)) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                              JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET);
         return false;
     }
 
-    debuggee->compartment()->setObjectMetadataCallback(SavedStacksMetadataCallback);
+    debuggee->compartment()->setAllocationMetadataBuilder(&SavedStacks::metadataBuilder);
     debuggee->compartment()->chooseAllocationSamplingProbability();
     return true;
 }
 
 /* static */ void
 Debugger::removeAllocationsTracking(GlobalObject& global)
 {
     // If there are still Debuggers that are observing allocations, we cannot
     // remove the metadata callback yet. Recompute the sampling probability
     // based on the remaining debuggers' needs.
     if (isObservedByDebuggerTrackingAllocations(global)) {
         global.compartment()->chooseAllocationSamplingProbability();
         return;
     }
 
-    global.compartment()->forgetObjectMetadataCallback();
+    global.compartment()->forgetAllocationMetadataBuilder();
 }
 
 bool
 Debugger::addAllocationsTrackingForAllDebuggees(JSContext* cx)
 {
     MOZ_ASSERT(trackingAllocationSites);
 
     // We don't want to end up in a state where we added allocations
@@ -3480,17 +3480,17 @@ Debugger::addDebuggeeGlobal(JSContext* c
 
     /*
      * For global to become this js::Debugger's debuggee:
      *
      * 1. this js::Debugger must be in global->getDebuggers(),
      * 2. global must be in this->debuggees,
      * 3. it must be in zone->getDebuggers(),
      * 4. the debuggee's zone must be in this->debuggeeZones,
-     * 5. if we are tracking allocations, the SavedStacksMetadataCallback must be
+     * 5. if we are tracking allocations, the SavedStacksMetadataBuilder must be
      *    installed for this compartment, and
      * 6. JSCompartment::isDebuggee()'s bit must be set.
      *
      * All six indications must be kept consistent.
      */
 
     AutoCompartment ac(cx, global);
     Zone* zone = global->zone();
@@ -8001,17 +8001,17 @@ DebuggerObject_getGlobal(JSContext* cx, 
         return false;
     args.rval().set(v);
     return true;
 }
 
 /* static */ SavedFrame*
 Debugger::getObjectAllocationSite(JSObject& obj)
 {
-    JSObject* metadata = GetObjectMetadata(&obj);
+    JSObject* metadata = GetAllocationMetadata(&obj);
     if (!metadata)
         return nullptr;
 
     MOZ_ASSERT(!metadata->is<WrapperObject>());
     return SavedFrame::isSavedFrameAndNotProto(*metadata)
         ? &metadata->as<SavedFrame>()
         : nullptr;
 }
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -129,17 +129,17 @@ GlobalObject::ensureConstructor(JSContex
 GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key)
 {
     MOZ_ASSERT(!global->isStandardClassResolved(key));
 
     // Prohibit collection of allocation metadata. Metadata builders shouldn't
     // need to observe lazily-constructed prototype objects coming into
     // existence. And assertions start to fail when the builder itself attempts
     // an allocation that re-entrantly tries to create the same prototype.
-    AutoSuppressObjectMetadataCallback suppressMetadata(cx);
+    AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
 
     // Constructor resolution may execute self-hosted scripts. These
     // self-hosted scripts do not call out to user code by construction. Allow
     // all scripts to execute, even in debuggee compartments that are paused.
     AutoSuppressDebuggeeNoExecuteChecks suppressNX(cx);
 
     // There are two different kinds of initialization hooks. One of them is
     // the class js::InitFoo hook, defined in a JSProtoKey-keyed table at the
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -457,17 +457,17 @@ bool
 js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options,
                               const char16_t* chars, size_t length,
                               JS::OffThreadCompileCallback callback, void* callbackData)
 {
     // Suppress GC so that calls below do not trigger a new incremental GC
     // which could require barriers on the atoms compartment.
     gc::AutoSuppressGC nogc(cx);
     gc::AutoAssertNoNurseryAlloc noNurseryAlloc(cx->runtime());
-    AutoSuppressObjectMetadataCallback suppressMetadata(cx);
+    AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
 
     JSObject* global = CreateGlobalForOffThreadParse(cx, ParseTaskKind::Script, nogc);
     if (!global)
         return false;
 
     ScopedJSDeletePtr<ExclusiveContext> helpercx(
         cx->new_<ExclusiveContext>(cx->runtime(), (PerThreadData*) nullptr,
                                    ExclusiveContext::Context_Exclusive));
@@ -494,17 +494,17 @@ bool
 js::StartOffThreadParseModule(JSContext* cx, const ReadOnlyCompileOptions& options,
                               const char16_t* chars, size_t length,
                               JS::OffThreadCompileCallback callback, void* callbackData)
 {
     // Suppress GC so that calls below do not trigger a new incremental GC
     // which could require barriers on the atoms compartment.
     gc::AutoSuppressGC nogc(cx);
     gc::AutoAssertNoNurseryAlloc noNurseryAlloc(cx->runtime());
-    AutoSuppressObjectMetadataCallback suppressMetadata(cx);
+    AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
 
     JSObject* global = CreateGlobalForOffThreadParse(cx, ParseTaskKind::Module, nogc);
     if (!global)
         return false;
 
     ScopedJSDeletePtr<ExclusiveContext> helpercx(
         cx->new_<ExclusiveContext>(cx->runtime(), (PerThreadData*) nullptr,
                                    ExclusiveContext::Context_Exclusive));
--- a/js/src/vm/ProxyObject.cpp
+++ b/js/src/vm/ProxyObject.cpp
@@ -15,17 +15,17 @@ using namespace js;
 ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler, HandleValue priv, TaggedProto proto_,
                  const ProxyOptions& options)
 {
     Rooted<TaggedProto> proto(cx, proto_);
 
     const Class* clasp = options.clasp();
 
     MOZ_ASSERT(isValidProxyClass(clasp));
-    MOZ_ASSERT(clasp->shouldDelayMetadataCallback());
+    MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
     MOZ_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
 
     /*
      * Eagerly mark properties unknown for proxies, so we don't try to track
      * their properties and so that we don't need to walk the compartment if
      * their prototype changes later.  But don't do this for DOM proxies,
      * because we want to be able to keep track of them in typesets in useful
      * ways.
--- a/js/src/vm/Runtime-inl.h
+++ b/js/src/vm/Runtime-inl.h
@@ -62,17 +62,17 @@ NewObjectCache::newObjectFromHit(JSConte
 
     NativeObject* obj = static_cast<NativeObject*>(Allocate<JSObject, NoGC>(cx, entry->kind, 0,
                                                                             heap, group->clasp()));
     if (!obj)
         return nullptr;
 
     copyCachedToObject(obj, templateObj, entry->kind);
 
-    if (group->clasp()->shouldDelayMetadataCallback())
+    if (group->clasp()->shouldDelayMetadataBuilder())
         cx->compartment()->setObjectPendingMetadata(cx, obj);
     else
         obj = static_cast<NativeObject*>(SetNewObjectMetadata(cx, obj));
 
     probes::CreateObject(cx, obj);
     gc::TraceCreateObject(obj);
     return obj;
 }
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -482,17 +482,17 @@ SavedFrame::initFromLookup(SavedFrame::H
 
 /* static */ SavedFrame*
 SavedFrame::create(JSContext* cx)
 {
     RootedGlobalObject global(cx, cx->global());
     assertSameCompartment(cx, global);
 
     // Ensure that we don't try to capture the stack again in the
-    // `SavedStacksMetadataCallback` for this new SavedFrame object, and
+    // `SavedStacksMetadataBuilder` for this new SavedFrame object, and
     // accidentally cause O(n^2) behavior.
     SavedStacks::AutoReentrancyGuard guard(cx->compartment()->savedStacks());
 
     RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global));
     if (!proto)
         return nullptr;
     assertSameCompartment(cx, proto);
 
@@ -1470,36 +1470,38 @@ SavedStacks::chooseSamplingProbability(J
         bernoulli.setRandomState(seed[0], seed[1]);
         bernoulliSeeded = true;
     }
 
     bernoulli.setProbability(probability);
 }
 
 JSObject*
-SavedStacksMetadataCallback(JSContext* cx, HandleObject target)
+SavedStacks::MetadataBuilder::build(JSContext* cx, HandleObject target,
+                                    AutoEnterOOMUnsafeRegion& oomUnsafe) const
 {
     RootedObject obj(cx, target);
 
     SavedStacks& stacks = cx->compartment()->savedStacks();
     if (!stacks.bernoulli.trial())
         return nullptr;
 
-    AutoEnterOOMUnsafeRegion oomUnsafe;
     RootedSavedFrame frame(cx);
     if (!stacks.saveCurrentStack(cx, &frame))
-        oomUnsafe.crash("SavedStacksMetadataCallback");
+        oomUnsafe.crash("SavedStacksMetadataBuilder");
 
     if (!Debugger::onLogAllocationSite(cx, obj, frame, JS_GetCurrentEmbedderTime()))
-        oomUnsafe.crash("SavedStacksMetadataCallback");
+        oomUnsafe.crash("SavedStacksMetadataBuilder");
 
     MOZ_ASSERT_IF(frame, !frame->is<WrapperObject>());
     return frame;
 }
 
+const SavedStacks::MetadataBuilder SavedStacks::metadataBuilder;
+
 #ifdef JS_CRASH_DIAGNOSTICS
 void
 CompartmentChecker::check(SavedStacks* stacks)
 {
     if (&compartment->savedStacks() != stacks) {
         printf("*** Compartment SavedStacks mismatch: %p vs. %p\n",
                (void*) &compartment->savedStacks(), stacks);
         MOZ_CRASH();
--- a/js/src/vm/SavedStacks.h
+++ b/js/src/vm/SavedStacks.h
@@ -144,17 +144,16 @@ namespace js {
 // In the case of z, the `SavedFrame` accessors are called with the `SavedFrame`
 // object in the `this` value, and the content compartment as the cx's current
 // compartment. Similar to the case of y, only the B and C frames are exposed
 // because the cx's current compartment's principals do not subsume A's captured
 // principals.
 
 class SavedStacks {
     friend class SavedFrame;
-    friend JSObject* SavedStacksMetadataCallback(JSContext* cx, HandleObject target);
     friend bool JS::ubi::ConstructSavedFrameStackSlow(JSContext* cx,
                                                       JS::ubi::StackFrame& ubiFrame,
                                                       MutableHandleObject outSavedFrameStack);
 
   public:
     SavedStacks()
       : frames(),
         bernoulliSeeded(false),
@@ -175,16 +174,26 @@ class SavedStacks {
 
     // Set the sampling random number generator's state to |state0| and
     // |state1|. One or the other must be non-zero. See the comments for
     // mozilla::non_crypto::XorShift128PlusRNG::setState for details.
     void     setRNGState(uint64_t state0, uint64_t state1) { bernoulli.setRandomState(state0, state1); }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
+    // An alloction metadata builder that marks cells with the JavaScript stack
+    // at which they were allocated.
+    struct MetadataBuilder : public AllocationMetadataBuilder {
+        MetadataBuilder() : AllocationMetadataBuilder() { }
+        virtual JSObject* build(JSContext *cx, HandleObject obj,
+                                AutoEnterOOMUnsafeRegion& oomUnsafe) const override;
+    };
+
+    static const MetadataBuilder metadataBuilder;
+
   private:
     SavedFrame::Set frames;
     bool bernoulliSeeded;
     mozilla::FastBernoulliTrial bernoulli;
     bool creatingSavedFrame;
 
     // Similar to mozilla::ReentrancyGuard, but instead of asserting against
     // reentrancy, just change the behavior of SavedStacks::saveCurrentStack to
@@ -294,18 +303,16 @@ class SavedStacks {
     // removes the dead script; the second will clear out the source atom since
     // it is no longer held by the table.
     using PCLocationMap = GCHashMap<PCKey, LocationValue, PCLocationHasher, SystemAllocPolicy>;
     PCLocationMap pcLocationMap;
 
     bool getLocation(JSContext* cx, const FrameIter& iter, MutableHandle<LocationValue> locationp);
 };
 
-JSObject* SavedStacksMetadataCallback(JSContext* cx, HandleObject target);
-
 template <>
 class RootedBase<SavedStacks::LocationValue>
   : public SavedStacks::MutableLocationValueOperations<JS::Rooted<SavedStacks::LocationValue>>
 {};
 
 template <>
 class MutableHandleBase<SavedStacks::LocationValue>
   : public SavedStacks::MutableLocationValueOperations<JS::MutableHandle<SavedStacks::LocationValue>>
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -343,17 +343,17 @@ SharedArrayBufferObject::addSizeOfExclud
 
 const Class SharedArrayBufferObject::protoClass = {
     "SharedArrayBufferPrototype",
     JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer)
 };
 
 const Class SharedArrayBufferObject::class_ = {
     "SharedArrayBuffer",
-    JSCLASS_DELAY_METADATA_CALLBACK |
+    JSCLASS_DELAY_METADATA_BUILDER |
     JSCLASS_HAS_RESERVED_SLOTS(SharedArrayBufferObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* getProperty */
     nullptr, /* setProperty */
     nullptr, /* enumerate */
     nullptr, /* resolve */
--- a/js/src/vm/TypeInference-inl.h
+++ b/js/src/vm/TypeInference-inl.h
@@ -281,17 +281,17 @@ struct AutoEnterAnalysis
 
     // Allow clearing inference info on OOM during incremental sweeping.
     AutoClearTypeInferenceStateOnOOM oom;
 
     // Pending recompilations to perform before execution of JIT code can resume.
     RecompileInfoVector pendingRecompiles;
 
     // Prevent us from calling the objectMetadataCallback.
-    js::AutoSuppressObjectMetadataCallback suppressMetadata;
+    js::AutoSuppressAllocationMetadataBuilder suppressMetadata;
 
     FreeOp* freeOp;
     Zone* zone;
 
     explicit AutoEnterAnalysis(ExclusiveContext* cx)
       : suppressGC(cx), oom(cx->zone()), suppressMetadata(cx)
     {
         init(cx->defaultFreeOp(), cx->zone());
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1933,17 +1933,17 @@ static const ClassSpec TypedArrayObjectC
 };
 
 #define IMPL_TYPED_ARRAY_CLASS(_type)                                          \
 {                                                                              \
     #_type "Array",                                                            \
     JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) |             \
     JSCLASS_HAS_PRIVATE |                                                      \
     JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array) |                         \
-    JSCLASS_DELAY_METADATA_CALLBACK,                                           \
+    JSCLASS_DELAY_METADATA_BUILDER,                                            \
     nullptr,                 /* addProperty */                                 \
     nullptr,                 /* delProperty */                                 \
     nullptr,                 /* getProperty */                                 \
     nullptr,                 /* setProperty */                                 \
     nullptr,                 /* enumerate   */                                 \
     nullptr,                 /* resolve     */                                 \
     nullptr,                 /* mayResolve  */                                 \
     nullptr,                 /* finalize    */                                 \
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -919,17 +919,17 @@ static const ObjectOps UnboxedPlainObjec
     UnboxedPlainObject::obj_enumerate,
     nullptr    /* funToString */
 };
 
 const Class UnboxedPlainObject::class_ = {
     js_Object_str,
     Class::NON_NATIVE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
-    JSCLASS_DELAY_METADATA_CALLBACK,
+    JSCLASS_DELAY_METADATA_BUILDER,
     nullptr,        /* addProperty */
     nullptr,        /* delProperty */
     nullptr,        /* getProperty */
     nullptr,        /* setProperty */
     nullptr,        /* enumerate   */
     nullptr,        /* resolve     */
     nullptr,        /* mayResolve  */
     nullptr,        /* finalize    */
new file mode 100644
--- /dev/null
+++ b/layout/base/StaticPresData.cpp
@@ -0,0 +1,311 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/StaticPresData.h"
+
+#include "mozilla/Preferences.h"
+#include "nsPresContext.h"
+
+namespace mozilla {
+
+static StaticPresData* sSingleton = nullptr;
+
+void
+StaticPresData::Init()
+{
+  MOZ_ASSERT(!sSingleton);
+  sSingleton = new StaticPresData();
+}
+
+void
+StaticPresData::Shutdown()
+{
+  MOZ_ASSERT(sSingleton);
+  delete sSingleton;
+  sSingleton = nullptr;
+}
+
+StaticPresData*
+StaticPresData::Get()
+{
+  MOZ_ASSERT(sSingleton);
+  return sSingleton;
+}
+
+StaticPresData::StaticPresData()
+{
+  mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
+
+  mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THIN] = nsPresContext::CSSPixelsToAppUnits(1);
+  mBorderWidthTable[NS_STYLE_BORDER_WIDTH_MEDIUM] = nsPresContext::CSSPixelsToAppUnits(3);
+  mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THICK] = nsPresContext::CSSPixelsToAppUnits(5);
+}
+
+#define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
+ _pref.Assign(_s0); \
+ _pref.Append(_s1);
+
+static const char* const kGenericFont[] = {
+  ".variable.",
+  ".fixed.",
+  ".serif.",
+  ".sans-serif.",
+  ".monospace.",
+  ".cursive.",
+  ".fantasy."
+};
+
+// These are private, use the list in nsFont.h if you want a public list.
+enum {
+  eDefaultFont_Variable,
+  eDefaultFont_Fixed,
+  eDefaultFont_Serif,
+  eDefaultFont_SansSerif,
+  eDefaultFont_Monospace,
+  eDefaultFont_Cursive,
+  eDefaultFont_Fantasy,
+  eDefaultFont_COUNT
+};
+
+const LangGroupFontPrefs*
+StaticPresData::GetFontPrefsForLangHelper(nsIAtom *aLanguage,
+                                          const LangGroupFontPrefs* aPrefs) const
+{
+  // Get language group for aLanguage:
+  MOZ_ASSERT(aLanguage);
+  MOZ_ASSERT(mLangService);
+  MOZ_ASSERT(aPrefs);
+
+  nsresult rv = NS_OK;
+  nsIAtom *langGroupAtom = nullptr;
+  langGroupAtom = mLangService->GetLanguageGroup(aLanguage, &rv);
+  if (NS_FAILED(rv) || !langGroupAtom) {
+    langGroupAtom = nsGkAtoms::x_western; // Assume x-western is safe...
+  }
+
+  LangGroupFontPrefs *prefs = const_cast<LangGroupFontPrefs*>(aPrefs);
+  if (prefs->mLangGroup) { // if initialized
+    DebugOnly<uint32_t> count = 0;
+    for (;;) {
+      NS_ASSERTION(++count < 35, "Lang group count exceeded!!!");
+      if (prefs->mLangGroup == langGroupAtom) {
+        return prefs;
+      }
+      if (!prefs->mNext) {
+        break;
+      }
+      prefs = prefs->mNext;
+    }
+
+    // nothing cached, so go on and fetch the prefs for this lang group:
+    prefs = prefs->mNext = new LangGroupFontPrefs;
+  }
+
+  prefs->mLangGroup = langGroupAtom;
+
+  /* Fetch the font prefs to be used -- see bug 61883 for details.
+     Not all prefs are needed upfront. Some are fallback prefs intended
+     for the GFX font sub-system...
+
+  1) unit : assumed to be the same for all language groups -------------
+  font.size.unit = px | pt    XXX could be folded in the size... bug 90440
+
+  2) attributes for generic fonts --------------------------------------
+  font.default.[langGroup] = serif | sans-serif - fallback generic font
+  font.name.[generic].[langGroup] = current user' selected font on the pref dialog
+  font.name-list.[generic].[langGroup] = fontname1, fontname2, ... [factory pre-built list]
+  font.size.[generic].[langGroup] = integer - settable by the user
+  font.size-adjust.[generic].[langGroup] = "float" - settable by the user
+  font.minimum-size.[langGroup] = integer - settable by the user
+  */
+
+  nsAutoCString langGroup;
+  langGroupAtom->ToUTF8String(langGroup);
+
+  prefs->mDefaultVariableFont.size = nsPresContext::CSSPixelsToAppUnits(16);
+  prefs->mDefaultFixedFont.size = nsPresContext::CSSPixelsToAppUnits(13);
+
+  nsAutoCString pref;
+
+  // get the current applicable font-size unit
+  enum {eUnit_unknown = -1, eUnit_px, eUnit_pt};
+  int32_t unit = eUnit_px;
+
+  nsAdoptingCString cvalue =
+    Preferences::GetCString("font.size.unit");
+
+  if (!cvalue.IsEmpty()) {
+    if (cvalue.EqualsLiteral("px")) {
+      unit = eUnit_px;
+    }
+    else if (cvalue.EqualsLiteral("pt")) {
+      unit = eUnit_pt;
+    }
+    else {
+      // XXX should really send this warning to the user (Error Console?).
+      // And just default to unit = eUnit_px?
+      NS_WARNING("unexpected font-size unit -- expected: 'px' or 'pt'");
+      unit = eUnit_unknown;
+    }
+  }
+
+  // get font.minimum-size.[langGroup]
+
+  MAKE_FONT_PREF_KEY(pref, "font.minimum-size.", langGroup);
+
+  int32_t size = Preferences::GetInt(pref.get());
+  if (unit == eUnit_px) {
+    prefs->mMinimumFontSize = nsPresContext::CSSPixelsToAppUnits(size);
+  }
+  else if (unit == eUnit_pt) {
+    prefs->mMinimumFontSize = nsPresContext::CSSPointsToAppUnits(size);
+  }
+
+  nsFont* fontTypes[] = {
+    &prefs->mDefaultVariableFont,
+    &prefs->mDefaultFixedFont,
+    &prefs->mDefaultSerifFont,
+    &prefs->mDefaultSansSerifFont,
+    &prefs->mDefaultMonospaceFont,
+    &prefs->mDefaultCursiveFont,
+    &prefs->mDefaultFantasyFont
+  };
+  static_assert(MOZ_ARRAY_LENGTH(fontTypes) == eDefaultFont_COUNT,
+                "FontTypes array count is not correct");
+
+  // Get attributes specific to each generic font. We do not get the user's
+  // generic-font-name-to-specific-family-name preferences because its the
+  // generic name that should be fed into the cascade. It is up to the GFX
+  // code to look up the font prefs to convert generic names to specific
+  // family names as necessary.
+  nsAutoCString generic_dot_langGroup;
+  for (uint32_t eType = 0; eType < ArrayLength(fontTypes); ++eType) {
+    generic_dot_langGroup.Assign(kGenericFont[eType]);
+    generic_dot_langGroup.Append(langGroup);
+
+    nsFont* font = fontTypes[eType];
+
+    // set the default variable font (the other fonts are seen as 'generic' fonts
+    // in GFX and will be queried there when hunting for alternative fonts)
+    if (eType == eDefaultFont_Variable) {
+      MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
+
+      nsAdoptingString value = Preferences::GetString(pref.get());
+      if (!value.IsEmpty()) {
+        FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
+        FontFamilyType defaultType = defaultVariableName.mType;
+        NS_ASSERTION(defaultType == eFamily_serif ||
+                     defaultType == eFamily_sans_serif,
+                     "default type must be serif or sans-serif");
+        prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
+      }
+      else {
+        MAKE_FONT_PREF_KEY(pref, "font.default.", langGroup);
+        value = Preferences::GetString(pref.get());
+        if (!value.IsEmpty()) {
+          FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
+          FontFamilyType defaultType = defaultVariableName.mType;
+          NS_ASSERTION(defaultType == eFamily_serif ||
+                       defaultType == eFamily_sans_serif,
+                       "default type must be serif or sans-serif");
+          prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
+        }
+      }
+    }
+    else {
+      if (eType == eDefaultFont_Monospace) {
+        // This takes care of the confusion whereby people often expect "monospace"
+        // to have the same default font-size as "-moz-fixed" (this tentative
+        // size may be overwritten with the specific value for "monospace" when
+        // "font.size.monospace.[langGroup]" is read -- see below)
+        prefs->mDefaultMonospaceFont.size = prefs->mDefaultFixedFont.size;
+      }
+      else if (eType != eDefaultFont_Fixed) {
+        // all the other generic fonts are initialized with the size of the
+        // variable font, but their specific size can supersede later -- see below
+        font->size = prefs->mDefaultVariableFont.size;
+      }
+    }
+
+    // Bug 84398: for spec purists, a different font-size only applies to the
+    // .variable. and .fixed. fonts and the other fonts should get |font-size-adjust|.
+    // The problem is that only GfxWin has the support for |font-size-adjust|. So for
+    // parity, we enable the ability to set a different font-size on all platforms.
+
+    // get font.size.[generic].[langGroup]
+    // size=0 means 'Auto', i.e., generic fonts retain the size of the variable font
+    MAKE_FONT_PREF_KEY(pref, "font.size", generic_dot_langGroup);
+    size = Preferences::GetInt(pref.get());
+    if (size > 0) {
+      if (unit == eUnit_px) {
+        font->size = nsPresContext::CSSPixelsToAppUnits(size);
+      }
+      else if (unit == eUnit_pt) {
+        font->size = nsPresContext::CSSPointsToAppUnits(size);
+      }
+    }
+
+    // get font.size-adjust.[generic].[langGroup]
+    // XXX only applicable on GFX ports that handle |font-size-adjust|
+    MAKE_FONT_PREF_KEY(pref, "font.size-adjust", generic_dot_langGroup);
+    cvalue = Preferences::GetCString(pref.get());
+    if (!cvalue.IsEmpty()) {
+      font->sizeAdjust = (float)atof(cvalue.get());
+    }
+
+#ifdef DEBUG_rbs
+    printf("%s Family-list:%s size:%d sizeAdjust:%.2f\n",
+           generic_dot_langGroup.get(),
+           NS_ConvertUTF16toUTF8(font->name).get(), font->size,
+           font->sizeAdjust);
+#endif
+  }
+
+  return prefs;
+}
+
+const nsFont*
+StaticPresData::GetDefaultFontHelper(uint8_t aFontID, nsIAtom *aLanguage,
+                                     const LangGroupFontPrefs* aPrefs) const
+{
+  MOZ_ASSERT(aLanguage);
+  MOZ_ASSERT(aPrefs);
+
+  const nsFont *font;
+  switch (aFontID) {
+    // Special (our default variable width font and fixed width font)
+    case kPresContext_DefaultVariableFont_ID:
+      font = &aPrefs->mDefaultVariableFont;
+      break;
+    case kPresContext_DefaultFixedFont_ID:
+      font = &aPrefs->mDefaultFixedFont;
+      break;
+    // CSS
+    case kGenericFont_serif:
+      font = &aPrefs->mDefaultSerifFont;
+      break;
+    case kGenericFont_sans_serif:
+      font = &aPrefs->mDefaultSansSerifFont;
+      break;
+    case kGenericFont_monospace:
+      font = &aPrefs->mDefaultMonospaceFont;
+      break;
+    case kGenericFont_cursive:
+      font = &aPrefs->mDefaultCursiveFont;
+      break;
+    case kGenericFont_fantasy:
+      font = &aPrefs->mDefaultFantasyFont;
+      break;
+    default:
+      font = nullptr;
+      NS_ERROR("invalid arg");
+      break;
+  }
+  return font;
+}
+
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/base/StaticPresData.h
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_StaticPresData_h
+#define mozilla_StaticPresData_h
+
+#include "nsAutoPtr.h"
+#include "nsCoord.h"
+#include "nsCOMPtr.h"
+#include "nsFont.h"
+#include "nsIAtom.h"
+#include "nsILanguageAtomService.h"
+
+namespace mozilla {
+
+struct LangGroupFontPrefs {
+  // Font sizes default to zero; they will be set in GetFontPreferences
+  LangGroupFontPrefs()
+    : mLangGroup(nullptr)
+    , mMinimumFontSize(0)
+    , mDefaultVariableFont(mozilla::eFamily_serif, 0)
+    , mDefaultFixedFont(mozilla::eFamily_monospace, 0)
+    , mDefaultSerifFont(mozilla::eFamily_serif, 0)
+    , mDefaultSansSerifFont(mozilla::eFamily_sans_serif, 0)
+    , mDefaultMonospaceFont(mozilla::eFamily_monospace, 0)
+    , mDefaultCursiveFont(mozilla::eFamily_cursive, 0)
+    , mDefaultFantasyFont(mozilla::eFamily_fantasy, 0)
+  {}
+
+  void Reset()
+  {
+    // Throw away any other LangGroupFontPrefs objects:
+    mNext = nullptr;
+
+    // Make GetFontPreferences reinitialize mLangGroupFontPrefs:
+    mLangGroup = nullptr;
+  }
+
+  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
+    size_t n = 0;
+    LangGroupFontPrefs* curr = mNext;
+    while (curr) {
+      n += aMallocSizeOf(curr);
+
+      // Measurement of the following members may be added later if DMD finds
+      // it is worthwhile:
+      // - mLangGroup
+      // - mDefault*Font
+
+      curr = curr->mNext;
+    }
+    return n;
+  }
+
+  nsCOMPtr<nsIAtom> mLangGroup;
+  nscoord mMinimumFontSize;
+  nsFont mDefaultVariableFont;
+  nsFont mDefaultFixedFont;
+  nsFont mDefaultSerifFont;
+  nsFont mDefaultSansSerifFont;
+  nsFont mDefaultMonospaceFont;
+  nsFont mDefaultCursiveFont;
+  nsFont mDefaultFantasyFont;
+  nsAutoPtr<LangGroupFontPrefs> mNext;
+};
+
+/**
+ * Some functionality that has historically lived on nsPresContext does not
+ * actually need to be per-document. This singleton class serves as a host
+ * for that functionality. We delegate to it from nsPresContext where
+ * appropriate, and use it standalone in some cases as well.
+ */
+class StaticPresData
+{
+public:
+  // Initialization and shutdown of the singleton. Called exactly once.
+  static void Init();
+  static void Shutdown();
+
+  // Gets an instance of the singleton. Infallible between the calls to Init
+  // and Shutdown.
+  static StaticPresData* Get();
+
+  /**
+   * This table maps border-width enums 'thin', 'medium', 'thick'
+   * to actual nscoord values.
+   */
+  const nscoord* GetBorderWidthTable() { return mBorderWidthTable; }
+
+  /**
+   * Fetch the user's font preferences for the given aLanguage's
+   * langugage group.
+   *
+   * The original code here is pretty old, and includes an optimization
+   * whereby language-specific prefs are read per-document, and the
+   * results are stored in a linked list, which is assumed to be very short
+   * since most documents only ever use one language.
+   *
+   * Storing this per-session rather than per-document would almost certainly
+   * be fine. But just to be on the safe side, we leave the old mechanism as-is,
+   * with an additional per-session cache that new callers can use if they don't
+   * have a PresContext.
+   */
+  const LangGroupFontPrefs* GetFontPrefsForLangHelper(nsIAtom* aLanguage,
+                                                      const LangGroupFontPrefs* aPrefs) const;
+  /**
+   * Get the default font for the given language and generic font ID.
+   * aLanguage may not be nullptr.
+   *
+   * This object is read-only, you must copy the font to modify it.
+   *
+   * When aFontID is kPresContext_DefaultVariableFontID or
+   * kPresContext_DefaultFixedFontID (which equals
+   * kGenericFont_moz_fixed, which is used for the -moz-fixed generic),
+   * the nsFont returned has its name as a CSS generic family (serif or
+   * sans-serif for the former, monospace for the latter), and its size
+   * as the default font size for variable or fixed fonts for the
+   * language group.
+   *
+   * For aFontID corresponding to a CSS Generic, the nsFont returned has
+   * its name set to that generic font's name, and its size set to
+   * the user's preference for font size for that generic and the
+   * given language.
+   */
+  const nsFont* GetDefaultFontHelper(uint8_t aFontID,
+                                     nsIAtom* aLanguage,
+                                     const LangGroupFontPrefs* aPrefs) const;
+
+  /*
+   * These versions operate on the font pref cache on StaticPresData.
+   */
+
+  const nsFont* GetDefaultFont(uint8_t aFontID, nsIAtom* aLanguage) const
+  {
+    MOZ_ASSERT(aLanguage);
+    return GetDefaultFontHelper(aFontID, aLanguage, GetFontPrefsForLang(aLanguage));
+  }
+  const LangGroupFontPrefs* GetFontPrefsForLang(nsIAtom* aLanguage) const
+  {
+    MOZ_ASSERT(aLanguage);
+    return GetFontPrefsForLangHelper(aLanguage, &mStaticLangGroupFontPrefs);
+  }
+
+  void ResetCachedFontPrefs() { mStaticLangGroupFontPrefs.Reset(); }
+
+private:
+  StaticPresData();
+  ~StaticPresData() {}
+
+  nsCOMPtr<nsILanguageAtomService> mLangService;
+  nscoord mBorderWidthTable[3];
+  LangGroupFontPrefs mStaticLangGroupFontPrefs;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_StaticPresData_h
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -104,16 +104,17 @@ EXPORTS.mozilla += [
     'ArenaRefPtrInlines.h',
     'GeometryUtils.h',
     'PaintTracker.h',
     'RestyleLogging.h',
     'RestyleManager.h',
     'RestyleManagerHandle.h',
     'RestyleManagerHandleInlines.h',
     'ServoRestyleManager.h',
+    'StaticPresData.h',
 ]
 
 UNIFIED_SOURCES += [
     'AccessibleCaret.cpp',
     'AccessibleCaretEventHub.cpp',
     'AccessibleCaretManager.cpp',
     'ActiveLayerTracker.cpp',
     'DisplayItemClip.cpp',
@@ -149,16 +150,17 @@ UNIFIED_SOURCES += [
     'nsStyleSheetService.cpp',
     'PaintTracker.cpp',
     'PositionedEventTargeting.cpp',
     'RestyleManager.cpp',
     'RestyleTracker.cpp',
     'ScrollbarStyles.cpp',
     'ServoRestyleManager.cpp',
     'StackArena.cpp',
+    'StaticPresData.cpp',
     'TouchManager.cpp',
     'ZoomConstraintsClient.cpp',
 ]
 
 # nsPresArena.cpp needs to be built separately because it uses plarena.h.
 # nsRefreshDriver.cpp needs to be built separately because of name clashes in the OS X headers
 SOURCES += [
     'nsPresArena.cpp',
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -392,251 +392,30 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   // NS_RELEASE(tmp->mLanguage); // an atom
   // NS_IMPL_CYCLE_COLLECTION_UNLINK(mTheme); // a service
   // NS_IMPL_CYCLE_COLLECTION_UNLINK(mLangService); // a service
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrintSettings);
 
   tmp->Destroy();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-
-#define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
- _pref.Assign(_s0); \
- _pref.Append(_s1);
-
-static const char* const kGenericFont[] = {
-  ".variable.",
-  ".fixed.",
-  ".serif.",
-  ".sans-serif.",
-  ".monospace.",
-  ".cursive.",
-  ".fantasy."
-};
-
 // whether no native theme service exists;
 // if this gets set to true, we'll stop asking for it.
 static bool sNoTheme = false;
 
 // Set to true when LookAndFeelChanged needs to be called.  This is used
 // because the look and feel is a service, so there's no need to notify it from
 // more than one prescontext.
 static bool sLookAndFeelChanged;
 
 // Set to true when ThemeChanged needs to be called on mTheme.  This is used
 // because mTheme is a service, so there's no need to notify it from more than
 // one prescontext.
 static bool sThemeChanged;
 
-const nsPresContext::LangGroupFontPrefs*
-nsPresContext::GetFontPrefsForLang(nsIAtom *aLanguage) const
-{
-  // Get language group for aLanguage:
-
-  nsresult rv = NS_OK;
-  nsIAtom *langGroupAtom = nullptr;
-  if (!aLanguage) {
-    aLanguage = mLanguage;
-  }
-  if (aLanguage && mLangService) {
-    langGroupAtom = mLangService->GetLanguageGroup(aLanguage, &rv);
-  }
-  if (NS_FAILED(rv) || !langGroupAtom) {
-    langGroupAtom = nsGkAtoms::x_western; // Assume x-western is safe...
-  }
-
-  // Look for cached prefs for this lang group.
-  // Most documents will only use one (or very few) language groups. Rather
-  // than have the overhead of a hash lookup, we simply look along what will
-  // typically be a very short (usually of length 1) linked list. There are 31
-  // language groups, so in the worst case scenario we'll need to traverse 31
-  // link items.
-
-  LangGroupFontPrefs *prefs =
-    const_cast<LangGroupFontPrefs*>(&mLangGroupFontPrefs);
-  if (prefs->mLangGroup) { // if initialized
-    DebugOnly<uint32_t> count = 0;
-    for (;;) {
-      NS_ASSERTION(++count < 35, "Lang group count exceeded!!!");
-      if (prefs->mLangGroup == langGroupAtom) {
-        return prefs;
-      }
-      if (!prefs->mNext) {
-        break;
-      }
-      prefs = prefs->mNext;
-    }
-
-    // nothing cached, so go on and fetch the prefs for this lang group:
-    prefs = prefs->mNext = new LangGroupFontPrefs;
-  }
-
-  prefs->mLangGroup = langGroupAtom;
-
-  /* Fetch the font prefs to be used -- see bug 61883 for details.
-     Not all prefs are needed upfront. Some are fallback prefs intended
-     for the GFX font sub-system...
-
-  1) unit : assumed to be the same for all language groups -------------
-  font.size.unit = px | pt    XXX could be folded in the size... bug 90440
-
-  2) attributes for generic fonts --------------------------------------
-  font.default.[langGroup] = serif | sans-serif - fallback generic font
-  font.name.[generic].[langGroup] = current user' selected font on the pref dialog
-  font.name-list.[generic].[langGroup] = fontname1, fontname2, ... [factory pre-built list]
-  font.size.[generic].[langGroup] = integer - settable by the user
-  font.size-adjust.[generic].[langGroup] = "float" - settable by the user
-  font.minimum-size.[langGroup] = integer - settable by the user
-  */
-
-  nsAutoCString langGroup;
-  langGroupAtom->ToUTF8String(langGroup);
-
-  prefs->mDefaultVariableFont.size = CSSPixelsToAppUnits(16);
-  prefs->mDefaultFixedFont.size = CSSPixelsToAppUnits(13);
-
-  nsAutoCString pref;
-
-  // get the current applicable font-size unit
-  enum {eUnit_unknown = -1, eUnit_px, eUnit_pt};
-  int32_t unit = eUnit_px;
-
-  nsAdoptingCString cvalue =
-    Preferences::GetCString("font.size.unit");
-
-  if (!cvalue.IsEmpty()) {
-    if (cvalue.EqualsLiteral("px")) {
-      unit = eUnit_px;
-    }
-    else if (cvalue.EqualsLiteral("pt")) {
-      unit = eUnit_pt;
-    }
-    else {
-      // XXX should really send this warning to the user (Error Console?).
-      // And just default to unit = eUnit_px?
-      NS_WARNING("unexpected font-size unit -- expected: 'px' or 'pt'");
-      unit = eUnit_unknown;
-    }
-  }
-
-  // get font.minimum-size.[langGroup]
-
-  MAKE_FONT_PREF_KEY(pref, "font.minimum-size.", langGroup);
-
-  int32_t size = Preferences::GetInt(pref.get());
-  if (unit == eUnit_px) {
-    prefs->mMinimumFontSize = CSSPixelsToAppUnits(size);
-  }
-  else if (unit == eUnit_pt) {
-    prefs->mMinimumFontSize = CSSPointsToAppUnits(size);
-  }
-
-  nsFont* fontTypes[] = {
-    &prefs->mDefaultVariableFont,
-    &prefs->mDefaultFixedFont,
-    &prefs->mDefaultSerifFont,
-    &prefs->mDefaultSansSerifFont,
-    &prefs->mDefaultMonospaceFont,
-    &prefs->mDefaultCursiveFont,
-    &prefs->mDefaultFantasyFont
-  };
-  static_assert(MOZ_ARRAY_LENGTH(fontTypes) == eDefaultFont_COUNT,
-                "FontTypes array count is not correct");
-
-  // Get attributes specific to each generic font. We do not get the user's
-  // generic-font-name-to-specific-family-name preferences because its the
-  // generic name that should be fed into the cascade. It is up to the GFX
-  // code to look up the font prefs to convert generic names to specific
-  // family names as necessary.
-  nsAutoCString generic_dot_langGroup;
-  for (uint32_t eType = 0; eType < ArrayLength(fontTypes); ++eType) {
-    generic_dot_langGroup.Assign(kGenericFont[eType]);
-    generic_dot_langGroup.Append(langGroup);
-
-    nsFont* font = fontTypes[eType];
-
-    // set the default variable font (the other fonts are seen as 'generic' fonts
-    // in GFX and will be queried there when hunting for alternative fonts)
-    if (eType == eDefaultFont_Variable) {
-      MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
-
-      nsAdoptingString value = Preferences::GetString(pref.get());
-      if (!value.IsEmpty()) {
-        FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
-        FontFamilyType defaultType = defaultVariableName.mType;
-        NS_ASSERTION(defaultType == eFamily_serif ||
-                     defaultType == eFamily_sans_serif,
-                     "default type must be serif or sans-serif");
-        prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
-      }
-      else {
-        MAKE_FONT_PREF_KEY(pref, "font.default.", langGroup);
-        value = Preferences::GetString(pref.get());
-        if (!value.IsEmpty()) {
-          FontFamilyName defaultVariableName = FontFamilyName::Convert(value);
-          FontFamilyType defaultType = defaultVariableName.mType;
-          NS_ASSERTION(defaultType == eFamily_serif ||
-                       defaultType == eFamily_sans_serif,
-                       "default type must be serif or sans-serif");
-          prefs->mDefaultVariableFont.fontlist = FontFamilyList(defaultType);
-        }
-      }
-    }
-    else {
-      if (eType == eDefaultFont_Monospace) {
-        // This takes care of the confusion whereby people often expect "monospace"
-        // to have the same default font-size as "-moz-fixed" (this tentative
-        // size may be overwritten with the specific value for "monospace" when
-        // "font.size.monospace.[langGroup]" is read -- see below)
-        prefs->mDefaultMonospaceFont.size = prefs->mDefaultFixedFont.size;
-      }
-      else if (eType != eDefaultFont_Fixed) {
-        // all the other generic fonts are initialized with the size of the
-        // variable font, but their specific size can supersede later -- see below
-        font->size = prefs->mDefaultVariableFont.size;
-      }
-    }
-
-    // Bug 84398: for spec purists, a different font-size only applies to the
-    // .variable. and .fixed. fonts and the other fonts should get |font-size-adjust|.
-    // The problem is that only GfxWin has the support for |font-size-adjust|. So for
-    // parity, we enable the ability to set a different font-size on all platforms.
-
-    // get font.size.[generic].[langGroup]
-    // size=0 means 'Auto', i.e., generic fonts retain the size of the variable font
-    MAKE_FONT_PREF_KEY(pref, "font.size", generic_dot_langGroup);
-    size = Preferences::GetInt(pref.get());
-    if (size > 0) {
-      if (unit == eUnit_px) {
-        font->size = CSSPixelsToAppUnits(size);
-      }
-      else if (unit == eUnit_pt) {
-        font->size = CSSPointsToAppUnits(size);
-      }
-    }
-
-    // get font.size-adjust.[generic].[langGroup]
-    // XXX only applicable on GFX ports that handle |font-size-adjust|
-    MAKE_FONT_PREF_KEY(pref, "font.size-adjust", generic_dot_langGroup);
-    cvalue = Preferences::GetCString(pref.get());
-    if (!cvalue.IsEmpty()) {
-      font->sizeAdjust = (float)atof(cvalue.get());
-    }
-
-#ifdef DEBUG_rbs
-    printf("%s Family-list:%s size:%d sizeAdjust:%.2f\n",
-           generic_dot_langGroup.get(),
-           NS_ConvertUTF16toUTF8(font->name).get(), font->size,
-           font->sizeAdjust);
-#endif
-  }
-
-  return prefs;
-}
-
 void
 nsPresContext::GetDocumentColorPreferences()
 {
   // Make sure the preferences are initialized.  In the normal run,
   // they would already be, because gfxPlatform would have been created,
   // but in some reference tests, that is not the case.
   gfxPrefs::GetSingleton();
 
@@ -795,17 +574,18 @@ nsPresContext::GetUserPreferences()
   mBodyTextColor = mDefaultColor;
 
   // * use fonts?
   mUseDocumentFonts =
     Preferences::GetInt("browser.display.use_document_fonts") != 0;
 
   mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
 
-  ResetCachedFontPrefs();
+  mLangGroupFontPrefs.Reset();
+  StaticPresData::Get()->ResetCachedFontPrefs();
 
   // * image animation
   const nsAdoptingCString& animatePref =
     Preferences::GetCString("image.animation_mode");
   if (animatePref.EqualsLiteral("normal"))
     mImageAnimationModePref = imgIContainer::kNormalAnimMode;
   else if (animatePref.EqualsLiteral("none"))
     mImageAnimationModePref = imgIContainer::kDontAnimMode;
@@ -1231,17 +1011,17 @@ nsPresContext::UpdateCharSet(const nsCSt
   if (mLangService) {
     mLanguage = mLangService->LookupCharSet(aCharSet);
     // this will be a language group (or script) code rather than a true language code
 
     // bug 39570: moved from nsLanguageAtomService::LookupCharSet()
     if (mLanguage == nsGkAtoms::Unicode) {
       mLanguage = mLangService->GetLocaleLanguage();
     }
-    ResetCachedFontPrefs();
+    mLangGroupFontPrefs.Reset();
   }
 
   switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
 
     case IBMBIDI_TEXTTYPE_LOGICAL:
       SetVisualMode(false);
       break;
 
@@ -1470,54 +1250,16 @@ nsPresContext::SetImageAnimationModeInte
 }
 
 void
 nsPresContext::SetImageAnimationModeExternal(uint16_t aMode)
 {
   SetImageAnimationModeInternal(aMode);
 }
 
-const nsFont*
-nsPresContext::GetDefaultFont(uint8_t aFontID, nsIAtom *aLanguage) const
-{
-  const LangGroupFontPrefs *prefs = GetFontPrefsForLang(aLanguage);
-
-  const nsFont *font;
-  switch (aFontID) {
-    // Special (our default variable width font and fixed width font)
-    case kPresContext_DefaultVariableFont_ID:
-      font = &prefs->mDefaultVariableFont;
-      break;
-    case kPresContext_DefaultFixedFont_ID:
-      font = &prefs->mDefaultFixedFont;
-      break;
-    // CSS
-    case kGenericFont_serif:
-      font = &prefs->mDefaultSerifFont;
-      break;
-    case kGenericFont_sans_serif:
-      font = &prefs->mDefaultSansSerifFont;
-      break;
-    case kGenericFont_monospace:
-      font = &prefs->mDefaultMonospaceFont;
-      break;
-    case kGenericFont_cursive:
-      font = &prefs->mDefaultCursiveFont;
-      break;
-    case kGenericFont_fantasy:
-      font = &prefs->mDefaultFantasyFont;
-      break;
-    default:
-      font = nullptr;
-      NS_ERROR("invalid arg");
-      break;
-  }
-  return font;
-}
-
 already_AddRefed<nsIAtom>
 nsPresContext::GetContentLanguage() const
 {
   nsAutoString language;
   Document()->GetContentLanguage(language);
   language.StripWhitespace();
 
   // Content-Language may be a comma-separated list of language codes,
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -37,16 +37,17 @@
 #include "prclist.h"
 #include "nsThreadUtils.h"
 #include "ScrollbarStyles.h"
 #include "nsIMessageManager.h"
 #include "mozilla/RestyleLogging.h"
 #include "Units.h"
 #include "mozilla/RestyleManagerHandle.h"
 #include "prenv.h"
+#include "mozilla/StaticPresData.h"
 
 class nsAString;
 class nsIPrintSettings;
 class nsDocShell;
 class nsIDocShell;
 class nsIDocument;
 class nsILanguageAtomService;
 class nsITheme;
@@ -130,17 +131,19 @@ public:
 class nsRootPresContext;
 
 // An interface for presentation contexts. Presentation contexts are
 // objects that provide an outer context for a presentation shell.
 
 class nsPresContext : public nsIObserver {
 public:
   typedef mozilla::FramePropertyTable FramePropertyTable;
+  typedef mozilla::LangGroupFontPrefs LangGroupFontPrefs;
   typedef mozilla::ScrollbarStyles ScrollbarStyles;
+  typedef mozilla::StaticPresData StaticPresData;
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
   NS_DECL_CYCLE_COLLECTION_CLASS(nsPresContext)
 
   enum nsPresContextType {
     eContext_Galley,       // unpaginated screen presentation
@@ -360,33 +363,25 @@ public:
     if (mShell)
       mShell->FreeMisc(aSize, aFreeChunk);
   }
 
   /**
    * Get the default font for the given language and generic font ID.
    * If aLanguage is nullptr, the document's language is used.
    *
-   * This object is read-only, you must copy the font to modify it.
-   *
-   * When aFontID is kPresContext_DefaultVariableFontID or
-   * kPresContext_DefaultFixedFontID (which equals
-   * kGenericFont_moz_fixed, which is used for the -moz-fixed generic),
-   * the nsFont returned has its name as a CSS generic family (serif or
-   * sans-serif for the former, monospace for the latter), and its size
-   * as the default font size for variable or fixed fonts for the
-   * language group.
-   *
-   * For aFontID corresponding to a CSS Generic, the nsFont returned has
-   * its name set to that generic font's name, and its size set to
-   * the user's preference for font size for that generic and the
-   * given language.
+   * See the comment in StaticPresData::GetDefaultFont.
    */
   const nsFont* GetDefaultFont(uint8_t aFontID,
-                                           nsIAtom *aLanguage) const;
+                               nsIAtom *aLanguage) const
+  {
+    nsIAtom* lang = aLanguage ? aLanguage : mLanguage.get();
+    return StaticPresData::Get()->GetDefaultFontHelper(aFontID, lang,
+                                                       GetFontPrefsForLang(lang));
+  }
 
   /** Get a cached boolean pref, by its type */
   // *  - initially created for bugs 31816, 20760, 22963
   bool GetCachedBoolPref(nsPresContext_CachedBoolPrefType aPrefType) const
   {
     // If called with a constant parameter, the compiler should optimize
     // this switch statement away.
     switch (aPrefType) {
@@ -1120,74 +1115,24 @@ protected:
   void PreferenceChanged(const char* aPrefName);
   static void PrefChangedCallback(const char*, void*);
 
   void UpdateAfterPreferencesChanged();
   static void PrefChangedUpdateTimerCallback(nsITimer *aTimer, void *aClosure);
 
   void GetUserPreferences();
 
-  // Allow nsAutoPtr<LangGroupFontPrefs> dtor to access this protected struct's
-  // dtor:
-  struct LangGroupFontPrefs;
-  friend class nsAutoPtr<LangGroupFontPrefs>;
-  struct LangGroupFontPrefs {
-    // Font sizes default to zero; they will be set in GetFontPreferences
-    LangGroupFontPrefs()
-      : mLangGroup(nullptr)
-      , mMinimumFontSize(0)
-      , mDefaultVariableFont(mozilla::eFamily_serif, 0)
-      , mDefaultFixedFont(mozilla::eFamily_monospace, 0)
-      , mDefaultSerifFont(mozilla::eFamily_serif, 0)
-      , mDefaultSansSerifFont(mozilla::eFamily_sans_serif, 0)
-      , mDefaultMonospaceFont(mozilla::eFamily_monospace, 0)
-      , mDefaultCursiveFont(mozilla::eFamily_cursive, 0)
-      , mDefaultFantasyFont(mozilla::eFamily_fantasy, 0)
-    {}
-
-    size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
-      size_t n = 0;
-      LangGroupFontPrefs *curr = mNext;
-      while (curr) {
-        n += aMallocSizeOf(curr);
-
-        // Measurement of the following members may be added later if DMD finds
-        // it is worthwhile:
-        // - mLangGroup
-        // - mDefault*Font
-
-        curr = curr->mNext;
-      }
-      return n;
-    }
-
-    nsCOMPtr<nsIAtom> mLangGroup;
-    nscoord mMinimumFontSize;
-    nsFont mDefaultVariableFont;
-    nsFont mDefaultFixedFont;
-    nsFont mDefaultSerifFont;
-    nsFont mDefaultSansSerifFont;
-    nsFont mDefaultMonospaceFont;
-    nsFont mDefaultCursiveFont;
-    nsFont mDefaultFantasyFont;
-    nsAutoPtr<LangGroupFontPrefs> mNext;
-  };
-
   /**
    * Fetch the user's font preferences for the given aLanguage's
    * langugage group.
    */
-  const LangGroupFontPrefs* GetFontPrefsForLang(nsIAtom *aLanguage) const;
-
-  void ResetCachedFontPrefs() {
-    // Throw away any other LangGroupFontPrefs objects:
-    mLangGroupFontPrefs.mNext = nullptr;
-
-    // Make GetFontPreferences reinitialize mLangGroupFontPrefs:
-    mLangGroupFontPrefs.mLangGroup = nullptr;
+  const LangGroupFontPrefs* GetFontPrefsForLang(nsIAtom *aLanguage) const
+  {
+    nsIAtom* lang = aLanguage ? aLanguage : mLanguage.get();
+    return StaticPresData::Get()->GetFontPrefsForLangHelper(lang, &mLangGroupFontPrefs);
   }
 
   void UpdateCharSet(const nsCString& aCharSet);
 
 public:
   void DoChangeCharSet(const nsCString& aCharSet);
 
   /**
@@ -1327,16 +1272,21 @@ protected:
   ScrollbarStyles       mViewportStyleScrollbar;
   uint8_t               mFocusRingWidth;
 
   bool mExistThrottledUpdates;
 
   uint16_t              mImageAnimationMode;
   uint16_t              mImageAnimationModePref;
 
+  // Most documents will only use one (or very few) language groups. Rather
+  // than have the overhead of a hash lookup, we simply look along what will
+  // typically be a very short (usually of length 1) linked list. There are 31
+  // language groups, so in the worst case scenario we'll need to traverse 31
+  // link items.
   LangGroupFontPrefs    mLangGroupFontPrefs;
 
   nscoord               mBorderWidthTable[3];
 
   uint32_t              mInterruptChecksToSkip;
 
   // Counters for tests and tools that want to detect frame construction
   // or reflow.
@@ -1428,28 +1378,16 @@ protected:
   bool                  mInitialized;
 #endif
 
 
 protected:
 
   virtual ~nsPresContext();
 
-  // these are private, use the list in nsFont.h if you want a public list
-  enum {
-    eDefaultFont_Variable,
-    eDefaultFont_Fixed,
-    eDefaultFont_Serif,
-    eDefaultFont_SansSerif,
-    eDefaultFont_Monospace,
-    eDefaultFont_Cursive,
-    eDefaultFont_Fantasy,
-    eDefaultFont_COUNT
-  };
-
   nscolor MakeColorPref(const nsString& aColor);
 
   void LastRelease();
 
 #ifdef DEBUG
 private:
   friend struct nsAutoLayoutPhase;
   uint32_t mLayoutPhaseCount[eLayoutPhase_COUNT];
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5998,26 +5998,43 @@ PresShell::AssumeAllFramesVisible()
       "layout.framevisibility.enabled", true);
     sFrameVisibilityPrefCached = true;
   }
 
   if (!sFrameVisibilityEnabled || !mPresContext || !mDocument) {
     return true;
   }
 
-  // We assume all frames are visible in print, print preview, chrome, xul, and
+  // We assume all frames are visible in print, print preview, chrome, and
   // resource docs and don't keep track of them.
   if (mPresContext->Type() == nsPresContext::eContext_PrintPreview ||
       mPresContext->Type() == nsPresContext::eContext_Print ||
       mPresContext->IsChrome() ||
-      mDocument->IsResourceDoc() ||
-      mDocument->IsXULDocument()) {
+      mDocument->IsResourceDoc()) {
     return true;
   }
 
+  // If we're assuming all frames are visible in the top level content
+  // document, we need to in subdocuments as well. Otherwise we can get in a
+  // situation where things like animations won't work in subdocuments because
+  // their frames appear not to be visible, since we won't schedule an image
+  // visibility update if the top level content document is assuming all
+  // frames are visible.
+  //
+  // Note that it's not safe to call IsRootContentDocument() if we're
+  // currently being destroyed, so we have to check that first.
+  if (!mHaveShutDown && !mIsDestroying &&
+      !mPresContext->IsRootContentDocument()) {
+    nsPresContext* presContext =
+      mPresContext->GetToplevelContentDocumentPresContext();
+    if (presContext && presContext->PresShell()->AssumeAllFramesVisible()) {
+      return true;
+    }
+  }
+
   return false;
 }
 
 void
 PresShell::ScheduleApproximateFrameVisibilityUpdateSoon()
 {
   if (AssumeAllFramesVisible()) {
     return;
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -126,16 +126,17 @@ using namespace mozilla::system;
 #include "mozilla/IMEStateManager.h"
 #include "nsDocument.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "CameraPreferences.h"
 #include "TouchManager.h"
 #include "MediaDecoder.h"
 #include "mozilla/layers/CompositorLRU.h"
 #include "mozilla/dom/devicestorage/DeviceStorageStatics.h"
+#include "mozilla/StaticPresData.h"
 
 #ifdef MOZ_B2G_BT
 #include "mozilla/dom/BluetoothUUID.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::net;
 using namespace mozilla::dom;
@@ -192,16 +193,17 @@ nsLayoutStatics::Initialize()
   rv = nsTextFragment::Init();
   if (NS_FAILED(rv)) {
     NS_ERROR("Could not initialize nsTextFragment");
     return rv;
   }
 
   nsCellMap::Init();
 
+  StaticPresData::Init();
   nsCSSRendering::Init();
 
   nsTextFrameTextRunCache::Init();
 
   rv = nsHTMLDNSPrefetch::Initialize();
   if (NS_FAILED(rv)) {
     NS_ERROR("Could not initialize HTML DNS prefetch");
     return rv;
@@ -342,16 +344,17 @@ nsLayoutStatics::Shutdown()
   Attr::Shutdown();
   EventListenerManager::Shutdown();
   IMEStateManager::Shutdown();
   nsCSSParser::Shutdown();
   nsCSSRuleProcessor::Shutdown();
   nsTextFrameTextRunCache::Shutdown();
   nsHTMLDNSPrefetch::Shutdown();
   nsCSSRendering::Shutdown();
+  StaticPresData::Shutdown();
 #ifdef DEBUG
   nsFrame::DisplayReflowShutdown();
 #endif
   nsCellMap::Shutdown();
   ActiveLayerTracker::Shutdown();
 
   // Release all of our atoms
   nsColorNames::ReleaseTable();
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -73,16 +73,99 @@ kAxisOrientationToSidesMap[eNumAxisOrien
   { eSideLeft,   eSideRight  },  // eAxis_LR
   { eSideRight,  eSideLeft   },  // eAxis_RL
   { eSideTop,    eSideBottom },  // eAxis_TB
   { eSideBottom, eSideTop }      // eAxis_BT
 };
 
 // Helper structs / classes / methods
 // ==================================
+// Returns true iff the given nsStyleDisplay has display:-webkit-{inline-}-box.
+static inline bool
+IsDisplayValueLegacyBox(const nsStyleDisplay* aStyleDisp)
+{
+  return aStyleDisp->mDisplay == NS_STYLE_DISPLAY_WEBKIT_BOX ||
+    aStyleDisp->mDisplay == NS_STYLE_DISPLAY_WEBKIT_INLINE_BOX;
+}
+
+// Helper to check whether our nsFlexContainerFrame is emulating a legacy
+// -webkit-{inline-}box, in which case we should use legacy CSS properties
+// instead of the modern ones. The params are are the nsStyleDisplay and the
+// nsStyleContext associated with the nsFlexContainerFrame itself.
+static inline bool
+IsLegacyBox(const nsStyleDisplay* aStyleDisp,
+            nsStyleContext* aStyleContext)
+{
+  // Trivial case: just check "display" directly.
+  if (IsDisplayValueLegacyBox(aStyleDisp)) {
+    return true;
+  }
+
+  // If this frame is for a scrollable element, then it will actually have
+  // "display:block", and its *parent* will have the real flex-flavored display
+  // value. So in that case, check the parent to find out if we're legacy.
+  if (aStyleDisp->mDisplay == NS_STYLE_DISPLAY_BLOCK) {
+    nsStyleContext* parentStyleContext = aStyleContext->GetParent();
+    NS_ASSERTION(parentStyleContext &&
+                 aStyleContext->GetPseudo() == nsCSSAnonBoxes::scrolledContent,
+                 "The only way a nsFlexContainerFrame can have 'display:block' "
+                 "should be if it's the inner part of a scrollable element");
+    if (IsDisplayValueLegacyBox(parentStyleContext->StyleDisplay())) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// Returns the "align-items" value that's equivalent to the legacy "box-align"
+// value in the given style struct.
+static uint8_t
+ConvertLegacyStyleToAlignItems(const nsStyleXUL* aStyleXUL)
+{
+  // -[moz|webkit]-box-align corresponds to modern "align-items"
+  switch (aStyleXUL->mBoxAlign) {
+    case NS_STYLE_BOX_ALIGN_STRETCH:
+      return NS_STYLE_ALIGN_STRETCH;
+    case NS_STYLE_BOX_ALIGN_START:
+      return NS_STYLE_ALIGN_FLEX_START;
+    case NS_STYLE_BOX_ALIGN_CENTER:
+      return NS_STYLE_ALIGN_CENTER;
+    case NS_STYLE_BOX_ALIGN_BASELINE:
+      return NS_STYLE_ALIGN_BASELINE;
+    case NS_STYLE_BOX_ALIGN_END:
+      return NS_STYLE_ALIGN_FLEX_END;
+  }
+
+  MOZ_ASSERT_UNREACHABLE("Unrecognized mBoxAlign enum value");
+  // Fall back to default value of "align-items" property:
+  return NS_STYLE_ALIGN_STRETCH;
+}
+
+// Returns the "justify-content" value that's equivalent to the legacy
+// "box-pack" value in the given style struct.
+static uint8_t
+ConvertLegacyStyleToJustifyContent(const nsStyleXUL* aStyleXUL)
+{
+  // -[moz|webkit]-box-pack corresponds to modern "justify-content"
+  switch (aStyleXUL->mBoxPack) {
+    case NS_STYLE_BOX_PACK_START:
+      return NS_STYLE_ALIGN_FLEX_START;
+    case NS_STYLE_BOX_PACK_CENTER:
+      return NS_STYLE_ALIGN_CENTER;
+    case NS_STYLE_BOX_PACK_END:
+      return NS_STYLE_ALIGN_FLEX_END;
+    case NS_STYLE_BOX_PACK_JUSTIFY:
+      return NS_STYLE_ALIGN_SPACE_BETWEEN;
+  }
+
+  MOZ_ASSERT_UNREACHABLE("Unrecognized mBoxPack enum value");
+  // Fall back to default value of "justify-content" property:
+  return NS_STYLE_ALIGN_FLEX_START;
+}
 
 // Indicates whether advancing along the given axis is equivalent to
 // increasing our X or Y position (as opposed to decreasing it).
 static inline bool
 AxisGrowsInPositiveDirection(AxisOrientationType aAxis)
 {
   return eAxis_LR == aAxis || eAxis_TB == aAxis;
 }
@@ -874,16 +957,39 @@ BuildStrutInfoFromCollapsedItems(const F
         aStruts.AppendElement(StrutInfo(itemIdxInContainer,
                                         line->GetLineCrossSize()));
       }
       itemIdxInContainer++;
     }
   }
 }
 
+// Convenience function to get either the "order" or the "box-ordinal-group"
+// property-value for a flex item (depending on whether the container is a
+// modern flex container or a legacy box).
+static int32_t
+GetOrderOrBoxOrdinalGroup(nsIFrame* aFlexItem, bool aIsLegacyBox)
+{
+  if (aIsLegacyBox) {
+    // We'll be using mBoxOrdinal, which has type uint32_t. However, the modern
+    // 'order' property (whose functionality we're co-opting) has type int32_t.
+    // So: if we happen to have a uint32_t value that's greater than INT32_MAX,
+    // we clamp it rather than letting it overflow. Chances are, this is just
+    // an author using BIG_VALUE anyway, so the clamped value should be fine.
+    // (particularly since sufficiently-huge values are busted in Chrome/WebKit
+    // per https://bugs.chromium.org/p/chromium/issues/detail?id=599645 )
+    uint32_t clampedBoxOrdinal = std::min(aFlexItem->StyleXUL()->mBoxOrdinal,
+                                          static_cast<uint32_t>(INT32_MAX));
+    return static_cast<int32_t>(clampedBoxOrdinal);
+  }
+
+  // Normal case: just use modern 'order' property.
+  return aFlexItem->StylePosition()->mOrder;
+}
+
 // Helper-function to find the first non-anonymous-box descendent of aFrame.
 static nsIFrame*
 GetFirstNonAnonBoxDescendant(nsIFrame* aFrame)
 {
   while (aFrame) {
     nsIAtom* pseudoTag = aFrame->StyleContext()->GetPseudo();
 
     // If aFrame isn't an anonymous container, then it'll do.
@@ -938,31 +1044,36 @@ GetFirstNonAnonBoxDescendant(nsIFrame* a
  *         Otherwise, returns false.
  */
 bool
 IsOrderLEQWithDOMFallback(nsIFrame* aFrame1,
                           nsIFrame* aFrame2)
 {
   MOZ_ASSERT(aFrame1->IsFlexItem() && aFrame2->IsFlexItem(),
              "this method only intended for comparing flex items");
+  MOZ_ASSERT(aFrame1->GetParent() == aFrame2->GetParent(),
+             "this method only intended for comparing siblings");
+  nsStyleContext* parentFrameSC = aFrame1->GetParent()->StyleContext();
+  bool isInLegacyBox = IsLegacyBox(parentFrameSC->StyleDisplay(),
+                                   parentFrameSC);
 
   if (aFrame1 == aFrame2) {
     // Anything is trivially LEQ itself, so we return "true" here... but it's
     // probably bad if we end up actually needing this, so let's assert.
     NS_ERROR("Why are we checking if a frame is LEQ itself?");
     return true;
   }
 
   // If we've got a placeholder frame, use its out-of-flow frame's 'order' val.
   {
     nsIFrame* aRealFrame1 = nsPlaceholderFrame::GetRealFrameFor(aFrame1);
     nsIFrame* aRealFrame2 = nsPlaceholderFrame::GetRealFrameFor(aFrame2);
 
-    int32_t order1 = aRealFrame1->StylePosition()->mOrder;
-    int32_t order2 = aRealFrame2->StylePosition()->mOrder;
+    int32_t order1 = GetOrderOrBoxOrdinalGroup(aRealFrame1, isInLegacyBox);
+    int32_t order2 = GetOrderOrBoxOrdinalGroup(aRealFrame2, isInLegacyBox);
 
     if (order1 != order2) {
       return order1 < order2;
     }
   }
 
   // The "order" values are equal, so we need to fall back on DOM comparison.
   // For that, we need to dig through any anonymous box wrapper frames to find
@@ -1019,23 +1130,28 @@ IsOrderLEQWithDOMFallback(nsIFrame* aFra
  *         equal to that of aFrame2.  Otherwise, returns false.
  */
 bool
 IsOrderLEQ(nsIFrame* aFrame1,
            nsIFrame* aFrame2)
 {
   MOZ_ASSERT(aFrame1->IsFlexItem() && aFrame2->IsFlexItem(),
              "this method only intended for comparing flex items");
+  MOZ_ASSERT(aFrame1->GetParent() == aFrame2->GetParent(),
+             "this method only intended for comparing siblings");
+  nsStyleContext* parentFrameSC = aFrame1->GetParent()->StyleContext();
+  bool isInLegacyBox = IsLegacyBox(parentFrameSC->StyleDisplay(),
+                                   parentFrameSC);
 
   // If we've got a placeholder frame, use its out-of-flow frame's 'order' val.
   nsIFrame* aRealFrame1 = nsPlaceholderFrame::GetRealFrameFor(aFrame1);
   nsIFrame* aRealFrame2 = nsPlaceholderFrame::GetRealFrameFor(aFrame2);
 
-  int32_t order1 = aRealFrame1->StylePosition()->mOrder;
-  int32_t order2 = aRealFrame2->StylePosition()->mOrder;
+  int32_t order1 = GetOrderOrBoxOrdinalGroup(aRealFrame1, isInLegacyBox);
+  int32_t order2 = GetOrderOrBoxOrdinalGroup(aRealFrame2, isInLegacyBox);
 
   return order1 <= order2;
 }
 
 bool
 nsFlexContainerFrame::IsHorizontal()
 {
   const FlexboxAxisTracker axisTracker(StylePosition(), GetWritingMode());
@@ -1053,19 +1169,25 @@ nsFlexContainerFrame::GenerateFlexItemFo
   // main-size and the computed values of min / max main-size property.
   // (This reflow state will _not_ be used for reflow.)
   nsHTMLReflowState
     childRS(aPresContext, aParentReflowState, aChildFrame,
             aParentReflowState.ComputedSize(aChildFrame->GetWritingMode()));
 
   // FLEX GROW & SHRINK WEIGHTS
   // --------------------------
-  const nsStylePosition* stylePos = aChildFrame->StylePosition();
-  float flexGrow   = stylePos->mFlexGrow;
-  float flexShrink = stylePos->mFlexShrink;
+  float flexGrow, flexShrink;
+  if (IsLegacyBox(aParentReflowState.mStyleDisplay, mStyleContext)) {
+    flexGrow = flexShrink = aChildFrame->StyleXUL()->mBoxFlex;
+  } else {
+    const nsStylePosition* stylePos = aChildFrame->StylePosition();
+    flexGrow   = stylePos->mFlexGrow;
+    flexShrink = stylePos->mFlexShrink;
+  }
+
   WritingMode childWM = childRS.GetWritingMode();
 
   // MAIN SIZES (flex base size, min/max size)
   // -----------------------------------------
   nscoord flexBaseSize = GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, childWM,
                                                     childRS.ComputedISize(),
                                                     childRS.ComputedBSize());
   nscoord mainMinSize = GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, childWM,
@@ -1565,25 +1687,39 @@ FlexItem::FlexItem(nsHTMLReflowState& aF
     // mAlignSelf, see below
 {
   MOZ_ASSERT(mFrame, "expecting a non-null child frame");
   MOZ_ASSERT(mFrame->GetType() != nsGkAtoms::placeholderFrame,
              "placeholder frames should not be treated as flex items");
   MOZ_ASSERT(!(mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
              "out-of-flow frames should not be treated as flex items");
 
-  mAlignSelf = aFlexItemReflowState.mStylePosition->ComputedAlignSelf(
-                 mFrame->StyleContext()->GetParent());
-  if (MOZ_LIKELY(mAlignSelf == NS_STYLE_ALIGN_NORMAL)) {
-    mAlignSelf = NS_STYLE_ALIGN_STRETCH;
+  const nsHTMLReflowState* containerRS = aFlexItemReflowState.parentReflowState;
+  if (IsLegacyBox(containerRS->mStyleDisplay,
+                  containerRS->frame->StyleContext())) {
+    // For -webkit-box/-webkit-inline-box, we need to:
+    // (1) Use "-webkit-box-align" instead of "align-items" to determine the
+    //     container's cross-axis alignment behavior.
+    // (2) Suppress the ability for flex items to override that with their own
+    //     cross-axis alignment. (The legacy box model doesn't support this.)
+    // So, each FlexItem simply copies the container's converted "align-items"
+    // value and disregards their own "align-self" property.
+    const nsStyleXUL* containerStyleXUL = containerRS->frame->StyleXUL();
+    mAlignSelf = ConvertLegacyStyleToAlignItems(containerStyleXUL);
+  } else {
+    mAlignSelf = aFlexItemReflowState.mStylePosition->ComputedAlignSelf(
+                   mFrame->StyleContext()->GetParent());
+    if (MOZ_LIKELY(mAlignSelf == NS_STYLE_ALIGN_NORMAL)) {
+      mAlignSelf = NS_STYLE_ALIGN_STRETCH;
+    }
+
+    // XXX strip off the <overflow-position> bit until we implement that
+    mAlignSelf &= ~NS_STYLE_ALIGN_FLAG_BITS;
   }
 
-  // XXX strip off the <overflow-position> bit until we implement that
-  mAlignSelf &= ~NS_STYLE_ALIGN_FLAG_BITS;
-
   SetFlexBaseSizeAndMainSize(aFlexBaseSize);
   CheckForMinSizeAuto(aFlexItemReflowState, aAxisTracker);
 
   // Assert that any "auto" margin components are set to 0.
   // (We'll resolve them later; until then, we want to treat them as 0-sized.)
 #ifdef DEBUG
   {
     const nsStyleSides& styleMargin =
@@ -3778,21 +3914,24 @@ nsFlexContainerFrame::DoFlexLayout(nsPre
     } else  {
       flexContainerAscent =
         ComputePhysicalAscentFromFlexRelativeAscent(
           crossAxisPosnTracker.GetPosition() + firstLineBaselineOffset,
           contentBoxCrossSize, aReflowState, aAxisTracker);
     }
   }
 
+  const auto justifyContent = IsLegacyBox(aReflowState.mStyleDisplay,
+                                          mStyleContext) ?
+    ConvertLegacyStyleToJustifyContent(StyleXUL()) :
+    aReflowState.mStylePosition->ComputedJustifyContent();
+
   for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
-
     // Main-Axis Alignment - Flexbox spec section 9.5
     // ==============================================
-    auto justifyContent = aReflowState.mStylePosition->ComputedJustifyContent();
     line->PositionItemsInMainAxis(justifyContent,
                                   aContentBoxMainSize,
                                   aAxisTracker);
 
     // Cross-Axis Alignment - Flexbox spec section 9.6
     // ===============================================
     line->PositionItemsInCrossAxis(crossAxisPosnTracker.GetPosition(),
                                    aAxisTracker);
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -2146,16 +2146,17 @@ nsImageFrame::AttributeChanged(int32_t a
 
 void
 nsImageFrame::OnVisibilityChange(Visibility aNewVisibility,
                                  Maybe<OnNonvisible> aNonvisibleAction)
 {
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
   if (!imageLoader) {
     MOZ_ASSERT_UNREACHABLE("Should have an nsIImageLoadingContent");
+    ImageFrameSuper::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
     return;
   }
 
   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 
   if (aNewVisibility == Visibility::APPROXIMATELY_VISIBLE) {
     MaybeDecodeForPredictedSize();
   }
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -45,18 +45,18 @@
 using namespace mozilla;
 using mozilla::layout::RenderFrameParent;
 
 static nsIDocument*
 GetDocumentFromView(nsView* aView)
 {
   NS_PRECONDITION(aView, "");
 
-  nsIFrame* f = aView->GetFrame();
-  nsIPresShell* ps =  f ? f->PresContext()->PresShell() : nullptr;
+  nsViewManager* vm = aView->GetViewManager();
+  nsIPresShell* ps =  vm ? vm->GetPresShell() : nullptr;
   return ps ? ps->GetDocument() : nullptr;
 }
 
 nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext)
   : nsSubDocumentFrameSuper(aContext)
   , mIsInline(false)
   , mPostedReflowCallback(false)
   , mDidCreateDoc(false)
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -4818,19 +4818,21 @@ nsTextFrame::BuildDisplayList(nsDisplayL
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists)
 {
   if (!IsVisibleForPainting(aBuilder))
     return;
   
   DO_GLOBAL_REFLOW_COUNT_DSP("nsTextFrame");
 
+  bool isTextTransparent =
+    NS_GET_A(StyleContext()->GetTextFillColor()) == 0;
   Maybe<bool> isSelected;
   if (((GetStateBits() & TEXT_NO_RENDERED_GLYPHS) ||
-       (NS_GET_A(StyleColor()->mColor) == 0 && !StyleText()->HasTextShadow())) &&
+       (isTextTransparent && !StyleText()->HasTextShadow())) &&
       aBuilder->IsForPainting() && !IsSVGText()) {
     isSelected.emplace(IsSelected());
     if (!isSelected.value()) {
       TextDecorations textDecs;
       GetTextDecorations(PresContext(), eResolvedColors, textDecs);
       if (!textDecs.HasDecorationLines()) {
         return;
       }
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -618,16 +618,17 @@ nsVideoFrame::AttributeChanged(int32_t a
 }
 
 void
 nsVideoFrame::OnVisibilityChange(Visibility aNewVisibility,
                                  Maybe<OnNonvisible> aNonvisibleAction)
 {
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mPosterImage);
   if (!imageLoader) {
+    nsVideoFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
     return;
   }
 
   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 
   nsVideoFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 }
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/async-scrolling/background-blend-mode-1-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Reference: Bug 1248913 - Keep background-attachment:fixed image fixed under APZ scrolling even when a background-blend-mode is applied.</title>
+
+<style>
+
+html {
+  background: radial-gradient(circle 200px at 400px 400px, lime 100px, transparent 0) scroll,
+              radial-gradient(circle 200px at 400px 300px, blue 100px, transparent 0) scroll
+               white no-repeat;
+  background-blend-mode: multiply;
+  height: 100%;
+}
+
+</style>
+
+<div></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/async-scrolling/background-blend-mode-1.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html reftest-async-scroll
+      reftest-displayport-x="0" reftest-displayport-y="0"
+      reftest-displayport-w="800" reftest-displayport-h="1000"
+      reftest-async-scroll-x="0" reftest-async-scroll-y="100">
+
+<meta charset="utf-8">
+<title>Bug 1248913 - Keep background-attachment:fixed image fixed under APZ scrolling even when a background-blend-mode is applied.</title>
+
+<style>
+
+html {
+  background: radial-gradient(circle 200px at 400px 400px, lime 100px, transparent 0) fixed,
+              radial-gradient(circle 200px at 400px 400px, blue 100px, transparent 0) scroll
+               white no-repeat;
+  background-blend-mode: multiply;
+  overflow: hidden;
+}
+
+body {
+  height: 4000px;
+}
+
+</style>
+
+<div></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/async-scrolling/perspective-scrolling-4-ref.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>Reference: Perspective scrolling with nested clips</title>
+
+<style>
+
+html {
+  padding: 50px 0 3000px;
+}
+
+body {
+  margin: 0;
+}
+
+.scrollbox {
+  width: 600px;
+  height: 500px;
+  perspective: 1px;
+  overflow: auto;
+}
+
+.transformed {
+  will-change: transform;
+  width: 200px;
+  height: 200px;
+  margin: 200px 100px;
+  border: 10px solid black;
+}
+
+.spacer {
+  height: 4000px;
+}
+
+</style>
+
+<div class="scrollbox">
+  <div class="transformed"></div>
+  <div class="spacer"></div>
+</div>
+
+<script>
+document.scrollingElement.scrollTop = 250;
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/async-scrolling/perspective-scrolling-4.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html lang="en"
+     reftest-async-scroll
+     reftest-displayport-x="0" reftest-displayport-y="0"
+     reftest-displayport-w="800" reftest-displayport-h="1000"
+     reftest-async-scroll-x="0" reftest-async-scroll-y="250">
+<meta charset="utf-8">
+<title>Perspective scrolling with nested clips</title>
+
+<style>
+
+html {
+  padding: 50px 0 3000px;
+}
+
+body {
+  margin: 0;
+}
+
+.scrollbox {
+  width: 600px;
+  height: 500px;
+  perspective: 1px;
+  overflow: auto;
+}
+
+.transformed {
+  will-change: transform;
+  width: 200px;
+  height: 200px;
+  margin: 200px 100px;
+  border: 10px solid black;
+}
+
+.spacer {
+  height: 4000px;
+}
+
+</style>
+
+<div class="scrollbox"
+     reftest-displayport-x="0" reftest-displayport-y="0"
+     reftest-displayport-w="600" reftest-displayport-h="2000"
+     reftest-async-scroll-x="0" reftest-async-scroll-y="0">
+
+  <div class="transformed"></div>
+  <div class="spacer"></div>
+
+</div>
--- a/layout/reftests/async-scrolling/reftest.list
+++ b/layout/reftests/async-scrolling/reftest.list
@@ -34,17 +34,19 @@ skip-if(!asyncPan) == position-sticky-tr
 skip-if(!asyncPan) == offscreen-prerendered-active-opacity.html offscreen-prerendered-active-opacity-ref.html
 fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-1.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,6,4) skip == offscreen-clipped-blendmode-3.html offscreen-clipped-blendmode-ref.html # bug 1251588 - wrong AGR on mix-blend-mode item
 fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-4.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-1.html perspective-scrolling-1-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-2.html perspective-scrolling-2-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-3.html perspective-scrolling-3-ref.html
+fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-4.html perspective-scrolling-4-ref.html
 pref(apz.disable_for_scroll_linked_effects,true) skip-if(!asyncPan) == disable-apz-for-sle-pages.html disable-apz-for-sle-pages-ref.html
+skip-if(!asyncPan) == background-blend-mode-1.html background-blend-mode-1-ref.html
 
 # for the following tests, we want to disable the low-precision buffer
 # as it will expand the displayport beyond what the test specifies in
 # its reftest-displayport attributes, and interfere with where we expect
 # checkerboarding to occur
 default-preferences pref(layers.low-precision-buffer,false)
 skip-if(!asyncPan) == checkerboard-1.html checkerboard-1-ref.html
 skip-if(!asyncPan) == checkerboard-2.html checkerboard-2-ref.html
--- a/layout/reftests/invalidation/fast-scrolling.html
+++ b/layout/reftests/invalidation/fast-scrolling.html
@@ -1,14 +1,10 @@
 <!DOCTYPE html>
-<html lang="en" class="reftest-wait"
-      reftest-displayport-x="0"
-      reftest-displayport-y="0"
-      reftest-displayport-w="800"
-      reftest-displayport-h="1000">
+<html lang="en" class="reftest-wait" reftest-async-scroll>
 <meta charset="utf-8">
 <title>Bug 1164227 - Testcase for the invalid region simplification bug</title>
 
 <style>
 
 #scrollbox {
   width: 400px;
   height: 500px;
@@ -42,17 +38,21 @@
   top: 250px;
   left: 30px;
   width: 200px;
   height: 50px;
   border: 1px solid red;
 }
 </style>
 
-<div id="scrollbox">
+<div id="scrollbox"
+     reftest-displayport-x="0"
+     reftest-displayport-y="0"
+     reftest-displayport-w="400"
+     reftest-displayport-h="500">
 
   <div class="contents">
 
     <div class="boxes">
       <div style="margin-top: 0px"></div>
       <div style="margin-top: 1px"></div>
       <div style="margin-top: 2px"></div>
       <div style="margin-top: 3px"></div>
--- a/layout/reftests/webkit-box/reftest.list
+++ b/layout/reftests/webkit-box/reftest.list
@@ -14,12 +14,25 @@ fails == webkit-box-anon-flex-items-3.ht
 # Tests for "-webkit-box" & "-webkit-inline-box" as display values:
 == webkit-display-values-1.html webkit-display-values-1-ref.html
 
 # Tests for "-webkit-box-align" (cross-axis alignment):
 == webkit-box-align-horiz-1a.html webkit-box-align-horiz-1-ref.html
 == webkit-box-align-horiz-1b.html webkit-box-align-horiz-1-ref.html
 == webkit-box-align-vert-1.html webkit-box-align-vert-1-ref.html
 
+# Tests for "-webkit-box-flex" (flexibility of items)
+== webkit-box-flex-1.html webkit-box-flex-1-ref.html
+
+# Tests for "-webkit-box-ordinal-group"
+== webkit-box-ordinal-group-1.html webkit-box-ordinal-group-1-ref.html
+# XXXdholbert The following test fails because we accept "0" as a valid value
+# for -webkit-box-ordinal-group (unlike Chrome/Blink), because that's simply
+# how its aliased property (-moz-box-ordinal-group) behaves. This shouldn't
+# matter in practice; it could only cause trouble if sites accidentally depend
+# on the "0" value being rejected.
+fails == webkit-box-ordinal-group-2.html webkit-box-ordinal-group-2-ref.html
+== webkit-box-ordinal-group-3.html webkit-box-ordinal-group-3-ref.html
+
 # Tests for "-webkit-box-pack" (main-axis alignment):
 == webkit-box-pack-horiz-1a.html webkit-box-pack-horiz-1-ref.html
 == webkit-box-pack-horiz-1b.html webkit-box-pack-horiz-1-ref.html
 == webkit-box-pack-vert-1.html webkit-box-pack-vert-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/webkit-box/webkit-box-flex-1-ref.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>
+    CSS Reference
+  </title>
+  <style>
+    .box {
+      display: flex;
+      border: 1px solid black;
+      margin: 5px 20px;
+      width: 100px;
+      float: left; /* For testing in "rows" */
+      font: 10px serif;
+    }
+    .box > * {
+      /* Modern flexbox (used in this reference case) allows everything to
+         shrink by default, but -webkit-box does not, so we have to turn that
+         feature off to make an accurate reference case. */
+      flex-shrink: 0;
+    }
+
+    .box > *:nth-child(1) { background: turquoise; }
+    .box > *:nth-child(2) { background: salmon;    }
+    .box > *:nth-child(3) { background: yellow;    }
+
+    .huge { width: 120px }
+    .bf1 { flex: 1 1 auto }
+    .bf3 { flex: 3 3 auto }
+
+    br { clear: both; }
+  </style>
+</head>
+<body>
+  <!-- FIRST ROW: Default -webkit-box-flex -->
+  <div class="box">
+    <div>a</div>
+  </div>
+
+  <div class="box">
+    <div>a</div><div>b</div>
+  </div>
+
+  <div class="box">
+    <div class="huge">a</div>
+  </div>
+
+  <br>
+
+  <!-- SECOND ROW: One item has nonzero -webkit-box-flex -->
+  <div class="box">
+    <div class="bf1">a</div>
+  </div>
+
+  <div class="box">
+    <div>a</div><div class="bf1">b</div>
+  </div>
+
+  <div class="box">
+    <div class="huge bf1">a</div>
+  </div>
+
+  <br>
+
+  <!-- THIRD ROW: Two items have nonzero (equal) -webkit-box-flex -->
+  <div class="box">
+    <div class="bf1">a</div><div class="bf1">b</div>
+  </div>
+
+  <div class="box">
+    <div class="bf1">a</div><div>b</div><div class="bf1">c</div>
+  </div>
+
+  <div class="box">
+    <div class="huge bf1">a</div>
+    <div>b</div>
+    <div class="huge bf1">c</div>
+  </div>
+
+  <br>
+
+  <!-- FOURTH ROW: Non-equal nonzero -webkit-box-flex values -->
+  <div class="box">
+    <div class="bf1">a</div><div class="bf3">b</div>
+  </div>
+
+  <div class="box">
+    <div class="bf3">a</div><div class="bf1">b</div>
+  </div>
+
+  <div class="box">
+    <div class="huge bf1">a</div>
+    <div class="huge bf3">b</div>
+  </div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/webkit-box/webkit-box-flex-1.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>
+    CSS Test: "-webkit-box-flex" in a "display: -webkit-box" container
+  </title>
+  <style>
+    .box {
+      display: -webkit-box;
+      border: 1px solid black;
+      margin: 5px 20px;
+      width: 100px;
+      float: left; /* For testing in "rows" */
+      font: 10px serif;
+    }
+    .box > *:nth-child(1) { background: turquoise; }
+    .box > *:nth-child(2) { background: salmon;    }
+    .box > *:nth-child(3) { background: yellow;    }
+
+    .huge { width: 120px }
+    .bf1 { -webkit-box-flex: 1 }
+    .bf3 { -webkit-box-flex: 3 }
+
+    br { clear: both; }
+  </style>
+</head>
+<body>
+  <!-- FIRST ROW: Default -webkit-box-flex -->
+  <div class="box">
+    <div>a</div>
+  </div>
+
+  <div class="box">
+    <div>a</div><div>b</div>
+  </div>
+
+  <div class="box">
+    <div class="huge">a</div>
+  </div>
+
+  <br>
+
+  <!-- SECOND ROW: One item has nonzero -webkit-box-flex -->
+  <div class="box">
+    <div class="bf1">a</div>
+  </div>
+
+  <div class="box">
+    <div>a</div><div class="bf1">b</div>
+  </div>
+
+  <div class="box">
+    <div class="huge bf1">a</div>
+  </div>
+
+  <br>
+
+  <!-- THIRD ROW: Two items have nonzero (equal) -webkit-box-flex -->
+  <div class="box">
+    <div class="bf1">a</div><div class="bf1">b</div>
+  </div>
+
+  <div class="box">
+    <div class="bf1">a</div><div>b</div><div class="bf1">c</div>
+  </div>
+
+  <div class="box">
+    <div class="huge bf1">a</div>
+    <div>b</div>
+    <div class="huge bf1">c</div>
+  </div>
+
+  <br>
+
+  <!-- FOURTH ROW: Non-equal nonzero -webkit-box-flex values -->
+  <div class="box">
+    <div class="bf1">a</div><div class="bf3">b</div>
+  </div>
+
+  <div class="box">
+    <div class="bf3">a</div><div class="bf1">b</div>
+  </div>
+
+  <div class="box">
+    <div class="huge bf1">a</div>
+    <div class="huge bf3">b</div>
+  </div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-1-ref.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>
+    CSS Reference
+  </title>
+  <style>
+    .box {
+      display: flex;
+      border: 1px solid black;
+      margin: 5px 20px;
+      float: left; /* For testing in "rows" */
+    }
+    br { clear: both; }
+
+    .box > * {
+      border: 1px dotted purple;
+    }
+  </style>
+</head>
+<body>
+  <!-- First row: initial value mixed with single specified values -->
+  <div class="box">
+    <div>*</div>
+    <div class="bogOne">1a</div>
+    <div>*</div>
+    <div class="bogOne">1b</div>
+    <div>*</div>
+  </div>
+
+  <div class="box">
+    <div>*</div>
+    <div>*</div>
+    <div>*</div>
+    <div class="bogTwo">2a</div>
+    <div class="bogTwo">2b</div>
+  </div>
+
+  <div class="box">
+    <div>*</div>
+    <div>*</div>
+    <div>*</div>
+    <div class="bogNine">9a</div>
+    <div class="bogNine">9b</div>
+  </div>
+
+  <br>
+
+  <!-- Second row: various mixes of specified values -->
+  <div class="box">
+    <div>*</div>
+    <div class="bogOne">1</div>
+    <div class="bogTwo">2</div>
+    <div class="bogNine">9</div>
+  </div>
+
+  <div class="box">
+    <div class="bogOne">1</div>
+    <div>*</div>
+    <div class="bogTwo">2</div>
+    <div class="bogNine">9</div>
+  </div>
+
+  <div class="box">
+    <div class="bogOne">1</div>
+    <div>*</div>
+    <div class="bogTwo">2a</div>
+    <div class="bogTwo">2b</div>
+    <div class="bogNine">9</div>
+  </div>
+
+  <div class="box">
+    <div class="bogOne">1</div>
+    <div class="bogTwo">2a</div>
+    <div class="bogTwo">2b</div>
+    <div class="bogNine">9a</div>
+    <div class="bogNine">9b</div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-1.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>
+    CSS Test: -webkit-box-orient inside a -webkit-box
+  </title>
+  <style>
+    .box {
+      display: -webkit-box;
+      border: 1px solid black;
+      margin: 5px 20px;
+      float: left; /* For testing in "rows" */
+    }
+    br { clear: both; }
+
+    .box > * {
+      border: 1px dotted purple;
+    }
+
+    .bogOne  { -webkit-box-ordinal-group: 1; }
+    .bogTwo  { -webkit-box-ordinal-group: 2; }
+    .bogNine { -webkit-box-ordinal-group: 9; }
+  </style>
+</head>
+<body>
+  <!-- First row: initial value mixed with single specified values -->
+  <div class="box">
+    <div>*</div>
+    <div class="bogOne">1a</div>
+    <div>*</div>
+    <div class="bogOne">1b</div>
+    <div>*</div>
+  </div>
+
+  <div class="box">
+    <div>*</div>
+    <div class="bogTwo">2a</div>
+    <div>*</div>
+    <div class="bogTwo">2b</div>
+    <div>*</div>
+  </div>
+
+  <div class="box">
+    <div>*</div>
+    <div class="bogNine">9a</div>
+    <div>*</div>
+    <div class="bogNine">9b</div>
+    <div>*</div>
+  </div>
+
+  <br>
+
+  <!-- Second row: various mixes of specified values -->
+  <div class="box">
+    <div>*</div>
+    <div class="bogOne">1</div>
+    <div class="bogTwo">2</div>
+    <div class="bogNine">9</div>
+  </div>
+
+  <div class="box">
+    <div class="bogNine">9</div>
+    <div class="bogTwo">2</div>
+    <div class="bogOne">1</div>
+    <div>*</div>
+  </div>
+
+  <div class="box">
+    <div class="bogTwo">2a</div>
+    <div class="bogNine">9</div>
+    <div class="bogTwo">2b</div>
+    <div class="bogOne">1</div>
+    <div>*</div>
+  </div>
+
+  <div class="box">
+    <div class="bogTwo">2a</div>
+    <div class="bogNine">9a</div>
+    <div class="bogNine">9b</div>
+    <div class="bogTwo">2b</div>
+    <div class="bogOne">1</div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-2-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>
+    CSS Reference
+  </title>
+  <style>
+    .box {
+      display: flex;
+      border: 1px solid black;
+      margin: 5px 20px;
+    }
+
+    .box > * {
+      border: 1px dotted purple;
+    }
+  </style>
+</head>
+<body>
+  <div class="box">
+    <div>1</div>
+    <div>0</div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-2.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>
+    CSS Test: -webkit-box-orient:0 inside a -webkit-box
+  </title>
+  <style>
+    .box {
+      display: -webkit-box;
+      border: 1px solid black;
+      margin: 5px 20px;
+    }
+
+    .box > * {
+      border: 1px dotted purple;
+    }
+
+    .bogZero { -webkit-box-ordinal-group: 0; }
+    .bogOne  { -webkit-box-ordinal-group: 1; }
+  </style>
+</head>
+<body>
+  <!-- -webkit-box-ordinal-group is strictly positive in Blink & WebKit. 0 is
+       rejected as an invalid value. So, the bogZero element below should
+       end up with the initial value (1) and should *not* be sorted out of its
+       DOM position in the final rendering. -->
+  <div class="box">
+    <div class="bogOne">1</div>
+    <div class="bogZero">0</div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-3-ref.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>
+    CSS Reference
+  </title>
+  <style>
+    .box {
+      display: flex;
+      border: 1px solid black;
+      margin: 5px 20px;
+      float: left; /* For testing in "rows" */
+    }
+    br { clear: both; }
+
+    .box > * {
+      border: 1px dotted purple;
+    }
+  </style>
+</head>
+<body>
+  <div class="box">
+    <div>*</div>
+    <div>10</div>
+    <div>A</div>
+  </div>
+  <div class="box">
+    <div>*</div>
+    <div>10</div>
+    <div>B</div>
+  </div>
+  <div class="box">
+    <div>*</div>
+    <div>10</div>
+    <div>C</div>
+  </div>
+
+  <br>
+
+  <div class="box">
+    <div>*</div>
+    <div>10</div>
+    <div>D</div>
+  </div>
+  <div class="box">
+    <div>*</div>
+    <div>10</div>
+    <div>E</div>
+  </div>
+  <div class="box">
+    <div>*</div>
+    <div>10</div>
+    <div>F</div>
+  </div>
+
+  <br>
+
+  <div class="box">
+    <div>A</div>
+    <div>B</div>
+  </div>
+  <div class="box">
+    <div>A</div>
+    <div>C</div>
+  </div>
+  <div class="box">
+    <div>A</div>
+    <div>D</div>
+  </div>
+  <div class="box">
+    <div>A</div>
+    <div>E</div>
+  </div>
+  <div class="box">
+    <div>A</div>
+    <div>F</div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-3.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>
+    CSS Test: -webkit-box-orient with huge values inside a -webkit-box
+  </title>
+  <style>
+    .box {
+      display: -webkit-box;
+      border: 1px solid black;
+      margin: 5px 20px;
+      float: left; /* For testing in "rows" */
+    }
+    br { clear: both; }
+
+    .box > * {
+      border: 1px dotted purple;
+    }
+
+    .bogTen   { -webkit-box-ordinal-group: 10; }
+    .bogHugeA { -webkit-box-ordinal-group: 2147483646; /* 2^31 - 2 */ }
+    .bogHugeB {
+      /* NOTE: This is INT32_MAX, so we may not be able to distinguish this
+         from anything larger than it (if we represent it internally in a
+         32-bit signed integer). However, it's still worth testing larger
+         values against e.g. 10 to be sure they don't overflow into
+         negative territory. */
+      -webkit-box-ordinal-group: 2147483647; /* 2^31 - 1 */ }
+
+    .bogHugeC { -webkit-box-ordinal-group: 4294967294; /* 2^32 - 2 */ }
+    .bogHugeD { -webkit-box-ordinal-group: 4294967295; /* 2^32 - 1 */ }
+    .bogHugeE { -webkit-box-ordinal-group: 4294967296; /* 2^32     */ }
+    .bogHugeF { -webkit-box-ordinal-group: 8589934592; /* 2^33     */ }
+  </style>
+</head>
+<body>
+  <!-- Test each huge value to see if it sorts after smaller values.
+       (The divs with huge values should sort to the right.) -->
+  <div class="box">
+    <div class="bogHugeA">A</div>
+    <div class="bogTen">10</div>
+    <div>*</div>
+  </div>
+  <div class="box">
+    <div class="bogHugeB">B</div>
+    <div class="bogTen">10</div>
+    <div>*</div>
+  </div>
+  <div class="box">
+    <div class="bogHugeC">C</div>
+    <div class="bogTen">10</div>
+    <div>*</div>
+  </div>
+
+  <br>
+
+  <div class="box">
+    <div class="bogHugeD">D</div>
+    <div class="bogTen">10</div>
+    <div>*</div>
+  </div>
+  <div class="box">
+    <div class="bogHugeE">E</div>
+    <div class="bogTen">10</div>
+    <div>*</div>
+  </div>
+  <div class="box">
+    <div class="bogHugeE">F</div>
+    <div class="bogTen">10</div>
+    <div>*</div>
+  </div>
+
+  <br>
+
+  <!-- Test that 'bogHugeA' sorts to the left of larger huge values. It's
+       less than INT32_MAX, so it's reasonable to expect that it can be
+       compared correctly against (possibly-clamped) larger values) -->
+  <div class="box">
+    <div class="bogHugeB">B</div>
+    <div class="bogHugeA">A</div>
+  </div>
+  <div class="box">
+    <div class="bogHugeC">C</div>
+    <div class="bogHugeA">A</div>
+  </div>
+  <div class="box">
+    <div class="bogHugeD">D</div>
+    <div class="bogHugeA">A</div>
+  </div>
+  <div class="box">
+    <div class="bogHugeE">E</div>
+    <div class="bogHugeA">A</div>
+  </div>
+  <div class="box">
+    <div class="bogHugeF">F</div>
+    <div class="bogHugeA">A</div>
+  </div>
+</body>
+</html>
--- a/layout/reftests/webkit-box/webkit-box-pack-horiz-1-ref.html
+++ b/layout/reftests/webkit-box/webkit-box-pack-horiz-1-ref.html
@@ -23,21 +23,20 @@
     }
     .box > *:nth-child(2) {
       background: salmon;
       font-size: 50%;
       width: 2em;
       /* auto height */
     }
 
-    .bpstart   { justify-content: flex-start; }
-    .bpcenter  { justify-content: center;     }
-    .bpend     { justify-content: flex-end;   }
-    .bpjustify { justify-content: justify;
-                 display:none; /* XXXdholbert Disabling until bug 1231682 is fixed */ }
+    .bpstart   { justify-content: flex-start;    }
+    .bpcenter  { justify-content: center;        }
+    .bpend     { justify-content: flex-end;      }
+    .bpjustify { justify-content: space-between; }
     br { clear: both; }
   </style>
 </head>
 <body>
   <!-- FIRST ROW: Default -webkit-box-pack -->
   <!-- intrinsically sized -->
   <div class="box">
     <div>a</div><div>b</div>
--- a/layout/reftests/webkit-box/webkit-box-pack-horiz-1a.html
+++ b/layout/reftests/webkit-box/webkit-box-pack-horiz-1a.html
@@ -27,18 +27,17 @@
       font-size: 50%;
       width: 2em;
       /* auto height */
     }
 
     .bpstart   { -webkit-box-pack: start;   }
     .bpcenter  { -webkit-box-pack: center;  }
     .bpend     { -webkit-box-pack: end;     }
-    .bpjustify { -webkit-box-pack: justify;
-                 display:none; /* XXXdholbert Disabling until bug 1231682 is fixed */ }
+    .bpjustify { -webkit-box-pack: justify; }
     br { clear: both; }
   </style>
 </head>
 <body>
   <!-- FIRST ROW: Default -webkit-box-pack -->
   <!-- intrinsically sized -->
   <div class="box">
     <div>a</div><div>b</div>
--- a/layout/reftests/webkit-box/webkit-box-pack-horiz-1b.html
+++ b/layout/reftests/webkit-box/webkit-box-pack-horiz-1b.html
@@ -28,18 +28,17 @@
       font-size: 50%;
       width: 2em;
       /* auto height */
     }
 
     .bpstart   { -webkit-box-pack: start;   }
     .bpcenter  { -webkit-box-pack: center;  }
     .bpend     { -webkit-box-pack: end;     }
-    .bpjustify { -webkit-box-pack: justify;
-                 display:none; /* XXXdholbert Disabling until bug 1231682 is fixed */ }
+    .bpjustify { -webkit-box-pack: justify; }
     br { clear: both; }
   </style>
 </head>
 <body>
   <!-- FIRST ROW: Default -webkit-box-pack -->
   <!-- intrinsically sized -->
   <div class="box">
     <div>a</div><div>b</div>
--- a/layout/reftests/webkit-box/webkit-box-pack-vert-1-ref.html
+++ b/layout/reftests/webkit-box/webkit-box-pack-vert-1-ref.html
@@ -24,21 +24,20 @@
     }
     .box > *:nth-child(2) {
       background: salmon;
       font-size: 50%;
       width: 2em;
       /* auto height */
     }
 
-    .bpstart   { justify-content: flex-start; }
-    .bpcenter  { justify-content: center;     }
-    .bpend     { justify-content: flex-end;   }
-    .bpjustify { justify-content: justify;
-                 display:none; /* XXXdholbert Disabling until bug 1231682 is fixed */ }
+    .bpstart   { justify-content: flex-start;    }
+    .bpcenter  { justify-content: center;        }
+    .bpend     { justify-content: flex-end;      }
+    .bpjustify { justify-content: space-between; }
     br { clear: both; }
   </style>
 </head>
 <body>
   <!-- FIRST ROW: Default -webkit-box-pack -->
   <!-- intrinsically sized -->
   <div class="box">
     <div>a</div><div>b</div>
--- a/layout/reftests/webkit-box/webkit-box-pack-vert-1.html
+++ b/layout/reftests/webkit-box/webkit-box-pack-vert-1.html
@@ -28,18 +28,17 @@
       font-size: 50%;
       width: 2em;
       /* auto height */
     }
 
     .bpstart   { -webkit-box-pack: start;   }
     .bpcenter  { -webkit-box-pack: center;  }
     .bpend     { -webkit-box-pack: end;     }
-    .bpjustify { -webkit-box-pack: justify;
-                 display:none; /* XXXdholbert Disabling until bug 1231682 is fixed */ }
+    .bpjustify { -webkit-box-pack: justify; }
     br { clear: both; }
   </style>
 </head>
 <body>
   <!-- FIRST ROW: Default -webkit-box-pack -->
   <!-- intrinsically sized -->
   <div class="box">
     <div>a</div><div>b</div>
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -8,16 +8,18 @@
 
 #include "nsCSSRuleProcessor.h"
 #include "nsContentUtils.h"
 #include "nsIDOMNode.h"
 #include "nsIDocument.h"
 #include "nsINode.h"
 #include "nsNameSpaceManager.h"
 #include "nsString.h"
+#include "nsStyleStruct.h"
+#include "StyleStructContext.h"
 
 #include "mozilla/EventStates.h"
 #include "mozilla/dom/Element.h"
 
 uint32_t
 Gecko_ChildrenCount(RawGeckoNode* aNode)
 {
   return aNode->GetChildCount();
@@ -144,16 +146,41 @@ Gecko_GetNodeData(RawGeckoNode* aNode)
 }
 
 void
 Gecko_SetNodeData(RawGeckoNode* aNode, ServoNodeData* aData)
 {
   aNode->SetServoNodeData(aData);
 }
 
+#define STYLE_STRUCT(name, checkdata_cb)                                      \
+                                                                              \
+void                                                                          \
+Gecko_Construct_nsStyle##name(nsStyle##name* ptr)                             \
+{                                                                             \
+  new (ptr) nsStyle##name(StyleStructContext::ServoContext());                \
+}                                                                             \
+                                                                              \
+void                                                                          \
+Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr,                         \
+                                  const nsStyle##name* other)                 \
+{                                                                             \
+  new (ptr) nsStyle##name(*other);                                            \
+}                                                                             \
+                                                                              \
+void                                                                          \
+Gecko_Destroy_nsStyle##name(nsStyle##name* ptr)                               \
+{                                                                             \
+  ptr->~nsStyle##name();                                                      \
+}
+
+#include "nsStyleStructList.h"
+
+#undef STYLE_STRUCT
+
 #ifndef MOZ_STYLO
 void
 Servo_DropNodeData(ServoNodeData* data)
 {
   MOZ_CRASH("stylo: shouldn't be calling Servo_DropNodeData in a "
             "non-MOZ_STYLO build");
 }
 
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -80,11 +80,20 @@ ServoComputedValues* Servo_GetComputedVa
 ServoComputedValues* Servo_GetComputedValuesForAnonymousBox(ServoComputedValues* parentStyleOrNull,
                                                             nsIAtom* pseudoTag);
 void Servo_AddRefComputedValues(ServoComputedValues*);
 void Servo_ReleaseComputedValues(ServoComputedValues*);
 
 // Servo API.
 void Servo_RestyleDocument(RawGeckoDocument* doc, RawServoStyleSet* set);
 
+// Style-struct management.
+#define STYLE_STRUCT(name, checkdata_cb) \
+struct nsStyle##name; \
+void Gecko_Construct_nsStyle##name(nsStyle##name* ptr); \
+void Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr, const nsStyle##name* other); \
+void Gecko_Destroy_nsStyle##name(nsStyle##name* ptr);
+#include "nsStyleStructList.h"
+#undef STYLE_STRUCT
+
 } // extern "C"
 
 #endif // mozilla_ServoBindings_h
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -3280,20 +3280,17 @@ StyleAnimationValue::ExtractComputedValu
           auto styleText = static_cast<const nsStyleText*>(styleStruct);
           nscolor color = styleText->mTextEmphasisColorForeground ?
             aStyleContext->StyleColor()->mColor : styleText->mTextEmphasisColor;
           aComputedValue.SetColorValue(color);
           break;
         }
 
         case eCSSProperty__webkit_text_fill_color: {
-          auto styleText = static_cast<const nsStyleText*>(styleStruct);
-          nscolor color = styleText->mWebkitTextFillColorForeground ?
-            aStyleContext->StyleColor()->mColor : styleText->mWebkitTextFillColor;
-          aComputedValue.SetColorValue(color);
+          aComputedValue.SetColorValue(aStyleContext->GetTextFillColor());
           break;
         }
 
         case eCSSProperty_border_spacing: {
           const nsStyleTableBorder *styleTableBorder =
             static_cast<const nsStyleTableBorder*>(styleStruct);
           nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair);
           nscoordToCSSValue(styleTableBorder->mBorderSpacingCol, pair->mXValue);
new file mode 100644
--- /dev/null
+++ b/layout/style/StyleStructContext.h
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_StyleStructContext_h
+#define mozilla_StyleStructContext_h
+
+#include "CounterStyleManager.h"
+#include "mozilla/LookAndFeel.h"
+#include "nsPresContext.h"
+
+class nsDeviceContext;
+
+/**
+ * Construction context for style structs.
+ *
+ * Certain Gecko style structs have historically taken an nsPresContext
+ * argument in their constructor, which is used to compute various things. This
+ * makes Gecko style structs document-specific (which Servo style structs are
+ * not), and means that the initial values for style-structs cannot be shared
+ * across the entire runtime (as is the case in Servo).
+ *
+ * We'd like to remove this constraint so that Gecko can get the benefits of the
+ * Servo model, and so that Gecko aligns better with the Servo style system when
+ * using it. Unfortunately, this may require a fair amount of work, especially
+ * related to text zoom.
+ *
+ * So as an intermediate step, we define a reduced API set of "things that are
+ * needed when constructing style structs". This just wraps and forwards to an
+ * nsPresContext in the Gecko case, and returns some default not-always-correct
+ * values in the Servo case. We can then focus on reducing this API surface to
+ * zero, at which point this can be removed.
+ *
+ * We don't put the type in namespace mozilla, since we expect it to be
+ * temporary, and the namespacing would clutter up nsStyleStruct.h.
+ */
+#ifdef MOZ_STYLO
+#define SERVO_DEFAULT(default_val) { if (!mPresContext) { return default_val; } }
+#else
+#define SERVO_DEFAULT(default_val) { MOZ_ASSERT(mPresContext); }
+#endif
+class StyleStructContext {
+public:
+  MOZ_IMPLICIT StyleStructContext(nsPresContext* aPresContext)
+    : mPresContext(aPresContext) { MOZ_ASSERT(aPresContext); }
+  static StyleStructContext ServoContext() { return StyleStructContext(); }
+
+  // XXXbholley: Need to make text zoom work with stylo. This probably means
+  // moving the zoom handling out of computed values and into a post-
+  // computation.
+  float TextZoom()
+  {
+    SERVO_DEFAULT(1.0);
+    return mPresContext->TextZoom();
+  }
+
+  const nsFont* GetDefaultFont(uint8_t aFontID)
+  {
+    // NB: The servo case only differ from the default case in terms of which
+    // font pref cache gets used. The distinction is probably unnecessary.
+    SERVO_DEFAULT(mozilla::StaticPresData::Get()->
+                  GetDefaultFont(aFontID, GetLanguageFromCharset()));
+    return mPresContext->GetDefaultFont(aFontID, GetLanguageFromCharset());
+  }
+
+  uint32_t GetBidi()
+  {
+    SERVO_DEFAULT(0);
+    return mPresContext->GetBidi();
+  }
+
+  int32_t AppUnitsPerDevPixel();
+
+  nscoord DevPixelsToAppUnits(int32_t aPixels)
+  {
+    return NSIntPixelsToAppUnits(aPixels, AppUnitsPerDevPixel());
+  }
+
+  typedef mozilla::LookAndFeel LookAndFeel;
+  nscolor DefaultColor()
+  {
+    SERVO_DEFAULT(LookAndFeel::GetColor(LookAndFeel::eColorID_WindowForeground,
+                                        NS_RGB(0x00, 0x00, 0x00)));
+    return mPresContext->DefaultColor();
+  }
+
+  mozilla::CounterStyle* BuildCounterStyle(const nsSubstring& aName)
+  {
+    SERVO_DEFAULT(nullptr);
+    return mPresContext->CounterStyleManager()->BuildCounterStyle(aName);
+  }
+
+  nsIAtom* GetLanguageFromCharset() const
+  {
+    SERVO_DEFAULT(nsGkAtoms::x_western);
+    return mPresContext->GetLanguageFromCharset();
+  }
+
+  already_AddRefed<nsIAtom> GetContentLanguage() const
+  {
+    SERVO_DEFAULT(do_AddRef(nsGkAtoms::x_western));
+    return mPresContext->GetContentLanguage();
+  }
+
+private:
+  nsDeviceContext* DeviceContext()
+  {
+    SERVO_DEFAULT(HackilyFindSomeDeviceContext());
+    return mPresContext->DeviceContext();
+  }
+
+  nsDeviceContext* HackilyFindSomeDeviceContext();
+
+  StyleStructContext() : mPresContext(nullptr) {}
+  nsPresContext* mPresContext;
+};
+
+#undef SERVO_DEFAULT
+
+#endif // mozilla_StyleStructContext_h
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -100,16 +100,17 @@ EXPORTS.mozilla += [
     'StyleContextSource.h',
     'StyleSetHandle.h',
     'StyleSetHandleInlines.h',
     'StyleSheet.h',
     'StyleSheetHandle.h',
     'StyleSheetHandleInlines.h',
     'StyleSheetInfo.h',
     'StyleSheetInlines.h',
+    'StyleStructContext.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'CSS.h',
     'CSSLexer.h',
     'CSSRuleList.h',
     'CSSValue.h',
     'FontFace.h',
--- a/layout/style/nsCSSPropAliasList.h
+++ b/layout/style/nsCSSPropAliasList.h
@@ -318,31 +318,35 @@ CSS_PROP_ALIAS(-webkit-box-shadow,
                box_shadow,
                WebkitBoxShadow,
                WEBKIT_PREFIX_PREF)
 CSS_PROP_ALIAS(-webkit-box-sizing,
                box_sizing,
                WebkitBoxSizing,
                WEBKIT_PREFIX_PREF)
 
-// Alias old flexbox properties to modern flexbox pseudo-equivalents:
+// Alias -webkit-box properties to their -moz-box equivalents.
+// (NOTE: Even though they're aliases, in practice these -webkit properties
+// will behave a bit differently from their -moz versions, if they're
+// accompanied by "display:-webkit-box", because we generate a different frame
+// for those two display values.)
 CSS_PROP_ALIAS(-webkit-box-flex,
-               flex_grow,
+               box_flex,
                WebkitBoxFlex,
                WEBKIT_PREFIX_PREF)
 CSS_PROP_ALIAS(-webkit-box-ordinal-group,
-               order,
+               box_ordinal_group,
                WebkitBoxOrdinalGroup,
                WEBKIT_PREFIX_PREF)
 CSS_PROP_ALIAS(-webkit-box-align,
-               align_items,
+               box_align,
                WebkitBoxAlign,
                WEBKIT_PREFIX_PREF)
 CSS_PROP_ALIAS(-webkit-box-pack,
-               justify_content,
+               box_pack,
                WebkitBoxPack,
                WEBKIT_PREFIX_PREF)
 
 CSS_PROP_ALIAS(-webkit-user-select,
                user_select,
                WebkitUserSelect,
                WEBKIT_PREFIX_PREF)
 
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3923,20 +3923,17 @@ nsComputedDOMStyle::DoGetTextSizeAdjust(
   }
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWebkitTextFillColor()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  const nsStyleText* text = StyleText();
-  nscolor color = text->mWebkitTextFillColorForeground ?
-    StyleColor()->mColor : text->mWebkitTextFillColor;
-  SetToRGBAColor(val, color);
+  SetToRGBAColor(val, mStyleContext->GetTextFillColor());
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPointerEvents()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -2446,17 +2446,17 @@ nsRuleNode::SetDefaultOnRoot(const nsSty
       else {
         fontData->mFont.size = fontData->mSize;
       }
       aContext->SetStyle(eStyleStruct_Font, fontData);
       return fontData;
     }
     case eStyleStruct_Display:
     {
-      nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay();
+      nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay(mPresContext);
       aContext->SetStyle(eStyleStruct_Display, disp);
       return disp;
     }
     case eStyleStruct_Visibility:
     {
       nsStyleVisibility* vis = new (mPresContext) nsStyleVisibility(mPresContext);
       aContext->SetStyle(eStyleStruct_Visibility, vis);
       return vis;
@@ -2464,47 +2464,47 @@ nsRuleNode::SetDefaultOnRoot(const nsSty
     case eStyleStruct_Text:
     {
       nsStyleText* text = new (mPresContext) nsStyleText(mPresContext);
       aContext->SetStyle(eStyleStruct_Text, text);
       return text;
     }
     case eStyleStruct_TextReset:
     {
-      nsStyleTextReset* text = new (mPresContext) nsStyleTextReset();
+      nsStyleTextReset* text = new (mPresContext) nsStyleTextReset(mPresContext);
       aContext->SetStyle(eStyleStruct_TextReset, text);
       return text;
     }
     case eStyleStruct_Color:
     {
       nsStyleColor* color = new (mPresContext) nsStyleColor(mPresContext);
       aContext->SetStyle(eStyleStruct_Color, color);
       return color;
     }
     case eStyleStruct_Background:
     {
-      nsStyleBackground* bg = new (mPresContext) nsStyleBackground();
+      nsStyleBackground* bg = new (mPresContext) nsStyleBackground(mPresContext);
       aContext->SetStyle(eStyleStruct_Background, bg);
       return bg;
     }
     case eStyleStruct_Margin:
     {
-      nsStyleMargin* margin = new (mPresContext) nsStyleMargin();
+      nsStyleMargin* margin = new (mPresContext) nsStyleMargin(mPresContext);
       aContext->SetStyle(eStyleStruct_Margin, margin);
       return margin;
     }
     case eStyleStruct_Border:
     {
       nsStyleBorder* border = new (mPresContext) nsStyleBorder(mPresContext);
       aContext->SetStyle(eStyleStruct_Border, border);
       return border;
     }
     case eStyleStruct_Padding:
     {
-      nsStylePadding* padding = new (mPresContext) nsStylePadding();
+      nsStylePadding* padding = new (mPresContext) nsStylePadding(mPresContext);
       aContext->SetStyle(eStyleStruct_Padding, padding);
       return padding;
     }
     case eStyleStruct_Outline:
     {
       nsStyleOutline* outline = new (mPresContext) nsStyleOutline(mPresContext);
       aContext->SetStyle(eStyleStruct_Outline, outline);
       return outline;
@@ -2512,83 +2512,83 @@ nsRuleNode::SetDefaultOnRoot(const nsSty
     case eStyleStruct_List:
     {
       nsStyleList* list = new (mPresContext) nsStyleList(mPresContext);
       aContext->SetStyle(eStyleStruct_List, list);
       return list;
     }
     case eStyleStruct_Position:
     {
-      nsStylePosition* pos = new (mPresContext) nsStylePosition();
+      nsStylePosition* pos = new (mPresContext) nsStylePosition(mPresContext);
       aContext->SetStyle(eStyleStruct_Position, pos);
       return pos;
     }
     case eStyleStruct_Table:
     {
-      nsStyleTable* table = new (mPresContext) nsStyleTable();
+      nsStyleTable* table = new (mPresContext) nsStyleTable(mPresContext);
       aContext->SetStyle(eStyleStruct_Table, table);
       return table;
     }
     case eStyleStruct_TableBorder:
     {
-      nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder();
+      nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder(mPresContext);
       aContext->SetStyle(eStyleStruct_TableBorder, table);
       return table;
     }
     case eStyleStruct_Content:
     {
-      nsStyleContent* content = new (mPresContext) nsStyleContent();
+      nsStyleContent* content = new (mPresContext) nsStyleContent(mPresContext);
       aContext->SetStyle(eStyleStruct_Content, content);
       return content;
     }
     case eStyleStruct_Quotes:
     {
-      nsStyleQuotes* quotes = new (mPresContext) nsStyleQuotes();
+      nsStyleQuotes* quotes = new (mPresContext) nsStyleQuotes(mPresContext);
       aContext->SetStyle(eStyleStruct_Quotes, quotes);
       return quotes;
     }
     case eStyleStruct_UserInterface:
     {
-      nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface();
+      nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface(mPresContext);
       aContext->SetStyle(eStyleStruct_UserInterface, ui);
       return ui;
     }
     case eStyleStruct_UIReset:
     {
-      nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset();
+      nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset(mPresContext);
       aContext->SetStyle(eStyleStruct_UIReset, ui);
       return ui;
     }
     case eStyleStruct_XUL:
     {
-      nsStyleXUL* xul = new (mPresContext) nsStyleXUL();
+      nsStyleXUL* xul = new (mPresContext) nsStyleXUL(mPresContext);
       aContext->SetStyle(eStyleStruct_XUL, xul);
       return xul;
     }
     case eStyleStruct_Column:
     {
       nsStyleColumn* column = new (mPresContext) nsStyleColumn(mPresContext);
       aContext->SetStyle(eStyleStruct_Column, column);
       return column;
     }
     case eStyleStruct_SVG:
     {
-      nsStyleSVG* svg = new (mPresContext) nsStyleSVG();
+      nsStyleSVG* svg = new (mPresContext) nsStyleSVG(mPresContext);
       aContext->SetStyle(eStyleStruct_SVG, svg);
       return svg;
     }
     case eStyleStruct_SVGReset:
     {
-      nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset();
+      nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset(mPresContext);
       aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
       return svgReset;
     }
     case eStyleStruct_Variables:
     {
-      nsStyleVariables* vars = new (mPresContext) nsStyleVariables();
+      nsStyleVariables* vars = new (mPresContext) nsStyleVariables(mPresContext);
       aContext->SetStyle(eStyleStruct_Variables, vars);
       return vars;
     }
     default:
       /*
        * unhandled case: nsStyleStructID_Length.
        * last item of nsStyleStructID, to know its length.
        */
@@ -2597,23 +2597,22 @@ nsRuleNode::SetDefaultOnRoot(const nsSty
   }
   return nullptr;
 }
 
 /**
  * Begin an nsRuleNode::Compute*Data function for an inherited struct.
  *
  * @param type_ The nsStyle* type this function computes.
- * @param ctorargs_ The arguments used for the default nsStyle* constructor.
  * @param data_ Variable (declared here) holding the result of this
  *              function.
  * @param parentdata_ Variable (declared here) holding the parent style
  *                    context's data for this struct.
  */
-#define COMPUTE_START_INHERITED(type_, ctorargs_, data_, parentdata_)         \
+#define COMPUTE_START_INHERITED(type_, data_, parentdata_)                    \
   NS_ASSERTION(aRuleDetail != eRuleFullInherited,                             \
                "should not have bothered calling Compute*Data");              \
                                                                               \
   nsStyleContext* parentContext = aContext->GetParent();                      \
                                                                               \
   nsStyle##type_* data_ = nullptr;                                            \
   mozilla::Maybe<nsStyle##type_> maybeFakeParentData;                         \
   const nsStyle##type_* parentdata_ = nullptr;                                \
@@ -2623,58 +2622,57 @@ nsRuleNode::SetDefaultOnRoot(const nsSty
   /* can't call parentContext->Style##type_() since it could recur into */    \
   /* setting the same struct on the same rule node, causing a leak. */        \
   if (aRuleDetail != eRuleFullReset &&                                        \
       (!aStartStruct || (aRuleDetail != eRulePartialReset &&                  \
                          aRuleDetail != eRuleNone))) {                        \
     if (parentContext) {                                                      \
       parentdata_ = parentContext->Style##type_();                            \
     } else {                                                                  \
-      maybeFakeParentData.emplace ctorargs_;                                  \
+      maybeFakeParentData.emplace(mPresContext);                              \
       parentdata_ = maybeFakeParentData.ptr();                                \
     }                                                                         \
   }                                                                           \
   if (eStyleStruct_##type_ == eStyleStruct_Variables)                         \
     /* no need to copy construct an nsStyleVariables, as we will copy */      \
     /* inherited variables (and call SetUncacheable()) in */                  \
     /* ComputeVariablesData */                                                \
-    data_ = new (mPresContext) nsStyle##type_ ctorargs_;                      \
+    data_ = new (mPresContext) nsStyle##type_(mPresContext);                  \
   else if (aStartStruct)                                                      \
     /* We only need to compute the delta between this computed data and */    \
     /* our computed data. */                                                  \
     data_ = new (mPresContext)                                                \
             nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct));      \
   else {                                                                      \
     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {     \
       /* No question. We will have to inherit. Go ahead and init */           \
       /* with inherited vals from parent. */                                  \
       conditions.SetUncacheable();                                            \
       if (parentdata_)                                                        \
         data_ = new (mPresContext) nsStyle##type_(*parentdata_);              \
       else                                                                    \
-        data_ = new (mPresContext) nsStyle##type_ ctorargs_;                  \
+        data_ = new (mPresContext) nsStyle##type_(mPresContext);              \
     }                                                                         \
     else                                                                      \
-      data_ = new (mPresContext) nsStyle##type_ ctorargs_;                    \
+      data_ = new (mPresContext) nsStyle##type_(mPresContext);                \
   }                                                                           \
                                                                               \
   if (!parentdata_)                                                           \
     parentdata_ = data_;
 
 /**
  * Begin an nsRuleNode::Compute*Data function for a reset struct.
  *
  * @param type_ The nsStyle* type this function computes.
- * @param ctorargs_ The arguments used for the default nsStyle* constructor.
  * @param data_ Variable (declared here) holding the result of this
  *              function.
  * @param parentdata_ Variable (declared here) holding the parent style
  *                    context's data for this struct.
  */
-#define COMPUTE_START_RESET(type_, ctorargs_, data_, parentdata_)             \
+#define COMPUTE_START_RESET(type_, data_, parentdata_)                        \
   NS_ASSERTION(aRuleDetail != eRuleFullInherited,                             \
                "should not have bothered calling Compute*Data");              \
                                                                               \
   nsStyleContext* parentContext = aContext->GetParent();                      \
   /* Reset structs don't inherit from first-line */                           \
   /* See similar code in WalkRuleTree */                                      \
   while (parentContext &&                                                     \
          parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) {      \
@@ -2683,30 +2681,30 @@ nsRuleNode::SetDefaultOnRoot(const nsSty
                                                                               \
   nsStyle##type_* data_;                                                      \
   if (aStartStruct)                                                           \
     /* We only need to compute the delta between this computed data and */    \
     /* our computed data. */                                                  \
     data_ = new (mPresContext)                                                \
             nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct));      \
   else                                                                        \
-    data_ = new (mPresContext) nsStyle##type_ ctorargs_;                      \
+    data_ = new (mPresContext) nsStyle##type_(mPresContext);                  \
                                                                               \
   /* If |conditions.Cacheable()| might be true by the time we're done, we */  \
   /* can't call parentContext->Style##type_() since it could recur into */    \
   /* setting the same struct on the same rule node, causing a leak. */        \
   mozilla::Maybe<nsStyle##type_> maybeFakeParentData;                         \
   const nsStyle##type_* parentdata_ = data_;                                  \
   if (aRuleDetail != eRuleFullReset &&                                        \
       aRuleDetail != eRulePartialReset &&                                     \
       aRuleDetail != eRuleNone) {                                             \
     if (parentContext) {                                                      \
       parentdata_ = parentContext->Style##type_();                            \
     } else {                                                                  \
-      maybeFakeParentData.emplace ctorargs_;                                  \
+      maybeFakeParentData.emplace(mPresContext);                              \
       parentdata_ = maybeFakeParentData.ptr();                                \
     }                                                                         \
   }                                                                           \
   RuleNodeCacheConditions conditions = aConditions;
 
 /**
  * End an nsRuleNode::Compute*Data function for an inherited struct.
  *
@@ -4032,17 +4030,17 @@ nsRuleNode::SetGenericFont(nsPresContext
 const void*
 nsRuleNode::ComputeFontData(void* aStartStruct,
                             const nsRuleData* aRuleData,
                             nsStyleContext* aContext,
                             nsRuleNode* aHighestNode,
                             const RuleDetail aRuleDetail,
                             const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_INHERITED(Font, (mPresContext), font, parentFont)
+  COMPUTE_START_INHERITED(Font, font, parentFont)
 
   // NOTE:  The |aRuleDetail| passed in is a little bit conservative due
   // to the -moz-system-font property.  We really don't need to consider
   // it here in determining whether to cache in the rule tree.  However,
   // we do need to consider it in WalkRuleTree when deciding whether to
   // walk further up the tree.  So this means that when the font struct
   // is fully specified using *longhand* properties (excluding
   // -moz-system-font), we won't cache in the rule tree even though we
@@ -4354,17 +4352,17 @@ struct SetLineHeightCalcOps : public css
 const void*
 nsRuleNode::ComputeTextData(void* aStartStruct,
                             const nsRuleData* aRuleData,
                             nsStyleContext* aContext,
                             nsRuleNode* aHighestNode,
                             const RuleDetail aRuleDetail,
                             const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_INHERITED(Text, (mPresContext), text, parentText)
+  COMPUTE_START_INHERITED(Text, text, parentText)
 
   // tab-size: integer, inherit
   SetDiscrete(*aRuleData->ValueForTabSize(),
               text->mTabSize, conditions,
               SETDSC_INTEGER | SETDSC_UNSET_INHERIT, parentText->mTabSize,
               NS_STYLE_TABSIZE_INITIAL, 0, 0, 0, 0);
 
   // letter-spacing: normal, length, inherit
@@ -4726,17 +4724,17 @@ nsRuleNode::ComputeTextData(void* aStart
 const void*
 nsRuleNode::ComputeTextResetData(void* aStartStruct,
                                  const nsRuleData* aRuleData,
                                  nsStyleContext* aContext,
                                  nsRuleNode* aHighestNode,
                                  const RuleDetail aRuleDetail,
                                  const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(TextReset, (), text, parentText)
+  COMPUTE_START_RESET(TextReset, text, parentText)
 
   // vertical-align: enum, length, percent, calc, inherit
   const nsCSSValue* verticalAlignValue = aRuleData->ValueForVerticalAlign();
   if (!SetCoord(*verticalAlignValue, text->mVerticalAlign,
                 parentText->mVerticalAlign,
                 SETCOORD_LPH | SETCOORD_ENUMERATED | SETCOORD_STORE_CALC,
                 aContext, mPresContext, conditions)) {
     if (eCSSUnit_Initial == verticalAlignValue->GetUnit() ||
@@ -4888,17 +4886,17 @@ nsRuleNode::ComputeTextResetData(void* a
 const void*
 nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
                                      const nsRuleData* aRuleData,
                                      nsStyleContext* aContext,
                                      nsRuleNode* aHighestNode,
                                      const RuleDetail aRuleDetail,
                                      const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_INHERITED(UserInterface, (), ui, parentUI)
+  COMPUTE_START_INHERITED(UserInterface, ui, parentUI)
 
   // cursor: enum, url, inherit
   const nsCSSValue* cursorValue = aRuleData->ValueForCursor();
   nsCSSUnit cursorUnit = cursorValue->GetUnit();
   if (cursorUnit != eCSSUnit_Null) {
     delete [] ui->mCursorArray;
     ui->mCursorArray = nullptr;
     ui->mCursorArrayLength = 0;
@@ -4983,17 +4981,17 @@ nsRuleNode::ComputeUserInterfaceData(voi
 const void*
 nsRuleNode::ComputeUIResetData(void* aStartStruct,
                                const nsRuleData* aRuleData,
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
                                const RuleDetail aRuleDetail,
                                const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(UIReset, (), ui, parentUI)
+  COMPUTE_START_RESET(UIReset, ui, parentUI)
 
   // user-select: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForUserSelect(),
               ui->mUserSelect, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentUI->mUserSelect,
               NS_STYLE_USER_SELECT_AUTO, 0, 0, 0, 0);
 
@@ -5229,17 +5227,17 @@ GetWillChangeBitFieldFromPropFlags(const
 const void*
 nsRuleNode::ComputeDisplayData(void* aStartStruct,
                                const nsRuleData* aRuleData,
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
                                const RuleDetail aRuleDetail,
                                const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(Display, (), display, parentDisplay)
+  COMPUTE_START_RESET(Display, display, parentDisplay)
 
   // We may have ended up with aStartStruct's values of mDisplay and
   // mFloats, but those may not be correct if our style data overrides
   // its position or float properties.  Reset to mOriginalDisplay and
   // mOriginalFloats; it if turns out we still need the display/floats
   // adjustments we'll do them below.
   display->mDisplay = display->mOriginalDisplay;
   display->mFloats = display->mOriginalFloats;
@@ -6373,18 +6371,17 @@ nsRuleNode::ComputeDisplayData(void* aSt
 const void*
 nsRuleNode::ComputeVisibilityData(void* aStartStruct,
                                   const nsRuleData* aRuleData,
                                   nsStyleContext* aContext,
                                   nsRuleNode* aHighestNode,
                                   const RuleDetail aRuleDetail,
                                   const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_INHERITED(Visibility, (mPresContext),
-                          visibility, parentVisibility)
+  COMPUTE_START_INHERITED(Visibility, visibility, parentVisibility)
 
   // IMPORTANT: No properties in this struct have lengths in them.  We
   // depend on this since CalcLengthWith can call StyleVisibility()
   // to get the language for resolving fonts!
 
   // direction: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForDirection(), visibility->mDirection,
               conditions,
@@ -6473,17 +6470,17 @@ nsRuleNode::ComputeVisibilityData(void* 
 const void*
 nsRuleNode::ComputeColorData(void* aStartStruct,
                              const nsRuleData* aRuleData,
                              nsStyleContext* aContext,
                              nsRuleNode* aHighestNode,
                              const RuleDetail aRuleDetail,
                              const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_INHERITED(Color, (mPresContext), color, parentColor)
+  COMPUTE_START_INHERITED(Color, color, parentColor)
 
   // color: color, string, inherit
   // Special case for currentColor.  According to CSS3, setting color to 'currentColor'
   // should behave as if it is inherited
   const nsCSSValue* colorValue = aRuleData->ValueForColor();
   if ((colorValue->GetUnit() == eCSSUnit_EnumColor &&
        colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) ||
       colorValue->GetUnit() == eCSSUnit_Unset) {
@@ -6954,17 +6951,17 @@ FillBackgroundList(AutoTArray< nsStyleIm
 const void*
 nsRuleNode::ComputeBackgroundData(void* aStartStruct,
                                   const nsRuleData* aRuleData,
                                   nsStyleContext* aContext,
                                   nsRuleNode* aHighestNode,
                                   const RuleDetail aRuleDetail,
                                   const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(Background, (), bg, parentBG)
+  COMPUTE_START_RESET(Background, bg, parentBG)
 
   // background-color: color, string, inherit
   const nsCSSValue* backColorValue = aRuleData->ValueForBackgroundColor();
   if (eCSSUnit_Initial == backColorValue->GetUnit() ||
       eCSSUnit_Unset == backColorValue->GetUnit()) {
     bg->mBackgroundColor = NS_RGBA(0, 0, 0, 0);
   } else if (!SetColor(*backColorValue, parentBG->mBackgroundColor,
                        mPresContext, aContext, bg->mBackgroundColor,
@@ -7098,17 +7095,17 @@ nsRuleNode::ComputeBackgroundData(void* 
 const void*
 nsRuleNode::ComputeMarginData(void* aStartStruct,
                               const nsRuleData* aRuleData,
                               nsStyleContext* aContext,
                               nsRuleNode* aHighestNode,
                               const RuleDetail aRuleDetail,
                               const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(Margin, (), margin, parentMargin)
+  COMPUTE_START_RESET(Margin, margin, parentMargin)
 
   // margin: length, percent, calc, inherit
   const nsCSSProperty* subprops =
     nsCSSProps::SubpropertyEntryFor(eCSSProperty_margin);
   nsStyleCoord coord;
   NS_FOR_CSS_SIDES(side) {
     nsStyleCoord parentCoord = parentMargin->mMargin.Get(side);
     if (SetCoord(*aRuleData->ValueFor(subprops[side]),
@@ -7204,17 +7201,17 @@ SetBorderImageSlice(const nsCSSValue& aV
 const void*
 nsRuleNode::ComputeBorderData(void* aStartStruct,
                               const nsRuleData* aRuleData,
                               nsStyleContext* aContext,
                               nsRuleNode* aHighestNode,
                               const RuleDetail aRuleDetail,
                               const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder)
+  COMPUTE_START_RESET(Border, border, parentBorder)
 
   // box-decoration-break: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForBoxDecorationBreak(),
               border->mBoxDecorationBreak, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentBorder->mBoxDecorationBreak,
               NS_STYLE_BOX_DECORATION_BREAK_SLICE, 0, 0, 0, 0);
 
@@ -7547,17 +7544,17 @@ nsRuleNode::ComputeBorderData(void* aSta
 const void*
 nsRuleNode::ComputePaddingData(void* aStartStruct,
                                const nsRuleData* aRuleData,
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
                                const RuleDetail aRuleDetail,
                                const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(Padding, (), padding, parentPadding)
+  COMPUTE_START_RESET(Padding, padding, parentPadding)
 
   // padding: length, percent, calc, inherit
   const nsCSSProperty* subprops =
     nsCSSProps::SubpropertyEntryFor(eCSSProperty_padding);
   nsStyleCoord coord;
   NS_FOR_CSS_SIDES(side) {
     nsStyleCoord parentCoord = parentPadding->mPadding.Get(side);
     if (SetCoord(*aRuleData->ValueFor(subprops[side]),
@@ -7576,17 +7573,17 @@ nsRuleNode::ComputePaddingData(void* aSt
 const void*
 nsRuleNode::ComputeOutlineData(void* aStartStruct,
                                const nsRuleData* aRuleData,
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
                                const RuleDetail aRuleDetail,
                                const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(Outline, (mPresContext), outline, parentOutline)
+  COMPUTE_START_RESET(Outline, outline, parentOutline)
 
   // outline-width: length, enum, inherit
   const nsCSSValue* outlineWidthValue = aRuleData->ValueForOutlineWidth();
   if (eCSSUnit_Initial == outlineWidthValue->GetUnit() ||
       eCSSUnit_Unset == outlineWidthValue->GetUnit()) {
     outline->mOutlineWidth =
       nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
   }
@@ -7687,17 +7684,17 @@ nsRuleNode::ComputeOutlineData(void* aSt
 const void*
 nsRuleNode::ComputeListData(void* aStartStruct,
                             const nsRuleData* aRuleData,
                             nsStyleContext* aContext,
                             nsRuleNode* aHighestNode,
                             const RuleDetail aRuleDetail,
                             const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_INHERITED(List, (mPresContext), list, parentList)
+  COMPUTE_START_INHERITED(List, list, parentList)
 
   // list-style-type: string, none, inherit, initial
   const nsCSSValue* typeValue = aRuleData->ValueForListStyleType();
   switch (typeValue->GetUnit()) {
     case eCSSUnit_Unset:
     case eCSSUnit_Inherit: {
       conditions.SetUncacheable();
       nsString type;
@@ -8144,17 +8141,17 @@ SetGridLine(const nsCSSValue& aValue,
 const void*
 nsRuleNode::ComputePositionData(void* aStartStruct,
                                 const nsRuleData* aRuleData,
                                 nsStyleContext* aContext,
                                 nsRuleNode* aHighestNode,
                                 const RuleDetail aRuleDetail,
                                 const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(Position, (), pos, parentPos)
+  COMPUTE_START_RESET(Position, pos, parentPos)
 
   // box offsets: length, percent, calc, auto, inherit
   static const nsCSSProperty offsetProps[] = {
     eCSSProperty_top,
     eCSSProperty_right,
     eCSSProperty_bottom,
     eCSSProperty_left
   };
@@ -8524,17 +8521,17 @@ nsRuleNode::ComputePositionData(void* aS
 const void*
 nsRuleNode::ComputeTableData(void* aStartStruct,
                              const nsRuleData* aRuleData,
                              nsStyleContext* aContext,
                              nsRuleNode* aHighestNode,
                              const RuleDetail aRuleDetail,
                              const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(Table, (), table, parentTable)
+  COMPUTE_START_RESET(Table, table, parentTable)
 
   // table-layout: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForTableLayout(),
               table->mLayoutStrategy, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentTable->mLayoutStrategy,
               NS_STYLE_TABLE_LAYOUT_AUTO, 0, 0, 0, 0);
 
@@ -8550,17 +8547,17 @@ nsRuleNode::ComputeTableData(void* aStar
 const void*
 nsRuleNode::ComputeTableBorderData(void* aStartStruct,
                                    const nsRuleData* aRuleData,
                                    nsStyleContext* aContext,
                                    nsRuleNode* aHighestNode,
                                    const RuleDetail aRuleDetail,
                                    const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_INHERITED(TableBorder, (), table, parentTable)
+  COMPUTE_START_INHERITED(TableBorder, table, parentTable)
 
   // border-collapse: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForBorderCollapse(), table->mBorderCollapse,
               conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentTable->mBorderCollapse,
               NS_STYLE_BORDER_SEPARATE, 0, 0, 0, 0);
 
@@ -8611,17 +8608,17 @@ nsRuleNode::ComputeContentData(void* aSt
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
                                const RuleDetail aRuleDetail,
                                const RuleNodeCacheConditions aConditions)
 {
   uint32_t count;
   nsAutoString buffer;
 
-  COMPUTE_START_RESET(Content, (), content, parentContent)
+  COMPUTE_START_RESET(Content, content, parentContent)
 
   // content: [string, url, counter, attr, enum]+, normal, none, inherit
   const nsCSSValue* contentValue = aRuleData->ValueForContent();
   switch (contentValue->GetUnit()) {
   case eCSSUnit_Null:
     break;
 
   case eCSSUnit_Normal:
@@ -8848,17 +8845,17 @@ nsRuleNode::ComputeContentData(void* aSt
 const void*
 nsRuleNode::ComputeQuotesData(void* aStartStruct,
                               const nsRuleData* aRuleData,
                               nsStyleContext* aContext,
                               nsRuleNode* aHighestNode,
                               const RuleDetail aRuleDetail,
                               const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_INHERITED(Quotes, (), quotes, parentQuotes)
+  COMPUTE_START_INHERITED(Quotes, quotes, parentQuotes)
 
   // quotes: inherit, initial, none, [string string]+
   const nsCSSValue* quotesValue = aRuleData->ValueForQuotes();
   switch (quotesValue->GetUnit()) {
   case eCSSUnit_Null:
     break;
   case eCSSUnit_Inherit:
   case eCSSUnit_Unset:
@@ -8903,17 +8900,17 @@ nsRuleNode::ComputeQuotesData(void* aSta
 const void*
 nsRuleNode::ComputeXULData(void* aStartStruct,
                            const nsRuleData* aRuleData,
                            nsStyleContext* aContext,
                            nsRuleNode* aHighestNode,
                            const RuleDetail aRuleDetail,
                            const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(XUL, (), xul, parentXUL)
+  COMPUTE_START_RESET(XUL, xul, parentXUL)
 
   // box-align: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForBoxAlign(),
               xul->mBoxAlign, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentXUL->mBoxAlign,
               NS_STYLE_BOX_ALIGN_STRETCH, 0, 0, 0, 0);
 
@@ -8969,17 +8966,17 @@ nsRuleNode::ComputeXULData(void* aStartS
 const void*
 nsRuleNode::ComputeColumnData(void* aStartStruct,
                               const nsRuleData* aRuleData,
                               nsStyleContext* aContext,
                               nsRuleNode* aHighestNode,
                               const RuleDetail aRuleDetail,
                               const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(Column, (mPresContext), column, parent)
+  COMPUTE_START_RESET(Column, column, parent)
 
   // column-width: length, auto, inherit
   SetCoord(*aRuleData->ValueForColumnWidth(),
            column->mColumnWidth, parent->mColumnWidth,
            SETCOORD_LAH | SETCOORD_INITIAL_AUTO |
              SETCOORD_CALC_LENGTH_ONLY | SETCOORD_CALC_CLAMP_NONNEGATIVE |
              SETCOORD_UNSET_INITIAL,
            aContext, mPresContext, conditions);
@@ -9192,17 +9189,17 @@ SetSVGOpacity(const nsCSSValue& aValue,
 const void*
 nsRuleNode::ComputeSVGData(void* aStartStruct,
                            const nsRuleData* aRuleData,
                            nsStyleContext* aContext,
                            nsRuleNode* aHighestNode,
                            const RuleDetail aRuleDetail,
                            const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_INHERITED(SVG, (), svg, parentSVG)
+  COMPUTE_START_INHERITED(SVG, svg, parentSVG)
 
   // clip-rule: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForClipRule(),
               svg->mClipRule, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mClipRule,
               NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
 
@@ -9732,17 +9729,17 @@ nsRuleNode::SetStyleFilterToCSSValue(nsS
 const void*
 nsRuleNode::ComputeSVGResetData(void* aStartStruct,
                                 const nsRuleData* aRuleData,
                                 nsStyleContext* aContext,
                                 nsRuleNode* aHighestNode,
                                 const RuleDetail aRuleDetail,
                                 const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_RESET(SVGReset, (), svgReset, parentSVGReset)
+  COMPUTE_START_RESET(SVGReset, svgReset, parentSVGReset)
 
   // stop-color:
   const nsCSSValue* stopColorValue = aRuleData->ValueForStopColor();
   if (eCSSUnit_Initial == stopColorValue->GetUnit() ||
       eCSSUnit_Unset == stopColorValue->GetUnit()) {
     svgReset->mStopColor = NS_RGB(0, 0, 0);
   } else {
     SetColor(*stopColorValue, parentSVGReset->mStopColor,
@@ -10026,17 +10023,17 @@ nsRuleNode::ComputeSVGResetData(void* aS
 const void*
 nsRuleNode::ComputeVariablesData(void* aStartStruct,
                                  const nsRuleData* aRuleData,
                                  nsStyleContext* aContext,
                                  nsRuleNode* aHighestNode,
                                  const RuleDetail aRuleDetail,
                                  const RuleNodeCacheConditions aConditions)
 {
-  COMPUTE_START_INHERITED(Variables, (), variables, parentVariables)
+  COMPUTE_START_INHERITED(Variables, variables, parentVariables)
 
   MOZ_ASSERT(aRuleData->mVariables,
              "shouldn't be in ComputeVariablesData if there were no variable "
              "declarations specified");
 
   CSSVariableResolver resolver(&variables->mVariables);
   resolver.Resolve(&parentVariables->mVariables,
                    aRuleData->mVariables);
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -500,22 +500,22 @@ nsStyleContext::CreateEmptyStyleData(con
   MOZ_ASSERT(!mChild && !mEmptyChild &&
              !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
              !GetCachedStyleData(aSID),
              "This style should not have been computed");
 
   void* result;
   nsPresContext* presContext = PresContext();
   switch (aSID) {
-#define UNIQUE_CASE(c_, ...) \
+#define UNIQUE_CASE(c_) \
     case eStyleStruct_##c_: \
-      result = new (presContext) nsStyle##c_(__VA_ARGS__); \
+      result = new (presContext) nsStyle##c_(presContext); \
       break;
 
-  UNIQUE_CASE(Border, presContext)
+  UNIQUE_CASE(Border)
   UNIQUE_CASE(Padding)
 
 #undef UNIQUE_CASE
 
   default:
     NS_ERROR("Struct type not supported.");
     return nullptr;
   }
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -167,16 +167,26 @@ public:
   //    non-null, GetStyleIfVisited()->mSource == aSourceIfVisited
   //  * RelevantLinkVisited() == aRelevantLinkVisited
   already_AddRefed<nsStyleContext>
   FindChildWithRules(const nsIAtom* aPseudoTag,
                      mozilla::NonOwningStyleContextSource aSource,
                      mozilla::NonOwningStyleContextSource aSourceIfVisited,
                      bool aRelevantLinkVisited);
 
+  /**
+   * Get the color that should be used to fill text: either
+   * the current foreground color, or a separately-specified text fill color.
+   */
+  nscolor GetTextFillColor() {
+    const nsStyleText* textStyle = StyleText();
+    return textStyle->mWebkitTextFillColorForeground
+           ? StyleColor()->mColor : textStyle->mWebkitTextFillColor;
+  }
+
   // Does this style context or any of its ancestors have text
   // decoration lines?
   // Differs from nsStyleTextReset::HasTextDecorationLines, which tests
   // only the data for a single context.
   bool HasTextDecorationLines() const
     { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATION_LINES); }
 
   // Whether any line break inside should be suppressed? If this returns
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -10,16 +10,17 @@
  */
 
 #include "nsStyleStruct.h"
 #include "nsStyleStructInlines.h"
 #include "nsStyleConsts.h"
 #include "nsThemeConstants.h"
 #include "nsString.h"
 #include "nsPresContext.h"
+#include "nsIAppShellService.h"
 #include "nsIWidget.h"
 #include "nsCRTGlue.h"
 #include "nsCSSParser.h"
 #include "nsCSSProps.h"
 
 #include "nsCOMPtr.h"
 
 #include "nsBidiUtils.h"
@@ -87,37 +88,53 @@ static bool EqualImages(imgIRequest *aIm
 static int safe_strcmp(const char16_t* a, const char16_t* b)
 {
   if (!a || !b) {
     return (int)(a - b);
   }
   return NS_strcmp(a, b);
 }
 
+int32_t
+StyleStructContext::AppUnitsPerDevPixel()
+{
+  return DeviceContext()->AppUnitsPerDevPixel();
+}
+
+nsDeviceContext*
+StyleStructContext::HackilyFindSomeDeviceContext()
+{
+  nsCOMPtr<nsIAppShellService> appShell(do_GetService("@mozilla.org/appshell/appShellService;1"));
+  MOZ_ASSERT(appShell);
+  nsCOMPtr<mozIDOMWindowProxy> win;
+  appShell->GetHiddenDOMWindow(getter_AddRefs(win));
+  return nsLayoutUtils::GetDeviceContextForScreenInfo(static_cast<nsPIDOMWindowOuter*>(win.get()));
+}
+
 static bool AreShadowArraysEqual(nsCSSShadowArray* lhs,
                                  nsCSSShadowArray* rhs);
 
 // --------------------
 // nsStyleFont
 //
-nsStyleFont::nsStyleFont(const nsFont& aFont, nsPresContext *aPresContext)
+nsStyleFont::nsStyleFont(const nsFont& aFont, StyleStructContext aContext)
   : mFont(aFont)
-  , mSize(nsStyleFont::ZoomText(aPresContext, mFont.size))
+  , mSize(nsStyleFont::ZoomText(aContext, mFont.size))
   , mGenericID(kGenericFont_NONE)
   , mScriptLevel(0)
   , mMathVariant(NS_MATHML_MATHVARIANT_NONE)
   , mMathDisplay(NS_MATHML_DISPLAYSTYLE_INLINE)
   , mMinFontSizeRatio(100) // 100%
   , mExplicitLanguage(false)
   , mAllowZoom(true)
   , mScriptUnconstrainedSize(mSize)
-  , mScriptMinSize(aPresContext->CSSTwipsToAppUnits(
+  , mScriptMinSize(nsPresContext::CSSTwipsToAppUnits(
       NS_POINTS_TO_TWIPS(NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT)))
   , mScriptSizeMultiplier(NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER)
-  , mLanguage(GetLanguage(aPresContext))
+  , mLanguage(GetLanguage(aContext))
 {
   MOZ_COUNT_CTOR(nsStyleFont);
   mFont.size = mSize;
 }
 
 nsStyleFont::nsStyleFont(const nsStyleFont& aSrc)
   : mFont(aSrc.mFont)
   , mSize(aSrc.mSize)
@@ -131,19 +148,19 @@ nsStyleFont::nsStyleFont(const nsStyleFo
   , mScriptUnconstrainedSize(aSrc.mScriptUnconstrainedSize)
   , mScriptMinSize(aSrc.mScriptMinSize)
   , mScriptSizeMultiplier(aSrc.mScriptSizeMultiplier)
   , mLanguage(aSrc.mLanguage)
 {
   MOZ_COUNT_CTOR(nsStyleFont);
 }
 
-nsStyleFont::nsStyleFont(nsPresContext* aPresContext)
-  : nsStyleFont(*(aPresContext->GetDefaultFont(
-      kPresContext_DefaultVariableFont_ID, nullptr)), aPresContext)
+nsStyleFont::nsStyleFont(StyleStructContext aContext)
+  : nsStyleFont(*aContext.GetDefaultFont(kPresContext_DefaultVariableFont_ID),
+                aContext)
 {
 }
 
 void 
 nsStyleFont::Destroy(nsPresContext* aContext) {
   this->~nsStyleFont();
   aContext->PresShell()->
     FreeByObjectID(eArenaObjectID_nsStyleFont, this);
@@ -191,42 +208,42 @@ nsChangeHint nsStyleFont::CalcDifference
       mScriptSizeMultiplier != aOther.mScriptSizeMultiplier) {
     return nsChangeHint_NeutralChange;
   }
 
   return NS_STYLE_HINT_NONE;
 }
 
 /* static */ nscoord
-nsStyleFont::ZoomText(nsPresContext *aPresContext, nscoord aSize)
+nsStyleFont::ZoomText(StyleStructContext aContext, nscoord aSize)
 {
   // aSize can be negative (e.g.: calc(-1px)) so we can't assert that here.
   // The caller is expected deal with that.
-  return NSToCoordTruncClamped(float(aSize) * aPresContext->TextZoom());
+  return NSToCoordTruncClamped(float(aSize) * aContext.TextZoom());
 }
 
 /* static */ nscoord
 nsStyleFont::UnZoomText(nsPresContext *aPresContext, nscoord aSize)
 {
   // aSize can be negative (e.g.: calc(-1px)) so we can't assert that here.
   // The caller is expected deal with that.
   return NSToCoordTruncClamped(float(aSize) / aPresContext->TextZoom());
 }
 
 /* static */ already_AddRefed<nsIAtom>
-nsStyleFont::GetLanguage(nsPresContext* aPresContext)
+nsStyleFont::GetLanguage(StyleStructContext aContext)
 {
-  RefPtr<nsIAtom> language = aPresContext->GetContentLanguage();
+  RefPtr<nsIAtom> language = aContext.GetContentLanguage();
   if (!language) {
     // we didn't find a (usable) Content-Language, so we fall back
     // to whatever the presContext guessed from the charset
     // NOTE this should not be used elsewhere, because we want websites
     // to use UTF-8 with proper language tag, instead of relying on
     // deriving language from charset. See bug 1040668 comment 67.
-    language = aPresContext->GetLanguageFromCharset();
+    language = aContext.GetLanguageFromCharset();
   }
   return language.forget();
 }
 
 static bool IsFixedData(const nsStyleSides& aSides, bool aEnumOK)
 {
   NS_FOR_CSS_SIDES(side) {
     if (!IsFixedUnit(aSides.Get(side), aEnumOK))
@@ -247,17 +264,17 @@ static nscoord CalcCoord(const nsStyleCo
     }
     NS_NOTREACHED("unexpected enum value");
     return 0;
   }
   MOZ_ASSERT(aCoord.ConvertsToLength(), "unexpected unit");
   return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
 }
 
-nsStyleMargin::nsStyleMargin()
+nsStyleMargin::nsStyleMargin(StyleStructContext aContext)
   : mHasCachedMargin(false)
   , mCachedMargin(0, 0, 0, 0)
 {
   MOZ_COUNT_CTOR(nsStyleMargin);
   nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
   NS_FOR_CSS_SIDES(side) {
     mMargin.Set(side, zero);
   }
@@ -298,17 +315,17 @@ nsChangeHint nsStyleMargin::CalcDifferen
   }
   // Margin differences can't affect descendant intrinsic sizes and
   // don't need to force children to reflow.
   return nsChangeHint_NeedReflow |
          nsChangeHint_ReflowChangesSizeOrPosition |
          nsChangeHint_ClearAncestorIntrinsics;
 }
 
-nsStylePadding::nsStylePadding()
+nsStylePadding::nsStylePadding(StyleStructContext aContext)
   : mHasCachedPadding(false)
   , mCachedPadding(0, 0, 0, 0)
 {
   MOZ_COUNT_CTOR(nsStylePadding);
   nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
   NS_FOR_CSS_SIDES(side) {
     mPadding.Set(side, zero);
   }
@@ -351,45 +368,45 @@ nsChangeHint nsStylePadding::CalcDiffere
   // Padding differences can't affect descendant intrinsic sizes, but do need
   // to force children to reflow so that we can reposition them, since their
   // offsets are from our frame bounds but our content rect's position within
   // those bounds is moving.
   return NS_SubtractHint(NS_STYLE_HINT_REFLOW,
                          nsChangeHint_ClearDescendantIntrinsics);
 }
 
-nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext)
+nsStyleBorder::nsStyleBorder(StyleStructContext aContext)
   : mBorderColors(nullptr),
     mBoxShadow(nullptr),
     mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL),
     mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
     mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
     mFloatEdge(NS_STYLE_FLOAT_EDGE_CONTENT),
     mBoxDecorationBreak(NS_STYLE_BOX_DECORATION_BREAK_SLICE),
     mComputedBorder(0, 0, 0, 0)
 {
   MOZ_COUNT_CTOR(nsStyleBorder);
 
   NS_FOR_CSS_HALF_CORNERS (corner) {
     mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
   }
 
   nscoord medium =
-    (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
+    (StaticPresData::Get()->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
   NS_FOR_CSS_SIDES(side) {
     mBorderImageSlice.Set(side, nsStyleCoord(1.0f, eStyleUnit_Percent));
     mBorderImageWidth.Set(side, nsStyleCoord(1.0f, eStyleUnit_Factor));
     mBorderImageOutset.Set(side, nsStyleCoord(0.0f, eStyleUnit_Factor));
 
     mBorder.Side(side) = medium;
     mBorderStyle[side] = NS_STYLE_BORDER_STYLE_NONE | BORDER_COLOR_FOREGROUND;
     mBorderColor[side] = NS_RGB(0, 0, 0);
   }
 
-  mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
+  mTwipsPerPixel = aContext.DevPixelsToAppUnits(1);
 }
 
 nsBorderColors::~nsBorderColors()
 {
   NS_CSS_DELETE_LIST_MEMBER(nsBorderColors, this, mNext);
 }
 
 nsBorderColors*
@@ -565,33 +582,33 @@ nsChangeHint nsStyleBorder::CalcDifferen
   // border values instead.
   if (mBorder != aOther.mBorder) {
     return nsChangeHint_NeutralChange;
   }
 
   return NS_STYLE_HINT_NONE;
 }
 
-nsStyleOutline::nsStyleOutline(nsPresContext* aPresContext)
+nsStyleOutline::nsStyleOutline(StyleStructContext aContext)
 {
   MOZ_COUNT_CTOR(nsStyleOutline);
   // spacing values not inherited
   nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
   NS_FOR_CSS_HALF_CORNERS(corner) {
     mOutlineRadius.Set(corner, zero);
   }
 
   mOutlineOffset = 0;
 
   mOutlineWidth = nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
   mOutlineStyle = NS_STYLE_BORDER_STYLE_NONE;
   mOutlineColor = NS_RGB(0, 0, 0);
 
   mHasCachedOutline = false;
-  mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
+  mTwipsPerPixel = aContext.DevPixelsToAppUnits(1);
 
   SetOutlineInitialColor();
 }
 
 nsStyleOutline::nsStyleOutline(const nsStyleOutline& aSrc)
   : mOutlineRadius(aSrc.mOutlineRadius)
   , mOutlineWidth(aSrc.mOutlineWidth)
   , mOutlineOffset(aSrc.mOutlineOffset)
@@ -653,21 +670,20 @@ nsChangeHint nsStyleOutline::CalcDiffere
   }
 
   return NS_STYLE_HINT_NONE;
 }
 
 // --------------------
 // nsStyleList
 //
-nsStyleList::nsStyleList(nsPresContext* aPresContext) 
+nsStyleList::nsStyleList(StyleStructContext aContext) 
   : mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE),
     mListStyleType(NS_LITERAL_STRING("disc")),
-    mCounterStyle(aPresContext->CounterStyleManager()->
-                  BuildCounterStyle(mListStyleType))
+    mCounterStyle(aContext.BuildCounterStyle(mListStyleType))
 {
   MOZ_COUNT_CTOR(nsStyleList);
 }
 
 nsStyleList::~nsStyleList() 
 {
   MOZ_COUNT_DTOR(nsStyleList);
 }
@@ -698,17 +714,17 @@ nsChangeHint nsStyleList::CalcDifference
       return NS_STYLE_HINT_VISUAL;
   }
   return NS_STYLE_HINT_REFLOW;
 }
 
 // --------------------
 // nsStyleXUL
 //
-nsStyleXUL::nsStyleXUL() 
+nsStyleXUL::nsStyleXUL(StyleStructContext aContext)
 { 
   MOZ_COUNT_CTOR(nsStyleXUL);
   mBoxAlign  = NS_STYLE_BOX_ALIGN_STRETCH;
   mBoxDirection = NS_STYLE_BOX_DIRECTION_NORMAL;
   mBoxFlex = 0.0f;
   mBoxOrient = NS_STYLE_BOX_ORIENT_HORIZONTAL;
   mBoxPack   = NS_STYLE_BOX_PACK_START;
   mBoxOrdinal = 1;
@@ -747,30 +763,31 @@ nsChangeHint nsStyleXUL::CalcDifference(
   return NS_STYLE_HINT_REFLOW;
 }
 
 // --------------------
 // nsStyleColumn
 //
 /* static */ const uint32_t nsStyleColumn::kMaxColumnCount = 1000;
 
-nsStyleColumn::nsStyleColumn(nsPresContext* aPresContext)
+nsStyleColumn::nsStyleColumn(StyleStructContext aContext)
 {
   MOZ_COUNT_CTOR(nsStyleColumn);
   mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
   mColumnWidth.SetAutoValue();
   mColumnGap.SetNormalValue();
   mColumnFill = NS_STYLE_COLUMN_FILL_BALANCE;
 
-  mColumnRuleWidth = (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
+  mColumnRuleWidth =
+    (StaticPresData::Get()->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
   mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
   mColumnRuleColor = NS_RGB(0, 0, 0);
   mColumnRuleColorIsForeground = true;
 
-  mTwipsPerPixel = aPresContext->AppUnitsPerDevPixel();
+  mTwipsPerPixel = aContext.AppUnitsPerDevPixel();
 }
 
 nsStyleColumn::~nsStyleColumn() 
 {
   MOZ_COUNT_DTOR(nsStyleColumn);
 }
 
 nsStyleColumn::nsStyleColumn(const nsStyleColumn& aSource)
@@ -816,17 +833,17 @@ nsChangeHint nsStyleColumn::CalcDifferen
   }
 
   return NS_STYLE_HINT_NONE;
 }
 
 // --------------------
 // nsStyleSVG
 //
-nsStyleSVG::nsStyleSVG()
+nsStyleSVG::nsStyleSVG(StyleStructContext aContext)
 {
   MOZ_COUNT_CTOR(nsStyleSVG);
   mFill.mType              = eStyleSVGPaintType_Color;
   mFill.mPaint.mColor      = NS_RGB(0,0,0);
   mFill.mFallbackColor     = NS_RGB(0,0,0);
   mStroke.mType            = eStyleSVGPaintType_None;
   mStroke.mPaint.mColor    = NS_RGB(0,0,0);
   mStroke.mFallbackColor   = NS_RGB(0,0,0);
@@ -1255,17 +1272,17 @@ nsStyleFilter::SetDropShadow(nsCSSShadow
   mDropShadow = aDropShadow;
   mDropShadow->AddRef();
   mType = NS_STYLE_FILTER_DROP_SHADOW;
 }
 
 // --------------------
 // nsStyleSVGReset
 //
-nsStyleSVGReset::nsStyleSVGReset()
+nsStyleSVGReset::nsStyleSVGReset(StyleStructContext aContext)
 {
   MOZ_COUNT_CTOR(nsStyleSVGReset);
   mStopColor               = NS_RGB(0,0,0);
   mFloodColor              = NS_RGB(0,0,0);
   mLightingColor           = NS_RGB(255,255,255);
   mStopOpacity             = 1.0f;
   mFloodOpacity            = 1.0f;
   mDominantBaseline        = NS_STYLE_DOMINANT_BASELINE_AUTO;
@@ -1393,17 +1410,17 @@ bool nsStyleSVGPaint::operator==(const n
   if (mType == eStyleSVGPaintType_Color)
     return mPaint.mColor == aOther.mPaint.mColor;
   return true;
 }
 
 // --------------------
 // nsStylePosition
 //
-nsStylePosition::nsStylePosition(void)
+nsStylePosition::nsStylePosition(StyleStructContext aContext)
 {
   MOZ_COUNT_CTOR(nsStylePosition);
 
   // positioning values not inherited
 
   mObjectPosition.SetInitialPercentValues(0.5f);
 
   nsStyleCoord  autoCoord(eStyleUnit_Auto);
@@ -1722,17 +1739,17 @@ nsStylePosition::ComputedJustifySelf(nsS
   }
   return NS_STYLE_JUSTIFY_NORMAL;
 }
 
 // --------------------
 // nsStyleTable
 //
 
-nsStyleTable::nsStyleTable() 
+nsStyleTable::nsStyleTable(StyleStructContext aContext)
 { 
   MOZ_COUNT_CTOR(nsStyleTable);
   // values not inherited
   mLayoutStrategy = NS_STYLE_TABLE_LAYOUT_AUTO;
   mSpan = 1;
 }
 
 nsStyleTable::~nsStyleTable(void) 
@@ -1753,17 +1770,17 @@ nsChangeHint nsStyleTable::CalcDifferenc
       mLayoutStrategy != aOther.mLayoutStrategy)
     return NS_STYLE_HINT_FRAMECHANGE;
   return NS_STYLE_HINT_NONE;
 }
 
 // -----------------------
 // nsStyleTableBorder
 
-nsStyleTableBorder::nsStyleTableBorder()
+nsStyleTableBorder::nsStyleTableBorder(StyleStructContext aContext)
 { 
   MOZ_COUNT_CTOR(nsStyleTableBorder);
   mBorderCollapse = NS_STYLE_BORDER_SEPARATE;
 
   mEmptyCells = NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
   mCaptionSide = NS_STYLE_CAPTION_SIDE_TOP;
   mBorderSpacingCol = 0;
   mBorderSpacingRow = 0;
@@ -1804,20 +1821,20 @@ nsChangeHint nsStyleTableBorder::CalcDif
   else
     return NS_STYLE_HINT_REFLOW;
 }
 
 // --------------------
 // nsStyleColor
 //
 
-nsStyleColor::nsStyleColor(nsPresContext* aPresContext)
+nsStyleColor::nsStyleColor(StyleStructContext aContext)
 {
   MOZ_COUNT_CTOR(nsStyleColor);
-  mColor = aPresContext->DefaultColor();
+  mColor = aContext.DefaultColor();
 }
 
 nsStyleColor::nsStyleColor(const nsStyleColor& aSource)
 {
   MOZ_COUNT_CTOR(nsStyleColor);
   mColor = aSource.mColor;
 }
 
@@ -2598,17 +2615,17 @@ nsStyleImageLayers::Layer::CalcDifferenc
 
   return hint;
 }
 
 // --------------------
 // nsStyleBackground
 //
 
-nsStyleBackground::nsStyleBackground()
+nsStyleBackground::nsStyleBackground(StyleStructContext aContext)
   : mBackgroundColor(NS_RGBA(0, 0, 0, 0))
 {
   MOZ_COUNT_CTOR(nsStyleBackground);
 }
 
 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
   : mImage(aSource.mImage)
   , mBackgroundColor(aSource.mBackgroundColor)
@@ -2791,17 +2808,17 @@ mozilla::StyleAnimation::operator==(cons
          mDelay == aOther.mDelay &&
          mName == aOther.mName &&
          mDirection == aOther.mDirection &&
          mFillMode == aOther.mFillMode &&
          mPlayState == aOther.mPlayState &&
          mIterationCount == aOther.mIterationCount;
 }
 
-nsStyleDisplay::nsStyleDisplay()
+nsStyleDisplay::nsStyleDisplay(StyleStructContext aContext)
   : mWillChangeBitField(0)
 {
   MOZ_COUNT_CTOR(nsStyleDisplay);
   mAppearance = NS_THEME_NONE;
   mDisplay = NS_STYLE_DISPLAY_INLINE;
   mOriginalDisplay = mDisplay;
   mContain = NS_STYLE_CONTAIN_NONE;
   mPosition = NS_STYLE_POSITION_STATIC;
@@ -3154,20 +3171,20 @@ nsChangeHint nsStyleDisplay::CalcDiffere
 
   return hint;
 }
 
 // --------------------
 // nsStyleVisibility
 //
 
-nsStyleVisibility::nsStyleVisibility(nsPresContext* aPresContext)
+nsStyleVisibility::nsStyleVisibility(StyleStructContext aContext)
 {
   MOZ_COUNT_CTOR(nsStyleVisibility);
-  uint32_t bidiOptions = aPresContext->GetBidi();
+  uint32_t bidiOptions = aContext.GetBidi();
   if (GET_BIDI_OPTION_DIRECTION(bidiOptions) == IBMBIDI_TEXTDIRECTION_RTL)
     mDirection = NS_STYLE_DIRECTION_RTL;
   else
     mDirection = NS_STYLE_DIRECTION_LTR;
 
   mVisible = NS_STYLE_VISIBILITY_VISIBLE;
   mPointerEvents = NS_STYLE_POINTER_EVENTS_AUTO;
   mWritingMode = NS_STYLE_WRITING_MODE_HORIZONTAL_TB;
@@ -3328,17 +3345,17 @@ nsStyleContentData::UntrackImage(nsPresC
 #endif
 }
 
 
 //-----------------------
 // nsStyleContent
 //
 
-nsStyleContent::nsStyleContent(void)
+nsStyleContent::nsStyleContent(StyleStructContext aContext)
   : mMarkerOffset(),
     mContents(nullptr),
     mIncrements(nullptr),
     mResets(nullptr),
     mContentCount(0),
     mIncrementCount(0),
     mResetCount(0)
 {
@@ -3474,17 +3491,17 @@ nsresult nsStyleContent::AllocateContent
   mContentCount = aCount;
   return NS_OK;
 }
 
 // ---------------------
 // nsStyleQuotes
 //
 
-nsStyleQuotes::nsStyleQuotes(void)
+nsStyleQuotes::nsStyleQuotes(StyleStructContext aContext)
   : mQuotesCount(0),
     mQuotes(nullptr)
 {
   MOZ_COUNT_CTOR(nsStyleQuotes);
   SetInitial();
 }
 
 nsStyleQuotes::~nsStyleQuotes(void)
@@ -3548,17 +3565,17 @@ nsChangeHint nsStyleQuotes::CalcDifferen
   }
   return NS_STYLE_HINT_FRAMECHANGE;
 }
 
 // --------------------
 // nsStyleTextReset
 //
 
-nsStyleTextReset::nsStyleTextReset(void) 
+nsStyleTextReset::nsStyleTextReset(StyleStructContext aContext)
 { 
   MOZ_COUNT_CTOR(nsStyleTextReset);
   mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE, eStyleUnit_Enumerated);
   mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
   mTextDecorationColor = NS_RGB(0,0,0);
   mTextDecorationStyle =
     NS_STYLE_TEXT_DECORATION_STYLE_SOLID | BORDER_COLOR_FOREGROUND;
   mUnicodeBidi = NS_STYLE_UNICODE_BIDI_NORMAL;
@@ -3626,17 +3643,17 @@ AreShadowArraysEqual(nsCSSShadowArray* l
   }
   return true;
 }
 
 // --------------------
 // nsStyleText
 //
 
-nsStyleText::nsStyleText(nsPresContext* aPresContext)
+nsStyleText::nsStyleText(StyleStructContext aContext)
 { 
   MOZ_COUNT_CTOR(nsStyleText);
   mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
   mTextAlignLast = NS_STYLE_TEXT_ALIGN_AUTO;
   mTextAlignTrue = false;
   mTextAlignLastTrue = false;
   mTextEmphasisColorForeground = true;
   mWebkitTextFillColorForeground = true;
@@ -3645,23 +3662,23 @@ nsStyleText::nsStyleText(nsPresContext* 
   mWordBreak = NS_STYLE_WORDBREAK_NORMAL;
   mWordWrap = NS_STYLE_WORDWRAP_NORMAL;
   mHyphens = NS_STYLE_HYPHENS_MANUAL;
   mRubyAlign = NS_STYLE_RUBY_ALIGN_SPACE_AROUND;
   mRubyPosition = NS_STYLE_RUBY_POSITION_OVER;
   mTextSizeAdjust = NS_STYLE_TEXT_SIZE_ADJUST_AUTO;
   mTextCombineUpright = NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE;
   mTextEmphasisStyle = NS_STYLE_TEXT_EMPHASIS_STYLE_NONE;
-  nsCOMPtr<nsIAtom> language = aPresContext->GetContentLanguage();
+  nsCOMPtr<nsIAtom> language = aContext.GetContentLanguage();
   mTextEmphasisPosition = language &&
     nsStyleUtil::MatchesLanguagePrefix(language, MOZ_UTF16("zh")) ?
     NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT_ZH :
     NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT;
-  mTextEmphasisColor = aPresContext->DefaultColor();
-  mWebkitTextFillColor = aPresContext->DefaultColor();
+  mTextEmphasisColor = aContext.DefaultColor();
+  mWebkitTextFillColor = aContext.DefaultColor();
   mControlCharacterVisibility = nsCSSParser::ControlCharVisibilityDefault();
 
   mWordSpacing.SetCoordValue(0);
   mLetterSpacing.SetNormalValue();
   mLineHeight.SetNormalValue();
   mTextIndent.SetCoordValue(0);
 
   mTextShadow = nullptr;
@@ -3823,17 +3840,17 @@ nsCursorImage::operator=(const nsCursorI
     mHotspotX = aOther.mHotspotX;
     mHotspotY = aOther.mHotspotY;
     SetImage(aOther.GetImage());
   }
 
   return *this;
 }
 
-nsStyleUserInterface::nsStyleUserInterface(void) 
+nsStyleUserInterface::nsStyleUserInterface(StyleStructContext aContext)
 { 
   MOZ_COUNT_CTOR(nsStyleUserInterface);
   mUserInput = NS_STYLE_USER_INPUT_AUTO;
   mUserModify = NS_STYLE_USER_MODIFY_READ_ONLY;
   mUserFocus = NS_STYLE_USER_FOCUS_NONE;
 
   mCursor = NS_STYLE_CURSOR_AUTO; // fix for bugzilla bug 51113
 
@@ -3901,17 +3918,17 @@ nsStyleUserInterface::CopyCursorArrayFro
     }
   }
 }
 
 //-----------------------
 // nsStyleUIReset
 //
 
-nsStyleUIReset::nsStyleUIReset(void) 
+nsStyleUIReset::nsStyleUIReset(StyleStructContext aContext)
 { 
   MOZ_COUNT_CTOR(nsStyleUIReset);
   mUserSelect = NS_STYLE_USER_SELECT_AUTO;
   mForceBrokenImageIcon = 0;
   mIMEMode = NS_STYLE_IME_MODE_AUTO;
   mWindowDragging = NS_STYLE_WINDOW_DRAGGING_DEFAULT;
   mWindowShadow = NS_STYLE_WINDOW_SHADOW_DEFAULT;
 }
@@ -3951,17 +3968,17 @@ nsChangeHint nsStyleUIReset::CalcDiffere
 
   return NS_STYLE_HINT_NONE;
 }
 
 //-----------------------
 // nsStyleVariables
 //
 
-nsStyleVariables::nsStyleVariables()
+nsStyleVariables::nsStyleVariables(StyleStructContext aContext)
 {
   MOZ_COUNT_CTOR(nsStyleVariables);
 }
 
 nsStyleVariables::nsStyleVariables(const nsStyleVariables& aSource)
 {
   MOZ_COUNT_CTOR(nsStyleVariables);
   mVariables = aSource.mVariables;
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -11,16 +11,17 @@
 
 #ifndef nsStyleStruct_h___
 #define nsStyleStruct_h___
 
 #include "mozilla/ArenaObjectID.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CSSVariableValues.h"
 #include "mozilla/SheetType.h"
+#include "mozilla/StyleStructContext.h"
 #include "nsColor.h"
 #include "nsCoord.h"
 #include "nsMargin.h"
 #include "nsFont.h"
 #include "nsStyleCoord.h"
 #include "nsStyleConsts.h"
 #include "nsChangeHint.h"
 #include "nsPresContext.h"
@@ -141,19 +142,19 @@ static_assert(sizeof(nsRect_Simple) == s
 static_assert(offsetof(nsRect_Simple, x) == offsetof(nsRect, x), "Wrong nsRect_Simple member alignment");
 static_assert(offsetof(nsRect_Simple, y) == offsetof(nsRect, y), "Wrong nsRect_Simple member alignment");
 static_assert(offsetof(nsRect_Simple, width) == offsetof(nsRect, width), "Wrong nsRect_Simple member alignment");
 static_assert(offsetof(nsRect_Simple, height) == offsetof(nsRect, height), "Wrong nsRect_Simple member alignment");
 
 // The lifetime of these objects is managed by the presshell's arena.
 struct nsStyleFont
 {
-  nsStyleFont(const nsFont& aFont, nsPresContext *aPresContext);
+  nsStyleFont(const nsFont& aFont, StyleStructContext aContext);
   nsStyleFont(const nsStyleFont& aStyleFont);
-  explicit nsStyleFont(nsPresContext *aPresContext);
+  explicit nsStyleFont(StyleStructContext aContext);
   ~nsStyleFont(void) {
     MOZ_COUNT_DTOR(nsStyleFont);
   }
 
   nsChangeHint CalcDifference(const nsStyleFont& aOther) const;
   static nsChangeHint MaxDifference() {
     return NS_CombineHint(NS_STYLE_HINT_REFLOW,
                           nsChangeHint_NeutralChange);
@@ -166,25 +167,26 @@ struct nsStyleFont
            nsChangeHint_ClearAncestorIntrinsics;
   }
 
   /**
    * Return aSize multiplied by the current text zoom factor (in aPresContext).
    * aSize is allowed to be negative, but the caller is expected to deal with
    * negative results.  The result is clamped to nscoord_MIN .. nscoord_MAX.
    */
-  static nscoord ZoomText(nsPresContext* aPresContext, nscoord aSize);
+  static nscoord ZoomText(StyleStructContext aContext, nscoord aSize);
   /**
    * Return aSize divided by the current text zoom factor (in aPresContext).
    * aSize is allowed to be negative, but the caller is expected to deal with
    * negative results.  The result is clamped to nscoord_MIN .. nscoord_MAX.
    */
   static nscoord UnZoomText(nsPresContext* aPresContext, nscoord aSize);
-  static already_AddRefed<nsIAtom> GetLanguage(nsPresContext* aPresContext);
-
+  static already_AddRefed<nsIAtom> GetLanguage(StyleStructContext aPresContext);
+
+  void* operator new(size_t sz, nsStyleFont* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleFont, sz);
   }
   void Destroy(nsPresContext* aContext);
 
   void EnableZoom(nsPresContext* aContext, bool aEnable);
 
@@ -409,32 +411,33 @@ private:
   nsAutoPtr<nsStyleSides> mCropRect;
 #ifdef DEBUG
   bool mImageTracked;
 #endif
 };
 
 struct nsStyleColor
 {
-  explicit nsStyleColor(nsPresContext* aPresContext);
+  explicit nsStyleColor(StyleStructContext aContext);
   nsStyleColor(const nsStyleColor& aOther);
   ~nsStyleColor(void) {
     MOZ_COUNT_DTOR(nsStyleColor);
   }
 
   nsChangeHint CalcDifference(const nsStyleColor& aOther) const;
   static nsChangeHint MaxDifference() {
     return nsChangeHint_RepaintFrame;
   }
   static nsChangeHint DifferenceAlwaysHandledForDescendants() {
     // CalcDifference never returns the reflow hints that are sometimes
     // handled for descendants at all.
     return nsChangeHint(0);
   }
 
+  void* operator new(size_t sz, nsStyleColor* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleColor, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleColor();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleColor, this);
@@ -710,20 +713,21 @@ struct nsStyleImageLayers {
     for (uint32_t var_ = (layers_).mImageCount; var_-- != 0; )
   #define NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT_WITH_RANGE(var_, layers_, start_, count_) \
     NS_ASSERTION((int32_t)(start_) >= 0 && (uint32_t)(start_) < (layers_).mImageCount, "Invalid layer start!"); \
     NS_ASSERTION((count_) > 0 && (count_) <= (start_) + 1, "Invalid layer range!"); \
     for (uint32_t var_ = (start_) + 1; var_-- != (uint32_t)((start_) + 1 - (count_)); )
 };
 
 struct nsStyleBackground {
-  nsStyleBackground();
+  explicit nsStyleBackground(StyleStructContext aContext);
   nsStyleBackground(const nsStyleBackground& aOther);
   ~nsStyleBackground();
 
+  void* operator new(size_t sz, nsStyleBackground* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleBackground, sz);
   }
   void Destroy(nsPresContext* aContext);
 
   nsChangeHint CalcDifference(const nsStyleBackground& aOther) const;
   static nsChangeHint MaxDifference() {
@@ -763,22 +767,23 @@ struct nsStyleBackground {
 
 #define NS_SPACING_MARGIN   0
 #define NS_SPACING_PADDING  1
 #define NS_SPACING_BORDER   2
 
 
 struct nsStyleMargin
 {
-  nsStyleMargin(void);
+  explicit nsStyleMargin(StyleStructContext aContext);
   nsStyleMargin(const nsStyleMargin& aMargin);
   ~nsStyleMargin(void) {
     MOZ_COUNT_DTOR(nsStyleMargin);
   }
 
+  void* operator new(size_t sz, nsStyleMargin* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleMargin, sz);
   }
   void Destroy(nsPresContext* aContext);
 
   void RecalcData();
   nsChangeHint CalcDifference(const nsStyleMargin& aOther) const;
@@ -808,22 +813,23 @@ struct nsStyleMargin
 protected:
   bool          mHasCachedMargin;
   nsMargin      mCachedMargin;
 };
 
 
 struct nsStylePadding
 {
-  nsStylePadding(void);
+  explicit nsStylePadding(StyleStructContext aContext);
   nsStylePadding(const nsStylePadding& aPadding);
   ~nsStylePadding(void) {
     MOZ_COUNT_DTOR(nsStylePadding);
   }
 
+  void* operator new(size_t sz, nsStylePadding* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStylePadding, sz);
   }
   void Destroy(nsPresContext* aContext);
 
   void RecalcData();
   nsChangeHint CalcDifference(const nsStylePadding& aOther) const;
@@ -1010,20 +1016,21 @@ private:
 static bool IsVisibleBorderStyle(uint8_t aStyle)
 {
   return (aStyle != NS_STYLE_BORDER_STYLE_NONE &&
           aStyle != NS_STYLE_BORDER_STYLE_HIDDEN);
 }
 
 struct nsStyleBorder
 {
-  explicit nsStyleBorder(nsPresContext* aContext);
+  explicit nsStyleBorder(StyleStructContext aContext);
   nsStyleBorder(const nsStyleBorder& aBorder);
   ~nsStyleBorder();
 
+  void* operator new(size_t sz, nsStyleBorder* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleBorder, sz);
   }
   void Destroy(nsPresContext* aContext);
 
   nsChangeHint CalcDifference(const nsStyleBorder& aOther) const;
   static nsChangeHint MaxDifference() {
@@ -1237,22 +1244,23 @@ private:
   nscoord       mTwipsPerPixel;
 
   nsStyleBorder& operator=(const nsStyleBorder& aOther) = delete;
 };
 
 
 struct nsStyleOutline
 {
-  explicit nsStyleOutline(nsPresContext* aPresContext);
+  explicit nsStyleOutline(StyleStructContext aContext);
   nsStyleOutline(const nsStyleOutline& aOutline);
   ~nsStyleOutline(void) {
     MOZ_COUNT_DTOR(nsStyleOutline);
   }
 
+  void* operator new(size_t sz, nsStyleOutline* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleOutline, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleOutline();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleOutline, this);
@@ -1336,20 +1344,21 @@ protected:
   uint8_t       mOutlineStyle;    // [reset] See nsStyleConsts.h
 
   nscoord       mTwipsPerPixel;
 };
 
 
 struct nsStyleList
 {
-  explicit nsStyleList(nsPresContext* aPresContext);
+  explicit nsStyleList(StyleStructContext aContext);
   nsStyleList(const nsStyleList& aStyleList);
   ~nsStyleList(void);
 
+  void* operator new(size_t sz, nsStyleList* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleList, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleList();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleList, this);
@@ -1543,20 +1552,21 @@ struct nsStyleGridTemplate
   bool IsRepeatAutoIndex(uint32_t aIndex) const {
     MOZ_ASSERT(aIndex < uint32_t(2*nsStyleGridLine::kMaxLine));
     return int32_t(aIndex) == mRepeatAutoIndex;
   }
 };
 
 struct nsStylePosition
 {
-  nsStylePosition(void);
+  explicit nsStylePosition(StyleStructContext aContext);
   nsStylePosition(const nsStylePosition& aOther);
   ~nsStylePosition(void);
 
+  void* operator new(size_t sz, nsStylePosition* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStylePosition, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStylePosition();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStylePosition, this);
@@ -1793,20 +1803,21 @@ struct nsStyleTextOverflow
 
   nsStyleTextOverflowSide mLeft;  // start side when mLogicalDirections is true
   nsStyleTextOverflowSide mRight; // end side when mLogicalDirections is true
   bool mLogicalDirections;  // true when only one value was specified
 };
 
 struct nsStyleTextReset
 {
-  nsStyleTextReset(void);
+  explicit nsStyleTextReset(StyleStructContext aContext);
   nsStyleTextReset(const nsStyleTextReset& aOther);
   ~nsStyleTextReset(void);
 
+  void* operator new(size_t sz, nsStyleTextReset* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleTextReset, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleTextReset();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleTextReset, this);
@@ -1878,20 +1889,21 @@ struct nsStyleTextReset
 protected:
   uint8_t mTextDecorationStyle;         // [reset] see nsStyleConsts.h
 
   nscolor mTextDecorationColor;         // [reset] the colors to use for a decoration lines, not used at currentColor
 };
 
 struct nsStyleText
 {
-  explicit nsStyleText(nsPresContext* aPresContext);
+  explicit nsStyleText(StyleStructContext aContext);
   nsStyleText(const nsStyleText& aOther);
   ~nsStyleText(void);
 
+  void* operator new(size_t sz, nsStyleText* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleText, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleText();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleText, this);
@@ -2086,22 +2098,23 @@ protected:
     : mOrientation(aOrientation)
   { }
 
   uint8_t mOrientation;
 };
 
 struct nsStyleVisibility
 {
-  explicit nsStyleVisibility(nsPresContext* aPresContext);
+  explicit nsStyleVisibility(StyleStructContext aContext);
   nsStyleVisibility(const nsStyleVisibility& aVisibility);
   ~nsStyleVisibility() {
     MOZ_COUNT_DTOR(nsStyleVisibility);
   }
 
+  void* operator new(size_t sz, nsStyleVisibility* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleVisibility, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleVisibility();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleVisibility, this);
@@ -2368,22 +2381,23 @@ private:
   uint8_t mPlayState;
   float mIterationCount; // mozilla::PositiveInfinity<float>() means infinite
 };
 
 } // namespace mozilla
 
 struct nsStyleDisplay
 {
-  nsStyleDisplay();
+  explicit nsStyleDisplay(StyleStructContext aContext);
   nsStyleDisplay(const nsStyleDisplay& aOther);
   ~nsStyleDisplay() {
     MOZ_COUNT_DTOR(nsStyleDisplay);
   }
 
+  void* operator new(size_t sz, nsStyleDisplay* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleDisplay, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleDisplay();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleDisplay, this);
@@ -2643,20 +2657,21 @@ struct nsStyleDisplay
   // resolved to {left,right} according to the given writing mode. These are
   // defined in WritingModes.h.
   inline uint8_t PhysicalFloats(mozilla::WritingMode aWM) const;
   inline uint8_t PhysicalBreakType(mozilla::WritingMode aWM) const;
 };
 
 struct nsStyleTable
 {
-  nsStyleTable(void);
+  explicit nsStyleTable(StyleStructContext aContext);
   nsStyleTable(const nsStyleTable& aOther);
   ~nsStyleTable(void);
 
+  void* operator new(size_t sz, nsStyleTable* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleTable, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleTable();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleTable, this);
@@ -2675,20 +2690,21 @@ struct nsStyleTable
   }
 
   uint8_t       mLayoutStrategy;// [reset] see nsStyleConsts.h NS_STYLE_TABLE_LAYOUT_*
   int32_t       mSpan;          // [reset] the number of columns spanned by a colgroup or col
 };
 
 struct nsStyleTableBorder
 {
-  nsStyleTableBorder();
+  explicit nsStyleTableBorder(StyleStructContext aContext);
   nsStyleTableBorder(const nsStyleTableBorder& aOther);
   ~nsStyleTableBorder(void);
 
+  void* operator new(size_t sz, nsStyleTableBorder* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleTableBorder, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleTableBorder();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleTableBorder, this);
@@ -2774,20 +2790,21 @@ struct nsStyleCounterData
   int32_t   mValue;
 };
 
 
 #define DELETE_ARRAY_IF(array)  if (array) { delete[] array; array = nullptr; }
 
 struct nsStyleQuotes
 {
-  nsStyleQuotes();
+  explicit nsStyleQuotes(StyleStructContext aContext);
   nsStyleQuotes(const nsStyleQuotes& aQuotes);
   ~nsStyleQuotes();
 
+  void* operator new(size_t sz, nsStyleQuotes* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleQuotes, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleQuotes();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleQuotes, this);
@@ -2857,20 +2874,21 @@ struct nsStyleQuotes
 
 protected:
   uint32_t            mQuotesCount;
   nsString*           mQuotes;
 };
 
 struct nsStyleContent
 {
-  nsStyleContent(void);
+  explicit nsStyleContent(StyleStructContext aContext);
   nsStyleContent(const nsStyleContent& aContent);
   ~nsStyleContent(void);
 
+  void* operator new(size_t sz, nsStyleContent* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleContent, sz);
   }
   void Destroy(nsPresContext* aContext);
 
   nsChangeHint CalcDifference(const nsStyleContent& aOther) const;
   static nsChangeHint MaxDifference() {
@@ -2967,20 +2985,21 @@ protected:
 
   uint32_t            mContentCount;
   uint32_t            mIncrementCount;
   uint32_t            mResetCount;
 };
 
 struct nsStyleUIReset
 {
-  nsStyleUIReset(void);
+  explicit nsStyleUIReset(StyleStructContext aContext);
   nsStyleUIReset(const nsStyleUIReset& aOther);
   ~nsStyleUIReset(void);
 
+  void* operator new(size_t sz, nsStyleUIReset* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleUIReset, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleUIReset();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleUIReset, this);
@@ -3032,20 +3051,21 @@ struct nsCursorImage
   }
 
 private:
   nsCOMPtr<imgIRequest> mImage;
 };
 
 struct nsStyleUserInterface
 {
-  nsStyleUserInterface(void);
+  explicit nsStyleUserInterface(StyleStructContext aContext);
   nsStyleUserInterface(const nsStyleUserInterface& aOther);
   ~nsStyleUserInterface(void);
 
+  void* operator new(size_t sz, nsStyleUserInterface* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleUserInterface, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleUserInterface();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleUserInterface, this);
@@ -3079,20 +3099,21 @@ struct nsStyleUserInterface
 
   // Does not free mCursorArray; the caller is responsible for calling
   // |delete [] mCursorArray| first if it is needed.
   void CopyCursorArrayFrom(const nsStyleUserInterface& aSource);
 };
 
 struct nsStyleXUL
 {
-  nsStyleXUL();
+  explicit nsStyleXUL(StyleStructContext aContext);
   nsStyleXUL(const nsStyleXUL& aSource);
   ~nsStyleXUL();
 
+  void* operator new(size_t sz, nsStyleXUL* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleXUL, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleXUL();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleXUL, this);
@@ -3116,20 +3137,21 @@ struct nsStyleXUL
   uint8_t       mBoxDirection;          // [reset] see nsStyleConsts.h
   uint8_t       mBoxOrient;             // [reset] see nsStyleConsts.h
   uint8_t       mBoxPack;               // [reset] see nsStyleConsts.h
   bool          mStretchStack;          // [reset] see nsStyleConsts.h
 };
 
 struct nsStyleColumn
 {
-  explicit nsStyleColumn(nsPresContext* aPresContext);
+  explicit nsStyleColumn(StyleStructContext aContext);
   nsStyleColumn(const nsStyleColumn& aSource);
   ~nsStyleColumn();
 
+  void* operator new(size_t sz, nsStyleColumn* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleColumn, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleColumn();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleColumn, this);
@@ -3210,20 +3232,21 @@ struct nsStyleSVGPaint
 
   bool operator!=(const nsStyleSVGPaint& aOther) const {
     return !(*this == aOther);
   }
 };
 
 struct nsStyleSVG
 {
-  nsStyleSVG();
+  explicit nsStyleSVG(StyleStructContext aContext);
   nsStyleSVG(const nsStyleSVG& aSource);
   ~nsStyleSVG();
 
+  void* operator new(size_t sz, nsStyleSVG* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleSVG, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleSVG();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleSVG, this);
@@ -3497,20 +3520,21 @@ private:
 template<>
 struct nsTArray_CopyChooser<nsStyleFilter>
 {
   typedef nsTArray_CopyWithConstructors<nsStyleFilter> Type;
 };
 
 struct nsStyleSVGReset
 {
-  nsStyleSVGReset();
+  explicit nsStyleSVGReset(StyleStructContext aContext);
   nsStyleSVGReset(const nsStyleSVGReset& aSource);
   ~nsStyleSVGReset();
 
+  void* operator new(size_t sz, nsStyleSVGReset* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleSVGReset, sz);
   }
   void Destroy(nsPresContext* aContext);
 
   nsChangeHint CalcDifference(const nsStyleSVGReset& aOther) const;
   static nsChangeHint MaxDifference() {
@@ -3552,20 +3576,21 @@ struct nsStyleSVGReset
 
   uint8_t          mDominantBaseline; // [reset] see nsStyleConsts.h
   uint8_t          mVectorEffect;     // [reset] see nsStyleConsts.h
   uint8_t          mMaskType;         // [reset] see nsStyleConsts.h
 };
 
 struct nsStyleVariables
 {
-  nsStyleVariables();
+  explicit nsStyleVariables(StyleStructContext aContext);
   nsStyleVariables(const nsStyleVariables& aSource);
   ~nsStyleVariables();
 
+  void* operator new(size_t sz, nsStyleVariables* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleVariables, sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleVariables();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleVariables, this);
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -7190,25 +7190,25 @@ if (IsCSSPropertyPrefEnabled("layout.css
     type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
     alias_for: "box-sizing",
     subproperties: [ "box-sizing" ],
   };
   gCSSProperties["-webkit-box-flex"] = {
     domProp: "webkitBoxFlex",
     inherited: false,
     type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
-    alias_for: "flex-grow",
-    subproperties: [ "flex-grow" ],
+    alias_for: "-moz-box-flex",
+    subproperties: [ "-moz-box-flex" ],
   };
   gCSSProperties["-webkit-box-ordinal-group"] = {
     domProp: "webkitBoxOrdinalGroup",
     inherited: false,
     type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
-    alias_for: "order",
-    subproperties: [ "order" ],
+    alias_for: "-moz-box-ordinal-group",
+    subproperties: [ "-moz-box-ordinal-group" ],
   };
   /* This one is not an alias - it's implemented as a logical property: */
   gCSSProperties["-webkit-box-orient"] = {
     domProp: "webkitBoxOrient",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     logical: true,
     get_computed: webkit_orient_get_computed,
@@ -7219,25 +7219,25 @@ if (IsCSSPropertyPrefEnabled("layout.css
       /* Flex-direction values: */
       "row", "column", "row-reverse", "column-reverse",
     ],
   };
   gCSSProperties["-webkit-box-align"] = {
     domProp: "webkitBoxAlign",
     inherited: false,
     type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
-    alias_for: "align-items",
-    subproperties: [ "align-items" ],
+    alias_for: "-moz-box-align",
+    subproperties: [ "-moz-box-align" ],
   };
   gCSSProperties["-webkit-box-pack"] = {
     domProp: "webkitBoxPack",
     inherited: false,
     type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
-    alias_for: "justify-content",
-    subproperties: [ "justify-content" ],
+    alias_for: "-moz-box-pack",
+    subproperties: [ "-moz-box-pack" ],
   };
   gCSSProperties["-webkit-user-select"] = {
     domProp: "webkitUserSelect",
     inherited: false,
     type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
     alias_for: "-moz-user-select",
     subproperties: [ "-moz-user-select" ],
   };
--- a/layout/svg/SVGFEImageFrame.cpp
+++ b/layout/svg/SVGFEImageFrame.cpp
@@ -151,15 +151,16 @@ SVGFEImageFrame::AttributeChanged(int32_
 void
 SVGFEImageFrame::OnVisibilityChange(Visibility aNewVisibility,
                                     Maybe<OnNonvisible> aNonvisibleAction)
 {
   nsCOMPtr<nsIImageLoadingContent> imageLoader =
     do_QueryInterface(SVGFEImageFrameBase::mContent);
   if (!imageLoader) {
     MOZ_ASSERT_UNREACHABLE("Should have an nsIImageLoadingContent");
+    SVGFEImageFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
     return;
   }
 
   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 
   SVGFEImageFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 }
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -242,16 +242,17 @@ nsSVGImageFrame::AttributeChanged(int32_
 }
 
 void
 nsSVGImageFrame::OnVisibilityChange(Visibility aNewVisibility,
                                     Maybe<OnNonvisible> aNonvisibleAction)
 {
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
   if (!imageLoader) {
+    nsSVGImageFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
     return;
   }
 
   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 
   nsSVGImageFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 }
 
--- a/layout/tools/reftest/reftestcommandline.py
+++ b/layout/tools/reftest/reftestcommandline.py
@@ -175,25 +175,19 @@ class ReftestArgumentsParser(argparse.Ar
                           action="store",
                           type=str,
                           dest="focusFilterMode",
                           default="all",
                           help="filters tests to run by whether they require focus. "
                           "Valid values are `all', `needs-focus', or `non-needs-focus'. "
                           "Defaults to `all'.")
 
-        self.add_argument("--e10s",
-                          action="store_true",
-                          default=False,
-                          dest="e10s",
-                          help="enables content processes")
-
         self.add_argument("--disable-e10s",
                           action="store_false",
-                          default=False,
+                          default=True,
                           dest="e10s",
                           help="disables content processes")
 
         self.add_argument("--setpref",
                           action="append",
                           type=str,
                           default=[],
                           dest="extraPrefs",
@@ -749,8 +743,13 @@ class RemoteArgumentsParser(ReftestArgum
         if not options.ignoreWindowSize:
             parts = automation._devicemanager.getInfo(
                 'screen')['screen'][0].split()
             width = int(parts[0].split(':')[1])
             height = int(parts[1].split(':')[1])
             if (width < 1366 or height < 1050):
                 self.error("ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (
                     width, height))
+
+        # Disable e10s by default on Android because we don't run Android
+        # e10s jobs anywhere yet.
+        options.e10s = False
+        return options
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -647,26 +647,28 @@ class RefTest(object):
                 cmdargs.append('-marionette')
 
             profile = self.createReftestProfile(options, manifests)
             profileDir = profile.profile  # name makes more sense
 
             # browser environment
             browserEnv = self.buildBrowserEnv(options, profileDir)
 
+            self.log.info("Running with e10s: {}".format(options.e10s))
             status = self.runApp(profile,
                                  binary=options.app,
                                  cmdargs=cmdargs,
                                  # give the JS harness 30 seconds to deal with
                                  # its own timeouts
                                  env=browserEnv,
                                  timeout=options.timeout + 30.0,
                                  symbolsPath=options.symbolsPath,
                                  options=options,
                                  debuggerInfo=debuggerInfo)
+            self.log.info("Process mode: {}".format('e10s' if options.e10s else 'non-e10s'))
             mozleak.process_leak_log(self.leakLogFile,
                                      leak_thresholds=options.leakThresholds,
                                      stack_fixer=get_stack_fixer_function(options.utilityPath,
                                                                           options.symbolsPath),
             )
         finally:
             self.cleanup(profileDir)
         return status
--- a/mobile/android/mach_commands.py
+++ b/mobile/android/mach_commands.py
@@ -98,18 +98,18 @@ class AndroidEmulatorCommands(MachComman
     """
        Run the Android emulator with one of the AVDs used in the Mozilla
        automated test environment. If necessary, the AVD is fetched from
        the tooltool server and installed.
     """
     @Command('android-emulator', category='devenv',
         conditions=[],
         description='Run the Android emulator with an AVD from test automation.')
-    @CommandArgument('--version', metavar='VERSION', choices=['2.3', '4.3', 'x86'],
-        help='Specify Android version to run in emulator. One of "2.3", "4.3", or "x86".',
+    @CommandArgument('--version', metavar='VERSION', choices=['4.3', 'x86'],
+        help='Specify Android version to run in emulator. One of "4.3", or "x86".',
         default='4.3')
     @CommandArgument('--wait', action='store_true',
         help='Wait for emulator to be closed.')
     @CommandArgument('--force-update', action='store_true',
         help='Update AVD definition even when AVD is already installed.')
     @CommandArgument('--verbose', action='store_true',
         help='Log informative status messages.')
     def emulator(self, version, wait=False, force_update=False, verbose=False):
--- a/testing/mach_commands.py
+++ b/testing/mach_commands.py
@@ -709,21 +709,21 @@ def get_parser(argv=None):
 
     parser.add_argument('--chunk-by-dir',
                         type=int,
                         dest='chunk_by_dir',
                         help='Group tests together in the same chunk that are in the same top '
                              'chunkByDir directories.',
                         default=None)
 
-    parser.add_argument('--e10s',
-                        action='store_true',
+    parser.add_argument('--disable-e10s',
+                        action='store_false',
                         dest='e10s',
-                        help='Find test on chunk with electrolysis preferences enabled.',
-                        default=False)
+                        help='Find test on chunk with electrolysis preferences disabled.',
+                        default=True)
 
     parser.add_argument('-p', '--platform',
                         choices=['linux', 'linux64', 'mac', 'macosx64', 'win32', 'win64'],
                         dest='platform',
                         help="Platform for the chunk to find the test.",
                         default=None)
 
     parser.add_argument('--debug',
--- a/testing/marionette/harness/marionette/runner/base.py
+++ b/testing/marionette/harness/marionette/runner/base.py
@@ -403,20 +403,21 @@ class BaseMarionetteArguments(ArgumentPa
                         default=False,
                         help='Enable the jsdebugger for marionette javascript.')
         self.add_argument('--pydebugger',
                         help='Enable python post-mortem debugger when a test fails.'
                              ' Pass in the debugger you want to use, eg pdb or ipdb.')
         self.add_argument('--socket-timeout',
                         default=self.socket_timeout_default,
                         help='Set the global timeout for marionette socket operations.')
-        self.add_argument('--e10s',
-                        action='store_true',
-                        default=False,
-                        help='Enable e10s when running marionette tests.')
+        self.add_argument('--disable-e10s',
+                        action='store_false',
+                        dest='e10s',
+                        default=True,
+                        help='Disable e10s when running marionette tests.')
         self.add_argument('--tag',
                         action='append', dest='test_tags',
                         default=None,
                         help="Filter out tests that don't have the given tag. Can be "
                              "used multiple times in which case the test must contain "
                              "at least one of the given tags.")
         self.add_argument('--workspace',
                           action='store',
@@ -533,17 +534,17 @@ class BaseMarionetteTestRunner(object):
                  repeat=0, testvars=None, tree=None, type=None,
                  device_serial=None, symbols_path=None, timeout=None,
                  shuffle=False, shuffle_seed=random.randint(0, sys.maxint),
                  sdcard=None, this_chunk=1, total_chunks=1, sources=None,
                  server_root=None, gecko_log=None, result_callbacks=None,
                  adb_host=None, adb_port=None, prefs=None, test_tags=None,
                  socket_timeout=BaseMarionetteArguments.socket_timeout_default,
                  startup_timeout=None, addons=None, workspace=None,
-                 verbose=0, **kwargs):
+                 verbose=0, e10s=True, **kwargs):
         self.address = address
         self.emulator = emulator
         self.emulator_binary = emulator_binary
         self.emulator_img = emulator_img
         self.emulator_res = emulator_res
         self.homedir = homedir
         self.app = app
         self.app_args = app_args or []
@@ -584,16 +585,17 @@ class BaseMarionetteTestRunner(object):
         self.prefs = prefs or {}
         self.test_tags = test_tags
         self.startup_timeout = startup_timeout
         self.workspace = workspace
         # If no workspace is set, default location for logcat and gecko.log is .
         # and default location for profile is TMP
         self.workspace_path = workspace or os.getcwd()
         self.verbose = verbose
+        self.e10s = e10s
 
         def gather_debug(test, status):
             rv = {}
             marionette = test._marionette_weakref()
 
             # In the event we're gathering debug without starting a session, skip marionette commands
             if marionette.session is not None:
                 try:
@@ -875,16 +877,17 @@ setReq.onerror = function() {
         invalid_tests = \
             [t['filepath'] for t in self.tests
              if not os.path.basename(t['filepath']).startswith('test_')]
         if invalid_tests:
             raise Exception("Tests file names must starts with 'test_'."
                             " Invalid test names:\n  %s"
                             % '\n  '.join(invalid_tests))
 
+        self.logger.info("running with e10s: {}".format(self.e10s))
         version_info = mozversion.get_version(binary=self.bin,
                                               sources=self.sources,
                                               dm_type=os.environ.get('DM_TRANS', 'adb'),
                                               device_serial=self.device_serial,
                                               adb_host=self.marionette.adb_host,
                                               adb_port=self.marionette.adb_port)
 
         self.logger.suite_start(self.tests,
@@ -955,16 +958,17 @@ setReq.onerror = function() {
 
         self.marionette.cleanup()
 
         for run_tests in self.mixin_run_tests:
             run_tests(tests)
         if self.shuffle:
             self.logger.info("Using seed where seed is:%d" % self.shuffle_seed)
 
+        self.logger.info('mode: {}'.format('e10s' if self.e10s else 'non-e10s'))
         self.logger.suite_end()
 
     def start_httpd(self, need_external_ip):
         warnings.warn("start_httpd has been deprecated in favour of create_httpd",
             DeprecationWarning)
         self.httpd = self.create_httpd(need_external_ip)
 
     def create_httpd(self, need_external_ip):
@@ -1005,25 +1009,24 @@ setReq.onerror = function() {
 
         if file_ext == '.ini':
             manifest = TestManifest()
             manifest.read(filepath)
 
             filters = []
             if self.test_tags:
                 filters.append(tags(self.test_tags))
-            e10s = self.appinfo.get('browserTabsRemoteAutostart', False)
             json_path = update_mozinfo(filepath)
             self.logger.info("mozinfo updated with the following: {}".format(None))
             manifest_tests = manifest.active_tests(exists=False,
                                                    disabled=True,
                                                    filters=filters,
                                                    device=self.device,
                                                    app=self.appName,
-                                                   e10s=e10s,
+                                                   e10s=self.e10s,
                                                    **mozinfo.info)
             if len(manifest_tests) == 0:
                 self.logger.error("no tests to run using specified "
                                   "combination of filters: {}".format(
                                        manifest.fmt_filters()))
 
             unfiltered_tests = []
             for test in manifest_tests:
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -383,27 +383,21 @@ class MochitestArguments(ArgumentContain
           }],
         [["--debug-on-failure"],
          {"action": "store_true",
           "default": False,
           "dest": "debugOnFailure",
           "help": "Breaks execution and enters the JS debugger on a test failure. Should "
                   "be used together with --jsdebugger."
           }],
-        [["--e10s"],
-         {"action": "store_true",
-          "default": False,
-          "help": "Run tests with electrolysis preferences and test filtering enabled.",
-          }],
         [["--disable-e10s"],
          {"action": "store_false",
-          "default": False,
+          "default": True,
           "dest": "e10s",
           "help": "Run tests with electrolysis preferences and test filtering disabled.",
-          "suppress": True,
           }],
         [["--store-chrome-manifest"],
          {"action": "store",
           "help": "Destination path to write a copy of any chrome manifest "
                   "written by the harness.",
           "default": None,
           "suppress": True,
           }],
@@ -788,18 +782,22 @@ class MochitestArguments(ArgumentContain
                     '--use-test-media-devices is only supported on Linux currently')
             for f in ['/usr/bin/gst-launch-0.10', '/usr/bin/pactl']:
                 if not os.path.isfile(f):
                     parser.error(
                         'Missing binary %s required for '
                         '--use-test-media-devices' % f)
 
         if options.nested_oop:
-            if not options.e10s:
-                options.e10s = True
+            options.e10s = True
+
+        # a11y and chrome tests don't run with e10s enabled in CI
+        if options.a11y or options.chrome:
+            options.e10s = False
+
         mozinfo.update({"e10s": options.e10s})  # for test manifest parsing.
 
         options.leakThresholds = {
             "default": options.defaultLeakThreshold,
             "tab": 10000,  # See dependencies of bug 1051230.
             # GMP rarely gets a log, but when it does, it leaks a little.
             "geckomediaplugin": 20000,
         }
@@ -1170,16 +1168,21 @@ class AndroidArguments(ArgumentContainer
 
         if options.robocopApk != "":
             if not os.path.exists(options.robocopApk):
                 parser.error(
                     "Unable to find robocop APK '%s'" %
                     options.robocopApk)
             options.robocopApk = os.path.abspath(options.robocopApk)
 
+        # Disable e10s by default on Android because we don't run Android
+        # e10s jobs anywhere yet.
+        options.e10s = False
+        mozinfo.update({'e10s': options.e10s})
+
         # allow us to keep original application around for cleanup while
         # running robocop via 'am'
         options.remoteappname = options.app
         return options
 
 
 container_map = {
     'generic': [MochitestArguments],
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -2331,16 +2331,17 @@ class MochitestDesktop(MochitestBase):
                 'port_timeout': options.marionette_port_timeout,
             }
 
             if options.marionette:
                 host, port = options.marionette.split(':')
                 marionette_args['host'] = host
                 marionette_args['port'] = int(port)
 
+            self.log.info("runtests.py | Running with e10s: {}".format(options.e10s))
             self.log.info("runtests.py | Running tests: start.\n")
             try:
                 status = self.runApp(testURL,
                                      self.browserEnv,
                                      options.app,
                                      profile=self.profile,
                                      extraArgs=options.browserArgs,
                                      utilityPath=options.utilityPath,
--- a/testing/mozbase/mozrunner/mozrunner/devices/android_device.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/android_device.py
@@ -30,60 +30,44 @@ MANIFEST_PATH = 'testing/config/tooltool
 
 verbose_logging = False
 
 class AvdInfo(object):
     """
        Simple class to contain an AVD description.
     """
     def __init__(self, description, name, tooltool_manifest, extra_args,
-                 port, uses_sut, sut_port, sut_port2):
+                 port):
         self.description = description
         self.name = name
         self.tooltool_manifest = tooltool_manifest
         self.extra_args = extra_args
         self.port = port
-        self.uses_sut = uses_sut
-        self.sut_port = sut_port
-        self.sut_port2 = sut_port2
 
 
 """
    A dictionary to map an AVD type to a description of that type of AVD.
 
    There is one entry for each type of AVD used in Mozilla automated tests
    and the parameters for each reflect those used in mozharness.
 """
 AVD_DICT = {
-    '2.3': AvdInfo('Android 2.3',
-                   'mozemulator-2.3',
-                   'testing/config/tooltool-manifests/androidarm/releng.manifest',
-                   ['-debug',
-                    'init,console,gles,memcheck,adbserver,adbclient,adb,avd_config,socket',
-                    '-qemu', '-m', '1024', '-cpu', 'cortex-a9'],
-                   5554,
-                   True,
-                   20701, 20700),
     '4.3': AvdInfo('Android 4.3',
                    'mozemulator-4.3',
                    'testing/config/tooltool-manifests/androidarm_4_3/releng.manifest',
                    ['-show-kernel', '-debug',
                     'init,console,gles,memcheck,adbserver,adbclient,adb,avd_config,socket'],
-                   5554,
-                   False,
-                   0, 0),
+                   5554),
     'x86': AvdInfo('Android 4.2 x86',
                    'mozemulator-x86',
                    'testing/config/tooltool-manifests/androidx86/releng.manifest',
                    ['-debug',
                     'init,console,gles,memcheck,adbserver,adbclient,adb,avd_config,socket',
                     '-qemu', '-m', '1024', '-enable-kvm'],
-                   5554,
-                   False,
-                   0, 0)
+                   5554)
 }
 
 def verify_android_device(build_obj, install=False, xre=False, debugger=False):
     """
        Determine if any Android device is connected via adb.
        If no device is found, prompt to start an emulator.
        If a device is found or an emulator started and 'install' is
        specified, also check whether Firefox is installed on the
@@ -441,19 +425,16 @@ class AndroidEmulator(object):
                 time.sleep(10)
                 if self.proc.proc.poll() is not None:
                     _log_warning("Emulator has already completed!")
                     return False
         _log_debug("Android boot status verified.")
 
         if not self._verify_emulator():
             return False
-        if self.avd_info.uses_sut:
-            if not self._verify_sut():
-                return False
         return True
 
     def wait(self):
         """
            Wait for the emulator to close. If interrupted, close the emulator.
         """
         try:
             self.proc.wait()
@@ -509,25 +490,16 @@ class AndroidEmulator(object):
         telnet_ok = False
         tn = None
         while(not telnet_ok):
             try:
                 tn = telnetlib.Telnet('localhost', self.avd_info.port, 10)
                 if tn is not None:
                     res = tn.read_until('OK', 10)
                     self._telnet_cmd(tn, 'avd status')
-                    if self.avd_info.uses_sut:
-                        cmd = 'redir add tcp:%s:%s' % \
-                           (str(self.avd_info.sut_port),
-                            str(self.avd_info.sut_port))
-                        self._telnet_cmd(tn, cmd)
-                        cmd = 'redir add tcp:%s:%s' % \
-                            (str(self.avd_info.sut_port2),
-                             str(self.avd_info.sut_port2))
-                        self._telnet_cmd(tn, cmd)
                     self._telnet_cmd(tn, 'redir list')
                     self._telnet_cmd(tn, 'network status')
                     tn.write('quit\n')
                     tn.read_all()
                     telnet_ok = True
                 else:
                     _log_warning("Unable to connect to port %d" % port)
             except:
@@ -537,44 +509,16 @@ class AndroidEmulator(object):
                     tn.close()
             if not telnet_ok:
                 time.sleep(10)
                 if self.proc.proc.poll() is not None:
                     _log_warning("Emulator has already completed!")
                     return False
         return telnet_ok
 
-    def _verify_sut(self):
-        sut_ok = False
-        while(not sut_ok):
-            try:
-                tn = telnetlib.Telnet('localhost', self.avd_info.sut_port, 10)
-                if tn is not None:
-                    _log_debug(
-                        "Connected to port %d" % self.avd_info.sut_port)
-                    res = tn.read_until('$>', 10)
-                    if res.find('$>') == -1:
-                        _log_debug("Unexpected SUT response: %s" % res)
-                    else:
-                        _log_debug("SUT response: %s" % res)
-                        sut_ok = True
-                    tn.write('quit\n')
-                    tn.read_all()
-            except:
-                _log_debug("Caught exception while verifying sutagent")
-            finally:
-                if tn is not None:
-                    tn.close()
-            if not sut_ok:
-                time.sleep(10)
-                if self.proc.proc.poll() is not None:
-                    _log_warning("Emulator has already completed!")
-                    return False
-        return sut_ok
-
     def _get_avd_type(self, requested):
         if requested in AVD_DICT.keys():
             return requested
         if self.substs:
             if not self.substs['TARGET_CPU'].startswith('arm'):
                 return 'x86'
         return '4.3'
 
--- a/testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py
+++ b/testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py
@@ -205,18 +205,18 @@ class FirefoxMediaTestsBase(TestingMixin
         if self.symbols_path:
             cmd += ['--symbols-path', self.symbols_path]
         if self.media_urls:
             cmd += ['--urls', self.media_urls]
         if self.profile:
             cmd += ['--profile', self.profile]
         if self.tests:
             cmd.append(self.tests)
-        if self.e10s:
-            cmd.append('--e10s')
+        if not self.e10s:
+            cmd.append('--disable-e10s')
         if self.browsermob_script:
             cmd += ['--browsermob-script', self.browsermob_script]
         if self.browsermob_port:
             cmd += ['--browsermob-port', self.browsermob_port]
 
         test_suite = self.config.get('test_suite')
         if test_suite not in self.config["suite_definitions"]:
             self.fatal("%s is not defined in the config!" % test_suite)
--- a/testing/mozharness/scripts/desktop_unittest.py
+++ b/testing/mozharness/scripts/desktop_unittest.py
@@ -28,16 +28,17 @@ from mozharness.mozilla.blob_upload impo
 from mozharness.mozilla.mozbase import MozbaseMixin
 from mozharness.mozilla.testing.codecoverage import (
     CodeCoverageMixin,
     code_coverage_config_options
 )
 from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options
 
 SUITE_CATEGORIES = ['gtest', 'cppunittest', 'jittest', 'mochitest', 'reftest', 'xpcshell', 'mozbase', 'mozmill']
+SUITE_DEFAULT_E10S = ['mochitest', 'reftest']
 
 # DesktopUnittest {{{1
 class DesktopUnittest(TestingMixin, MercurialScript, BlobUploadMixin, MozbaseMixin, CodeCoverageMixin):
     config_options = [
         [['--mochitest-suite', ], {
             "action": "extend",
             "dest": "specified_mochitest_suites",
             "type": "string",
@@ -314,17 +315,19 @@ class DesktopUnittest(TestingMixin, Merc
                                           'gtest'),
             }
 
             # TestingMixin._download_and_extract_symbols() will set
             # self.symbols_path when downloading/extracting.
             if self.symbols_path:
                 str_format_values['symbols_path'] = self.symbols_path
 
-            if c['e10s']:
+            if suite_category in SUITE_DEFAULT_E10S and not c['e10s']:
+                base_cmd.append('--disable-e10s')
+            elif suite_category not in SUITE_DEFAULT_E10S and c['e10s']:
                 base_cmd.append('--e10s')
 
             if c.get('strict_content_sandbox'):
                 if suite_category == "mochitest":
                     base_cmd.append('--strict-content-sandbox')
                 else:
                     self.fatal("--strict-content-sandbox only works with mochitest suites.")
 
--- a/testing/mozharness/scripts/marionette.py
+++ b/testing/mozharness/scripts/marionette.py
@@ -135,16 +135,17 @@ class MarionetteTest(TestingMixin, Mercu
         {"action": "store",
          "dest": "this_chunk",
          "help": "Number of this chunk",
         }
      ], [
         ["--e10s"],
         {"action": "store_true",
          "dest": "e10s",
+         "default": False,
          "help": "Run tests with multiple processes. (Desktop builds only)",
         }
      ]] + copy.deepcopy(testing_config_options) \
         + copy.deepcopy(blobupload_config_options)
 
     error_list = [
         {'substr': 'FAILED (errors=', 'level': WARNING},
         {'substr': r'''Could not successfully complete transport of message to Gecko, socket closed''', 'level': ERROR},
@@ -413,18 +414,18 @@ class MarionetteTest(TestingMixin, Mercu
                                               'runtests.py')]
 
             manifest = os.path.join(dirs['abs_marionette_tests_dir'],
                                     self.config['test_manifest'])
 
             if self.config.get('app_arg'):
                 config_fmt_args['app_arg'] = self.config['app_arg']
 
-            if self.config.get('e10s'):
-                cmd.append('--e10s')
+            if not self.config['e10s']:
+                cmd.append('--disable-e10s')
 
             cmd.append('--gecko-log=%s' % os.path.join(dirs["abs_blob_upload_dir"],
                                                        'gecko.log'))
 
         if self.config.get("structured_output"):
             config_fmt_args["raw_log_file"]= "-"
 
         options_group = self._get_options_group(self.config.get('emulator'),
--- a/testing/mozharness/scripts/web_platform_tests.py
+++ b/testing/mozharness/scripts/web_platform_tests.py
@@ -24,16 +24,17 @@ class WebPlatformTest(TestingMixin, Merc
         [['--test-type'], {
             "action": "extend",
             "dest": "test_type",
             "help": "Specify the test types to run."}
          ],
         [['--e10s'], {
             "action": "store_true",
             "dest": "e10s",
+            "default": False,
             "help": "Run with e10s enabled"}
          ],
         [["--total-chunks"], {
             "action": "store",
             "dest": "total_chunks",
             "help": "Number of total chunks"}
          ],
         [["--this-chunk"], {
@@ -130,18 +131,18 @@ class WebPlatformTest(TestingMixin, Merc
                                                        "wpt_errorsummary.log"),
                 "--binary=%s" % self.binary_path,
                 "--symbols-path=%s" % self.query_symbols_url(),
                 "--stackwalk-binary=%s" % self.query_minidump_stackwalk()]
 
         for test_type in c.get("test_type", []):
             cmd.append("--test-type=%s" % test_type)
 
-        if c.get("e10s"):
-            cmd.append("--e10s")
+        if not c["e10s"]:
+            cmd.append("--disable-e10s")
 
         for opt in ["total_chunks", "this_chunk"]:
             val = c.get(opt)
             if val:
                 cmd.append("--%s=%s" % (opt.replace("_", "-"), val))
 
         options = list(c.get("options", []))
 
--- a/testing/puppeteer/firefox/firefox_puppeteer/testcases/base.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/testcases/base.py
@@ -31,22 +31,30 @@ class BaseFirefoxTestCase(unittest.TestC
     parent class.
 
     """
     def __init__(self, *args, **kwargs):
         super(BaseFirefoxTestCase, self).__init__(*args, **kwargs)
 
     def _check_and_fix_leaked_handles(self):
         handle_count = len(self.marionette.window_handles)
+        url = []
 
         try:
-            self.assertEqual(handle_count, self._start_handle_count,
-                             'A test must not leak window handles. This test started with '
-                             '%s open top level browsing contexts, but ended with %s.' %
-                             (self._start_handle_count, handle_count))
+            #Verify the existence of leaked tabs and print their URLs.
+            if self._start_handle_count < handle_count:
+                message = ('A test must not leak window handles. This test started with '
+                           '%s open top level browsing contexts, but ended with %s.'
+                           ' Remaining Tabs URLs:') % (self._start_handle_count , handle_count)
+                with self.marionette.using_context('content'):
+                    for tab in self.marionette.window_handles:
+                        if tab not in self._init_tab_handles:
+                            url.append(' %s' % self.marionette.get_url())
+                self.assertListEqual(self._init_tab_handles , self.marionette.window_handles ,
+                                     message + ','.join(url))
         finally:
             # For clean-up make sure we work on a proper browser window
             if not self.browser or self.browser.closed:
                 # Find a proper replacement browser window
                 # TODO: We have to make this less error prone in case no browser is open.
                 self.browser = self.windows.switch_to(lambda win: type(win) is BrowserWindow)
 
             # Ensure to close all the remaining chrome windows to give following
@@ -78,16 +86,17 @@ class BaseFirefoxTestCase(unittest.TestC
 
         # Ensure that we always have a valid browser instance available
         self.browser = self.windows.switch_to(lambda win: type(win) is BrowserWindow)
 
     def setUp(self, *args, **kwargs):
         super(BaseFirefoxTestCase, self).setUp(*args, **kwargs)
 
         self._start_handle_count = len(self.marionette.window_handles)
+        self._init_tab_handles = self.marionette.window_handles
         self.marionette.set_context('chrome')
 
         self.browser = self.windows.current
         self.browser.focus()
         with self.marionette.using_context(self.marionette.CONTEXT_CONTENT):
             # Ensure that we have a default page opened
             self.marionette.navigate(self.prefs.get_pref('browser.newtab.url'))
 
--- a/testing/talos/talos.json
+++ b/testing/talos/talos.json
@@ -3,104 +3,104 @@
         "url": "http://talos-bundles.pvt.build.mozilla.org/zips/talos.a6052c33d420.zip",
         "path": ""
     },
     "extra_options": {
         "android": [ "--apkPath=%(apk_path)s" ]
     },
     "suites": {
         "chromez": {
-            "tests": ["tresize", "tcanvasmark"]
+            "tests": ["tresize", "tcanvasmark"],
+            "talos_options": ["--disable-e10s"]
         },
         "chromez-e10s": {
-            "tests": ["tresize", "tcanvasmark"],
-            "talos_options": ["--e10s"]
+            "tests": ["tresize", "tcanvasmark"]
         },
         "dromaeojs": {
-            "tests": ["dromaeo_css", "kraken"]
+            "tests": ["dromaeo_css", "kraken"],
+            "talos_options": ["--disable-e10s"]
         },
         "dromaeojs-e10s": {
-            "tests": ["dromaeo_css", "kraken"],
-            "talos_options": ["--e10s"]
+            "tests": ["dromaeo_css", "kraken"]
         },
         "other": {
-            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"]
+            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"],
+            "talos_options": ["--disable-e10s"]
         },
         "other-e10s": {
-            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"],
-            "talos_options": ["--e10s"]
+            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"]
         },
         "other_nol64": {
-            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"]
+            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"],
+            "talos_options": ["--disable-e10s"]
         },
         "other-e10s_nol64": {
-            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"],
-            "talos_options": ["--e10s"]
+            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"]
         },
         "other_l64": {
-            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"]
+            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"],
+            "talos_options": ["--disable-e10s"]
         },
         "other-e10s_l64": {
-            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"],
-            "talos_options": ["--e10s"]
+            "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint"]
         },
         "g1": {
             "tests": ["tp5o_scroll", "glterrain"],
+            "talos_options": ["--disable-e10s"],
             "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip"
         },
         "g1-e10s": {
             "tests": ["tp5o_scroll", "glterrain"],
-            "talos_options": ["--e10s"],
             "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip"
         },
         "g2": {
             "tests": ["damp", "tps"],
+            "talos_options": ["--disable-e10s"],
             "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip"
         },
         "g2-e10s": {
             "tests": ["damp", "tps"],
-            "talos_options": ["--e10s"],
             "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip"
         },
         "g3": {
-            "tests": ["dromaeo_dom"]
+            "tests": ["dromaeo_dom"],
+            "talos_options": ["--disable-e10s"]
         },
         "g3-e10s": {
-            "tests": ["dromaeo_dom"],
-            "talos_options": ["--e10s"]
+            "tests": ["dromaeo_dom"]
         },
         "svgr": {
-            "tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx", "cart"]
+            "tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx", "cart"],
+            "talos_options": ["--disable-e10s"]
         },
         "svgr-e10s": {
-            "tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx", "cart"],
-            "talos_options": ["--e10s"]
+            "tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx", "cart"]
         },
         "tp5o": {
             "tests": ["tp5o"],
+            "talos_options": ["--disable-e10s"],
             "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip"
         },
         "tp5o-e10s": {
             "tests": ["tp5o"],
-            "talos_options": ["--e10s"],
             "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip"
         },
         "xperf": {
             "tests": ["tp5n"],
             "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip",
             "talos_options": [
+                "--disable-e10s",
                 "--xperf_path",
                 "\"c:/Program Files/Microsoft Windows Performance Toolkit/xperf.exe\""
             ]
         },
         "xperf-e10s": {
             "tests": ["tp5n"],
             "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip",
             "talos_options": [
-                "--e10s",
                 "--xperf_path",
                 "\"c:/Program Files/Microsoft Windows Performance Toolkit/xperf.exe\""
             ]
         }
     },
     "mobile-suites": {
         "remote-tsvgx": {
             "tests": ["tsvgm"],
--- a/testing/talos/talos/cmdline.py
+++ b/testing/talos/talos/cmdline.py
@@ -62,18 +62,19 @@ def create_parser(mach_interface=False):
     add_arg('--branchName', dest="branch_name", default='',
             help="Name of the branch we are testing on")
     add_arg('--browserWait', dest='browser_wait', default=5, type=int,
             help="Amount of time allowed for the browser to cleanly close")
     add_arg('-a', '--activeTests',
             help="List of tests to run, separated by ':' (ex. damp:cart)")
     add_arg('--suite',
             help="Suite to use (instead of --activeTests)")
-    add_arg('--e10s', action='store_true',
-            help="enable e10s")
+    add_arg('--disable-e10s', dest='e10s',
+            action='store_false', default=True,
+            help="disable e10s")
     add_arg('--noChrome', action='store_true',
             help="do not run tests as chrome")
     add_arg('--rss', action='store_true',
             help="Collect RSS counters from pageloader instead of the"
                  " operating system")
     add_arg('--mainthread', action='store_true',
             help="Collect mainthread IO data from the browser by setting"
                  " an environment variable")
--- a/testing/web-platform/harness/wptrunner/wptcommandline.py
+++ b/testing/web-platform/harness/wptrunner/wptcommandline.py
@@ -154,18 +154,18 @@ def create_parser(product_choices=None):
     ssl_group.add_argument("--host-key-path", action="store", type=abs_path,
                         help="Path to host private key when using pregenerated ssl certificates")
     ssl_group.add_argument("--host-cert-path", action="store", type=abs_path,
                         help="Path to host certificate when using pregenerated ssl certificates")
 
     gecko_group = parser.add_argument_group("Gecko-specific")
     gecko_group.add_argument("--prefs-root", dest="prefs_root", action="store", type=abs_path,
                              help="Path to the folder containing browser prefs")
-    gecko_group.add_argument("--e10s", dest="gecko_e10s", action="store_true",
-                             help="Run tests with electrolysis preferences")
+    gecko_group.add_argument("--disable-e10s", dest="gecko_e10s", action="store_false", default=True,
+                             help="Run tests without electrolysis preferences")
 
     b2g_group = parser.add_argument_group("B2G-specific")
     b2g_group.add_argument("--b2g-no-backup", action="store_true", default=False,
                            help="Don't backup device before testrun with --product=b2g")
 
     servo_group = parser.add_argument_group("Servo-specific")
     servo_group.add_argument("--user-stylesheet",
                              default=[], action="append", dest="user_stylesheets",
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -28389,44 +28389,44 @@
         "path": "web-animations/animatable/animate.html",
         "url": "/web-animations/animatable/animate.html"
       },
       {
         "path": "web-animations/animation-effect-timing/delay.html",
         "url": "/web-animations/animation-effect-timing/delay.html"
       },
       {
+        "path": "web-animations/animation-effect-timing/direction.html",
+        "url": "/web-animations/animation-effect-timing/direction.html"
+      },
+      {
         "path": "web-animations/animation-effect-timing/duration.html",
         "url": "/web-animations/animation-effect-timing/duration.html"
       },
       {
         "path": "web-animations/animation-effect-timing/endDelay.html",
         "url": "/web-animations/animation-effect-timing/endDelay.html"
       },
       {
         "path": "web-animations/animation-effect-timing/getAnimations.html",
         "url": "/web-animations/animation-effect-timing/getAnimations.html"
       },
       {
         "path": "web-animations/animation-effect-timing/getComputedStyle.html",
         "url": "/web-animations/animation-effect-timing/getComputedStyle.html"
       },
       {
+        "path": "web-animations/animation-effect-timing/iterationStart.html",
+        "url": "/web-animations/animation-effect-timing/iterationStart.html"
+      },
+      {
         "path": "web-animations/animation-effect-timing/iterations.html",
         "url": "/web-animations/animation-effect-timing/iterations.html"
       },
       {
-        "path": "web-animations/animation-effect-timing/iterationStart.html",
-        "url": "/web-animations/animation-effect-timing/iterationStart.html"
-      },
-      {
-        "path": "web-animations/animation-effect-timing/direction.html",
-        "url": "/web-animations/animation-effect-timing/direction.html"
-      },
-      {
         "path": "web-animations/animation-timeline/document-timeline.html",
         "url": "/web-animations/animation-timeline/document-timeline.html"
       },
       {
         "path": "web-animations/animation-timeline/idlharness.html",
         "url": "/web-animations/animation-timeline/idlharness.html"
       },
       {
@@ -34873,16 +34873,28 @@
             "references": [
               [
                 "/compat/webkit-text-fill-color-property-001-ref.html",
                 "=="
               ]
             ],
             "url": "/compat/webkit-text-fill-color-property-001c.html"
           }
+        ],
+        "compat/webkit-text-fill-color-property-001d.html": [
+          {
+            "path": "compat/webkit-text-fill-color-property-001d.html",
+            "references": [
+              [
+                "/compat/webkit-text-fill-color-property-001-ref.html",
+                "=="
+              ]
+            ],
+            "url": "/compat/webkit-text-fill-color-property-001d.html"
+          }
         ]
       },
       "testharness": {
         "dom/collections/HTMLCollection-as-proto-length-get-throws.html": [
           {
             "path": "dom/collections/HTMLCollection-as-proto-length-get-throws.html",
             "url": "/dom/collections/HTMLCollection-as-proto-length-get-throws.html"
           }
@@ -34946,16 +34958,28 @@
           "references": [
             [
               "/compat/webkit-text-fill-color-property-001-ref.html",
               "=="
             ]
           ],
           "url": "/compat/webkit-text-fill-color-property-001c.html"
         }
+      ],
+      "compat/webkit-text-fill-color-property-001d.html": [
+        {
+          "path": "compat/webkit-text-fill-color-property-001d.html",
+          "references": [
+            [
+              "/compat/webkit-text-fill-color-property-001-ref.html",
+              "=="
+            ]
+          ],
+          "url": "/compat/webkit-text-fill-color-property-001d.html"
+        }
       ]
     }
   },
   "reftest_nodes": {
     "2dcontext/building-paths/canvas_complexshapes_arcto_001.htm": [
       {
         "path": "2dcontext/building-paths/canvas_complexshapes_arcto_001.htm",
         "references": [
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/compat/webkit-text-fill-color-property-001d.html.ini
@@ -0,0 +1,3 @@
+[webkit-text-fill-color-001d.html]
+  type: reftest
+  prefs: [layout.css.prefixes.webkit:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/compat/webkit-text-fill-color-property-001d.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>webkit-text-fill-color: green</title>
+<link rel="author" title="Jeremy Chen" href="jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://compat.spec.whatwg.org/#the-webkit-text-fill-color">
+<meta name="assert" content="The color of texts should be green">
+<link rel="match" href="webkit-text-fill-color-property-001-ref.html">
+<div style="color: transparent; -webkit-text-fill-color: green;">These texts should be green</div>
--- a/toolkit/components/formautofill/test/loader_common.js
+++ b/toolkit/components/formautofill/test/loader_common.js
@@ -36,29 +36,29 @@
  * processes at first.  Normally, at this point only the registration of test
  * cases happen.  When everything has finished loading, tests are started and
  * appropriately synchronized between processes.
  *
  * Tests can be declared using the add_task syntax:
  *
  * add_task(function* test_something () { ... });
  *   This adds a test either in the parent process or child process:
- *     - Parent: xpcshell, mochitest-chrome without --e10s, mochitest-browser
- *     - Child: mochitest-chrome with --e10s
- *   In the future, these might run in the child process for "xpcshell --e10s".
+ *     - Parent: xpcshell, mochitest-chrome --disable-e10s, mochitest-browser
+ *     - Child: mochitest-chrome with e10s
+ *   In the future, these might run in the child process for "xpcshell".
  *
  * add_task_in_parent_process(function* test_something () { ... });
  *   This test runs in the parent process, but the child process will wait for
  *   its completion before continuing with the next task.  This wait currently
- *   happens only in mochitest-chrome with --e10s, in other frameworks that run
+ *   happens only in mochitest-chrome with e10s, in other frameworks that run
  *   only in the parent process this is the same as a normal add_task.
  *
  * add_task_in_child_process(function* test_something () { ... });
  *   This test runs only in the child process.  This means that the test is not
- *   run unless this is an e10s test, currently mochitest-chrome with --e10s.
+ *   run unless this is an e10s test, currently mochitest-chrome with e10s.
  *
  * add_task_in_both_processes(function* test_something () { ... });
  *   Useful for initialization that must be done both in the parent and the
  *   child, like setting preferences.
  *
  * add_termination_task(function* () { ... });
  *   Registers a new asynchronous termination task.  This is executed after all
  *   test cases in the file finished, and always in the same process where the
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -1359,34 +1359,35 @@ void
 nsBaseWidget::CleanupRemoteDrawing()
 {
   mLastBackBuffer = nullptr;
 }
 
 already_AddRefed<mozilla::gfx::DrawTarget>
 nsBaseWidget::CreateBackBufferDrawTarget(mozilla::gfx::DrawTarget* aScreenTarget,
                                          const LayoutDeviceIntRect& aRect,
-                                         const bool aInitModeClear)
+                                         const LayoutDeviceIntRect& aClearRect)
 {
   MOZ_ASSERT(aScreenTarget);
   gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
   gfx::IntSize size = aRect.ToUnknownRect().Size();
   gfx::IntSize clientSize(GetClientSize().ToUnknownSize());
 
   RefPtr<gfx::DrawTarget> target;
   // Re-use back buffer if possible
   if (mLastBackBuffer &&
       mLastBackBuffer->GetBackendType() == aScreenTarget->GetBackendType() &&
       mLastBackBuffer->GetFormat() == format &&
       size <= mLastBackBuffer->GetSize() &&
       mLastBackBuffer->GetSize() <= clientSize) {
     target = mLastBackBuffer;
     target->SetTransform(gfx::Matrix());
-    if (aInitModeClear) {
-      target->ClearRect(gfx::Rect(0, 0, size.width, size.height));
+    if (!aClearRect.IsEmpty()) {
+      gfx::IntRect clearRect = aClearRect.ToUnknownRect() - aRect.ToUnknownRect().TopLeft();
+      target->ClearRect(gfx::Rect(clearRect.x, clearRect.y, clearRect.width, clearRect.height));
     }
   } else {
     target = aScreenTarget->CreateSimilarDrawTarget(size, format);
     mLastBackBuffer = target;
   }
   return target.forget();
 }
 
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -174,17 +174,17 @@ public:
   virtual void            PostRender(LayerManagerComposite* aManager) override {}
   virtual void            DrawWindowUnderlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) override {}
   virtual void            DrawWindowOverlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) override {}
   virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawing() override;
   virtual void            EndRemoteDrawing() override { };
   virtual void            CleanupRemoteDrawing() override;
   virtual already_AddRefed<mozilla::gfx::DrawTarget> CreateBackBufferDrawTarget(mozilla::gfx::DrawTarget* aScreenTarget,
                                                                                 const LayoutDeviceIntRect& aRect,
-                                                                                const bool aInitModeClear) override;
+                                                                                const LayoutDeviceIntRect& aClearRect) override;
   virtual void            UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override {}
   NS_IMETHOD              SetModal(bool aModal) override;
   virtual uint32_t        GetMaxTouchPoints() const override;
   NS_IMETHOD              SetWindowClass(const nsAString& xulWinType) override;
   virtual nsresult        SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects, bool aIntersectWithExisting) override;
   // Return whether this widget interprets parameters to Move and Resize APIs
   // as "desktop pixels" rather than "device pixels", and therefore
   // applies its GetDefaultScale() value to them before using them as mBounds
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -1320,17 +1320,17 @@ class nsIWidget : public nsISupports {
      */
     virtual void CleanupRemoteDrawing() = 0;
 
     /**
      * Create DrawTarget used as BackBuffer of the screen
      */
     virtual already_AddRefed<mozilla::gfx::DrawTarget> CreateBackBufferDrawTarget(mozilla::gfx::DrawTarget* aScreenTarget,
                                                                                   const LayoutDeviceIntRect& aRect,
-                                                                                  const bool aInitModeClear) = 0;
+                                                                                  const LayoutDeviceIntRect& aClearRect) = 0;
 
     /**
      * A hook for the widget to prepare a Compositor, during the latter's initialization.
      *
      * If this method returns true, it means that the widget will be able to
      * present frames from the compoositor.
      * Returning false will cause the compositor's initialization to fail, and
      * a different compositor backend will be used (if any).