Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 02 Jun 2015 18:20:12 -0700
changeset 266302 20a96e15631afb63521825aefb1faaee9d7bc452
parent 266218 535ab0825603e8fa611d409112a42769b0989468 (current diff)
parent 266301 202024e27e3bf19e31b34cb27dc0a99f559316b4 (diff)
child 266351 b0a507af2b4ad4f98fb3f73a4406e178f897c68a
push id8157
push userjlund@mozilla.com
push dateMon, 29 Jun 2015 20:36:23 +0000
treeherdermozilla-aurora@d480e05bd276 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone41.0a1
Merge inbound to central, a=merge
testing/mochitest/mach_commands.py
--- a/b2g/components/ProcessGlobal.js
+++ b/b2g/components/ProcessGlobal.js
@@ -58,16 +58,28 @@ function ConsoleMessage(aMsg, aLevel) {
       this.logLevel = Ci.nsIConsoleMessage.info;
       break;
     default:
       this.logLevel = Ci.nsIConsoleMessage.debug;
       break;
   }
 }
 
+function toggleUnrestrictedDevtools(unrestricted) {
+  Services.prefs.setBoolPref("devtools.debugger.forbid-certified-apps",
+    !unrestricted);
+  Services.prefs.setBoolPref("dom.apps.developer_mode", unrestricted);
+  // TODO: Remove once bug 1125916 is fixed.
+  Services.prefs.setBoolPref("network.disable.ipc.security", unrestricted);
+  Services.prefs.setBoolPref("dom.webcomponents.enabled", unrestricted);
+  let lock = settings.createLock();
+  lock.set("developer.menu.enabled", unrestricted, null);
+  lock.set("devtools.unrestricted", unrestricted, null);
+}
+
 ConsoleMessage.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleMessage]),
   toString: function() { return this.msg; }
 };
 
 const gFactoryResetFile = "__post_reset_cmd__";
 
 function ProcessGlobal() {}
@@ -94,27 +106,27 @@ ProcessGlobal.prototype = {
   },
 
   processCommandsFile: function(text) {
     log("processCommandsFile " + text);
     let lines = text.split("\n");
     lines.forEach((line) => {
       log(line);
       let params = line.split(" ");
-      if (params[0] == "wipe") {
-        this.wipeDir(params[1]);
-      } else if (params[0] == "root") {
-        log("unrestrict devtools");
-        Services.prefs.setBoolPref("devtools.debugger.forbid-certified-apps", false);
-        Services.prefs.setBoolPref("dom.apps.developer_mode", true);
-        // TODO: Remove once bug 1125916 is fixed.
-        Services.prefs.setBoolPref("network.disable.ipc.security", true);
-        Services.prefs.setBoolPref("dom.webcomponents.enabled", true);
-        let lock = settings.createLock();
-        lock.set("developer.menu.enabled", true, null);
+      switch (params[0]) {
+        case "root":
+          log("unrestrict devtools");
+          toggleUnrestrictedDevtools(true);
+          break;
+        case "wipe":
+          this.wipeDir(params[1]);
+        case "normal":
+          log("restrict devtools");
+          toggleUnrestrictedDevtools(false);
+          break;
       }
     });
   },
 
   cleanupAfterFactoryReset: function() {
     log("cleanupAfterWipe start");
 
     Cu.import("resource://gre/modules/osfile.jsm");
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -71,47 +71,50 @@ NS_IMETHODIMP
 BasePrincipal::GetOriginNoSuffix(nsACString& aOrigin)
 {
   return GetOriginInternal(aOrigin);
 }
 
 bool
 BasePrincipal::Subsumes(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration)
 {
-  MOZ_RELEASE_ASSERT(aOther, "The caller is performing a nonsensical security check!");
+  MOZ_ASSERT(aOther);
   return SubsumesInternal(aOther, aConsideration);
 }
 
 NS_IMETHODIMP
 BasePrincipal::Equals(nsIPrincipal *aOther, bool *aResult)
 {
-
+  NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
   *aResult = Subsumes(aOther, DontConsiderDocumentDomain) &&
              Cast(aOther)->Subsumes(this, DontConsiderDocumentDomain);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::EqualsConsideringDomain(nsIPrincipal *aOther, bool *aResult)
 {
+  NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
   *aResult = Subsumes(aOther, ConsiderDocumentDomain) &&
              Cast(aOther)->Subsumes(this, ConsiderDocumentDomain);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::Subsumes(nsIPrincipal *aOther, bool *aResult)
 {
+  NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
   *aResult = Subsumes(aOther, DontConsiderDocumentDomain);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::SubsumesConsideringDomain(nsIPrincipal *aOther, bool *aResult)
 {
+  NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
   *aResult = Subsumes(aOther, ConsiderDocumentDomain);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
 {
   NS_IF_ADDREF(*aCsp = mCSP);
--- a/dom/apps/tests/test_third_party_homescreen.html
+++ b/dom/apps/tests/test_third_party_homescreen.html
@@ -170,19 +170,16 @@ function runTest() {
                                   "context": context}], continueTest);
   yield undefined;
 
   // Launch the app.
   info("Running " + app.manifestURL);
   runApp(app, continueTest);
   yield undefined;
 
-  SpecialPowers.popPermissions(continueTest);
-  yield undefined;
-
   // Uninstall the app to cleanup after ourself.
   navigator.mozApps.mgmt.onuninstall = function(event) {
     var app = event.application;
     is(app.manifestURL, gManifestURL, "App uninstall event ok.");
     is(app.manifest.name, "Really Rapid Release (hosted)",
        "App uninstall manifest ok.");
     continueTest();
   }
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -31,16 +31,20 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsILoadContext.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsIServiceManager.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIWebNavigation.h"
 #include "nsIXPConnect.h"
 
+#ifdef MOZ_ENABLE_PROFILER_SPS
+#include "nsIProfiler.h"
+#endif
+
 // The maximum allowed number of concurrent timers per page.
 #define MAX_PAGE_TIMERS 10000
 
 // The maximum allowed number of concurrent counters per page.
 #define MAX_PAGE_COUNTERS 10000
 
 // The maximum stacktrace depth when populating the stacktrace array used for
 // console.trace().
@@ -855,16 +859,33 @@ Console::TimeStamp(JSContext* aCx, const
 {
   Sequence<JS::Value> data;
   SequenceRooter<JS::Value> rooter(aCx, &data);
 
   if (aData.isString() && !data.AppendElement(aData, fallible)) {
     return;
   }
 
+#ifdef MOZ_ENABLE_PROFILER_SPS
+  if (aData.isString() && NS_IsMainThread()) {
+    if (!mProfiler) {
+      mProfiler = do_GetService("@mozilla.org/tools/profiler;1");
+    }
+    if (mProfiler) {
+      bool active = false;
+      if (NS_SUCCEEDED(mProfiler->IsActive(&active)) && active) {
+        nsAutoJSString stringValue;
+        if (stringValue.init(aCx, aData)) {
+          mProfiler->AddMarker(NS_ConvertUTF16toUTF8(stringValue).get());
+        }
+      }
+    }
+  }
+#endif
+
   Method(aCx, MethodTimeStamp, NS_LITERAL_STRING("timeStamp"), data);
 }
 
 void
 Console::Profile(JSContext* aCx, const Sequence<JS::Value>& aData)
 {
   ProfileMethod(aCx, NS_LITERAL_STRING("profile"), aData);
 }
--- a/dom/base/Console.h
+++ b/dom/base/Console.h
@@ -13,16 +13,17 @@
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
 #include "nsWrapperCache.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsPIDOMWindow.h"
 
 class nsIConsoleAPIStorage;
+class nsIProfiler;
 class nsIXPConnectJSObjectHolder;
 
 namespace mozilla {
 namespace dom {
 
 class ConsoleCallData;
 struct ConsoleStackEntry;
 
@@ -198,16 +199,19 @@ private:
   ShouldIncludeStackTrace(MethodName aMethodName);
 
   nsIXPConnectJSObjectHolder*
   GetOrCreateSandbox(JSContext* aCx, nsIPrincipal* aPrincipal);
 
   nsCOMPtr<nsPIDOMWindow> mWindow;
   nsCOMPtr<nsIConsoleAPIStorage> mStorage;
   nsCOMPtr<nsIXPConnectJSObjectHolder> mSandbox;
+#ifdef MOZ_ENABLE_PROFILER_SPS
+  nsCOMPtr<nsIProfiler> mProfiler;
+#endif
 
   nsDataHashtable<nsStringHashKey, DOMHighResTimeStamp> mTimerRegistry;
   nsDataHashtable<nsStringHashKey, uint32_t> mCounterRegistry;
 
   uint64_t mOuterID;
   uint64_t mInnerID;
 
   friend class ConsoleCallData;
--- a/dom/base/nsContentPolicyUtils.h
+++ b/dom/base/nsContentPolicyUtils.h
@@ -108,16 +108,17 @@ NS_CP_ContentTypeName(uint32_t contentTy
     CASE_RETURN( TYPE_FONT              );
     CASE_RETURN( TYPE_MEDIA             );
     CASE_RETURN( TYPE_WEBSOCKET         );
     CASE_RETURN( TYPE_CSP_REPORT        );
     CASE_RETURN( TYPE_XSLT              );
     CASE_RETURN( TYPE_BEACON            );
     CASE_RETURN( TYPE_FETCH             );
     CASE_RETURN( TYPE_IMAGESET          );
+    CASE_RETURN( TYPE_WEB_MANIFEST      );
    default:
     return "<Unknown Type>";
   }
 }
 
 #undef CASE_RETURN
 
 /* Passes on parameters from its "caller"'s context. */
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -1655,17 +1655,17 @@ nsContentUtils::ParseLegacyFontSize(cons
     relative = true;
     negate = true;
     ++iter;
   } else if (*iter == char16_t('+')) {
     relative = true;
     ++iter;
   }
 
-  if (*iter < char16_t('0') || *iter > char16_t('9')) {
+  if (iter == end || *iter < char16_t('0') || *iter > char16_t('9')) {
     return 0;
   }
 
   // We don't have to worry about overflow, since we can bail out as soon as
   // we're bigger than 7.
   int32_t value = 0;
   while (iter != end && *iter >= char16_t('0') && *iter <= char16_t('9')) {
     value = 10*value + (*iter - char16_t('0'));
--- a/dom/base/nsDataDocumentContentPolicy.cpp
+++ b/dom/base/nsDataDocumentContentPolicy.cpp
@@ -118,17 +118,18 @@ nsDataDocumentContentPolicy::ShouldLoad(
   }
 
   // For resource documents, blacklist some load types
   if (aContentType == nsIContentPolicy::TYPE_OBJECT ||
       aContentType == nsIContentPolicy::TYPE_DOCUMENT ||
       aContentType == nsIContentPolicy::TYPE_SUBDOCUMENT ||
       aContentType == nsIContentPolicy::TYPE_SCRIPT ||
       aContentType == nsIContentPolicy::TYPE_XSLT ||
-      aContentType == nsIContentPolicy::TYPE_FETCH) {
+      aContentType == nsIContentPolicy::TYPE_FETCH ||
+      aContentType == nsIContentPolicy::TYPE_WEB_MANIFEST) {
     *aDecision = nsIContentPolicy::REJECT_TYPE;
   }
 
   // If you add more restrictions here, make sure to check that
   // CHECK_PRINCIPAL_AND_DATA in nsContentPolicyUtils is still valid.
   // nsContentPolicyUtils may not pass all the parameters to ShouldLoad
 
   return NS_OK;
--- a/dom/base/nsIContentPolicy.idl
+++ b/dom/base/nsIContentPolicy.idl
@@ -15,17 +15,17 @@ interface nsIPrincipal;
  * Interface for content policy mechanism.  Implementations of this
  * interface can be used to control loading of various types of out-of-line
  * content, or processing of certain types of in-line content.
  *
  * WARNING: do not block the caller from shouldLoad or shouldProcess (e.g.,
  * by launching a dialog to prompt the user for something).
  */
 
-[scriptable,uuid(447a2300-ab3c-11e4-bcd8-0800200c9a66)]
+[scriptable,uuid(cb978019-0c5b-4067-abb6-c914461208c1)]
 interface nsIContentPolicy : nsIContentPolicyBase
 {
   /**
    * Should the resource at this location be loaded?
    * ShouldLoad will be called before loading the resource at aContentLocation
    * to determine whether to start the load at all.
    *
    * @param aContentType      the type of content being tested. This will be one
--- a/dom/base/nsIContentPolicyBase.idl
+++ b/dom/base/nsIContentPolicyBase.idl
@@ -19,17 +19,17 @@ typedef unsigned long nsContentPolicyTyp
  * Interface for content policy mechanism.  Implementations of this
  * interface can be used to control loading of various types of out-of-line
  * content, or processing of certain types of in-line content.
  *
  * WARNING: do not block the caller from shouldLoad or shouldProcess (e.g.,
  * by launching a dialog to prompt the user for something).
  */
 
-[scriptable,uuid(21bb54b0-ab3c-11e4-bcd8-0800200c9a66)]
+[scriptable,uuid(4f2655e8-6365-4583-8510-732bff2186c5)]
 interface nsIContentPolicyBase : nsISupports
 {
   /**
    * Indicates a unset or bogus policy type.
    */
   const nsContentPolicyType TYPE_INVALID = 0;
 
   /**
@@ -167,16 +167,21 @@ interface nsIContentPolicyBase : nsISupp
    */
   const nsContentPolicyType TYPE_FETCH = 20;
 
   /**
    * Indicates a <img srcset> or <picture> request.
    */
   const nsContentPolicyType TYPE_IMAGESET = 21;
 
+  /**
+   * Indicates a web manifest.
+   */
+  const nsContentPolicyType TYPE_WEB_MANIFEST = 22;
+
   /* When adding new content types, please update nsContentBlocker,
    * NS_CP_ContentTypeName, nsCSPContext, all nsIContentPolicy
    * implementations, and other things that are not listed here that are
    * related to nsIContentPolicy. */
 
   //////////////////////////////////////////////////////////////////////
 
   /**
--- a/dom/base/nsISimpleContentPolicy.idl
+++ b/dom/base/nsISimpleContentPolicy.idl
@@ -23,17 +23,17 @@ interface nsIDOMElement;
  * to block loads without using cross-process wrappers (CPOWs). Add-ons should
  * prefer this interface to nsIContentPolicy because it should be faster in
  * e10s. In the future, it may also be run asynchronously.
  *
  * WARNING: do not block the caller from shouldLoad or shouldProcess (e.g.,
  * by launching a dialog to prompt the user for something).
  */
 
-[scriptable,uuid(83d93c70-ab46-11e4-bcd8-0800200c9a66)]
+[scriptable,uuid(704b4b8e-2287-498a-9c0a-d1bde547a2d4)]
 interface nsISimpleContentPolicy : nsIContentPolicyBase
 {
   /**
    * Should the resource at this location be loaded?
    * ShouldLoad will be called before loading the resource at aContentLocation
    * to determine whether to start the load at all.
    *
    * @param aContentType      the type of content being tested. This will be one
new file mode 100644
--- /dev/null
+++ b/dom/base/test/csp/browser.ini
@@ -0,0 +1,4 @@
+[DEFAULT]
+skip-if = e10s # Bug 1170385 - csp-on-violate-policy message not sent in browser tests with e10s
+[browser_test_web_manifest.js]
+[browser_test_web_manifest_mixed_content.js]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/csp/browser_test_web_manifest.js
@@ -0,0 +1,265 @@
+/*
+ * Description of the tests:
+ *   These tests check for conformance to the CSP spec as they relate to Web Manifests.
+ *
+ *   In particular, the tests check that default-src and manifest-src directives are
+ *   are respected by the ManifestObtainer.
+ */
+/*globals Components*/
+'use strict';
+requestLongerTimeout(10); // e10s tests take time.
+const {
+  ManifestObtainer
+} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {});
+const path = '/tests/dom/base/test/csp/';
+const testFile = `file=${path}file_CSP_web_manifest.html`;
+const remoteFile = `file=${path}file_CSP_web_manifest_remote.html`;
+const httpsManifest = `file=${path}file_CSP_web_manifest_https.html`;
+const mixedContent = `file=${path}file_CSP_web_manifest_mixed_content.html`;
+const server = 'file_csp_testserver.sjs';
+const defaultURL = `http://example.org${path}${server}`;
+const remoteURL = `http://mochi.test:8888`;
+const secureURL = `https://example.com${path}${server}`;
+const tests = [
+  // CSP block everything, so trying to load a manifest
+  // will result in a policy violation.
+  {
+    expected: `default-src 'none' blocks fetching manifest.`,
+    get tabURL() {
+      let queryParts = [
+        `csp=default-src 'none'`,
+        testFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(topic) {
+      is(topic, 'csp-on-violate-policy', this.expected);
+    }
+  },
+  // CSP allows fetching only from mochi.test:8888,
+  // so trying to load a manifest from same origin
+  // triggers a CSP violation.
+  {
+    expected: `default-src mochi.test:8888 blocks manifest fetching.`,
+    get tabURL() {
+      let queryParts = [
+        `csp=default-src mochi.test:8888`,
+        testFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(topic) {
+      is(topic, 'csp-on-violate-policy', this.expected);
+    }
+  },
+  // CSP restricts fetching to 'self', so allowing the manifest
+  // to load. The name of the manifest is then checked.
+  {
+    expected: `CSP default-src 'self' allows fetch of manifest.`,
+    get tabURL() {
+      let queryParts = [
+        `csp=default-src 'self'`,
+        testFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(manifest) {
+      is(manifest.name, 'loaded', this.expected);
+    }
+  },
+  // CSP only allows fetching from mochi.test:8888 and remoteFile
+  // requests a manifest from that origin, so manifest should load.
+  {
+    expected: 'CSP default-src mochi.test:8888 allows fetching manifest.',
+    get tabURL() {
+      let queryParts = [
+        `csp=default-src http://mochi.test:8888`,
+        remoteFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(manifest) {
+      is(manifest.name, 'loaded', this.expected);
+    }
+  },
+  // default-src blocks everything, so any attempt to
+  // fetch a manifest from another origin will trigger a
+  // policy violation.
+  {
+    expected: `default-src 'none' blocks mochi.test:8888`,
+    get tabURL() {
+      let queryParts = [
+        `csp=default-src 'none'`,
+        remoteFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(topic) {
+      is(topic, 'csp-on-violate-policy', this.expected);
+    }
+  },
+  // CSP allows fetching from self, so manifest should load.
+  {
+    expected: `CSP manifest-src allows self`,
+    get tabURL() {
+      let queryParts = [
+        `manifest-src 'self'`,
+        testFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(manifest) {
+      is(manifest.name, 'loaded', this.expected);
+    }
+  },
+  // CSP allows fetching from example.org, so manifest should load.
+  {
+    expected: `CSP manifest-src allows http://example.org`,
+    get tabURL() {
+      let queryParts = [
+        `manifest-src http://example.org`,
+        testFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(manifest) {
+      is(manifest.name, 'loaded', this.expected);
+    }
+  },
+  // Check interaction with default-src and another origin,
+  // CSP allows fetching from example.org, so manifest should load.
+  {
+    expected: `CSP manifest-src overrides default-src of elsewhere.com`,
+    get tabURL() {
+      let queryParts = [
+        `default-src: http://elsewhere.com; manifest-src http://example.org`,
+        testFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(manifest) {
+      is(manifest.name, 'loaded', this.expected);
+    }
+  },
+  // Check interaction with default-src none,
+  // CSP allows fetching manifest from example.org, so manifest should load.
+  {
+    expected: `CSP manifest-src overrides default-src`,
+    get tabURL() {
+      let queryParts = [
+        `default-src: 'none'; manifest-src 'self'`,
+        testFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(manifest) {
+      is(manifest.name, 'loaded', this.expected);
+    }
+  },
+  // CSP allows fetching from mochi.test:8888, which has a
+  // CORS header set to '*'. So the manifest should load.
+  {
+    expected: `CSP manifest-src allows mochi.test:8888`,
+    get tabURL() {
+      let queryParts = [
+        `csp=default-src *; manifest-src http://mochi.test:8888`,
+        remoteFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(manifest) {
+      is(manifest.name, 'loaded', this.expected);
+    }
+  },
+  // CSP restricts fetching to mochi.test:8888, but the test
+  // file is at example.org. Hence, a policy violation is
+  // triggered.
+  {
+    expected: `CSP blocks manifest fetching from example.org.`,
+    get tabURL() {
+      let queryParts = [
+        `csp=manifest-src mochi.test:8888`,
+        testFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(topic) {
+      is(topic, 'csp-on-violate-policy', this.expected);
+    }
+  },
+  // CSP is set to only allow manifest to be loaded from same origin,
+  // but the remote file attempts to load from a different origin. Thus
+  // this causes a CSP violation.
+  {
+    expected: `CSP manifest-src 'self' blocks cross-origin fetch.`,
+    get tabURL() {
+      let queryParts = [
+        `csp=manifest-src 'self'`,
+        remoteFile
+      ];
+      return `${defaultURL}?${queryParts.join('&')}`;
+    },
+    run(topic) {
+      is(topic, 'csp-on-violate-policy', this.expected);
+    }
+  }
+];
+//jscs:disable
+add_task(function* () {
+  //jscs:enable
+  for (let test of tests) {
+    let tabOptions = {
+      gBrowser: gBrowser,
+      url: test.tabURL,
+    };
+    yield BrowserTestUtils.withNewTab(
+      tabOptions,
+      browser => testObtainingManifest(browser, test)
+    );
+  }
+
+  function* testObtainingManifest(aBrowser, aTest) {
+    const observer = (/blocks/.test(aTest.expected)) ? new NetworkObserver(aTest) : null;
+    const obtainer = new ManifestObtainer();
+    let manifest;
+    // Expect an exception (from promise rejection) if there a content policy
+    // that is violated.
+    try {
+      manifest = yield obtainer.obtainManifest(aBrowser);
+    } catch (e) {
+      const msg = `Expected promise rejection obtaining.`;
+      ok(/blocked the loading of a resource/.test(e.message), msg);
+      if (observer) {
+        yield observer.finished;
+      }
+      return;
+    }
+    // otherwise, we test manifest's content.
+    if (manifest) {
+      aTest.run(manifest);
+    }
+  }
+});
+
+// Helper object used to observe policy violations. It waits 10 seconds
+// for a response, and then times out causing its associated test to fail.
+function NetworkObserver(test) {
+  let finishedTest;
+  let success = false;
+  this.finished = new Promise((resolver) => {
+    finishedTest = resolver;
+  })
+  this.observe = function observer(subject, topic) {
+    SpecialPowers.removeObserver(this, 'csp-on-violate-policy');
+    test.run(topic);
+    finishedTest();
+    success = true;
+  };
+  SpecialPowers.addObserver(this, 'csp-on-violate-policy', false);
+  setTimeout(() => {
+    if (!success) {
+      test.run('This test timed out.');
+      finishedTest();
+    }
+  }, 1000);
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/test/csp/browser_test_web_manifest_mixed_content.js
@@ -0,0 +1,55 @@
+/*
+ * Description of the test:
+ *   Check that mixed content blocker works prevents fetches of
+ *   mixed content manifests.
+ */
+'use strict';
+const {
+  ManifestObtainer
+} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {});
+const path = '/tests/dom/base/test/csp/';
+const mixedContent = `file=${path}file_CSP_web_manifest_mixed_content.html`;
+const server = 'file_csp_testserver.sjs';
+const secureURL = `https://example.com${path}${server}`;
+const tests = [
+  // Trying to load mixed content in file_CSP_web_manifest_mixed_content.html
+  // needs to result in an error.
+  {
+    expected: `Mixed Content Blocker prevents fetching manifest.`,
+    get tabURL() {
+      let queryParts = [
+        mixedContent
+      ];
+      return `${secureURL}?${queryParts.join('&')}`;
+    },
+    run(error) {
+      // Check reason for error.
+      const check = /blocked the loading of a resource/.test(error.message);
+      ok(check, this.expected);
+    }
+  }
+];
+
+//jscs:disable
+add_task(function*() {
+  //jscs:enable
+  for (let test of tests) {
+    let tabOptions = {
+      gBrowser: gBrowser,
+      url: test.tabURL,
+    };
+    yield BrowserTestUtils.withNewTab(
+      tabOptions,
+      browser => testObtainingManifest(browser, test)
+    );
+  }
+
+  function* testObtainingManifest(aBrowser, aTest) {
+    const obtainer = new ManifestObtainer();
+    try {
+      yield obtainer.obtainManifest(aBrowser);
+    } catch (e) {
+      aTest.run(e)
+    }
+  }
+});
new file mode 100644
--- /dev/null
+++ b/dom/base/test/csp/file_CSP_web_manifest.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<meta charset=utf-8>
+<head>
+<link rel="manifest" href="file_CSP_web_manifest.json">
+</head>
+<h1>Support Page for Web Manifest Tests</h1>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/base/test/csp/file_CSP_web_manifest.json
@@ -0,0 +1,1 @@
+{"name": "loaded"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/base/test/csp/file_CSP_web_manifest.json^headers^
@@ -0,0 +1,1 @@
+Access-Control-Allow-Origin: http://example.org
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/base/test/csp/file_CSP_web_manifest_https.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<meta charset=utf-8>
+<link rel="manifest" href="https://example.com:443/tests/dom/base/test/csp/file_CSP_web_manifest_https.json">
+<h1>Support Page for Web Manifest Tests</h1>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/base/test/csp/file_CSP_web_manifest_https.json
@@ -0,0 +1,1 @@
+{"name": "loaded"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/base/test/csp/file_CSP_web_manifest_mixed_content.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<meta charset=utf-8>
+<head>
+<link
+  rel="manifest"
+  href="http://example.org/tests/dom/base/test/csp/file_csp_testserver.sjs?file=/test/dom/base/test/csp/file_CSP_web_manifest.json&amp;cors=*">
+</head>
+<h1>Support Page for Web Manifest Tests</h1>
+<p>Used to try to load a resource over an insecure connection to trigger mixed content blocking.</p>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/base/test/csp/file_CSP_web_manifest_remote.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset=utf-8>
+<link rel="manifest"
+      crossorigin
+	  href="//mochi.test:8888/tests/dom/base/test/csp/file_csp_testserver.sjs?file=/tests/dom/base/test/csp/file_CSP_web_manifest.json&amp;cors=*">
+
+<h1>Support Page for Web Manifest Tests</h1>
+<p>Loads a manifest from mochi.test:8888 with CORS set to "*".</p>
\ No newline at end of file
--- a/dom/base/test/csp/file_csp_testserver.sjs
+++ b/dom/base/test/csp/file_csp_testserver.sjs
@@ -17,29 +17,37 @@ function loadHTMLFromFile(path) {
   var testHTMLFileStream =
     Components.classes["@mozilla.org/network/file-input-stream;1"].
     createInstance(Components.interfaces.nsIFileInputStream);
   testHTMLFileStream.init(testHTMLFile, -1, 0, 0);
   var testHTML = NetUtil.readInputStreamToString(testHTMLFileStream, testHTMLFileStream.available());
   return testHTML;
 }
 
+
 function handleRequest(request, response)
 {
   var query = {};
   request.queryString.split('&').forEach(function (val) {
     var [name, value] = val.split('=');
     query[name] = unescape(value);
   });
 
-  var csp = unescape(query['csp']);
+  var csp = (query['csp']) ? unescape(query['csp']) : "";
   var file = unescape(query['file']);
+  var cors = unescape(query['cors']);
 
   // avoid confusing cache behaviors
   response.setHeader("Cache-Control", "no-cache", false);
 
   // Deliver the CSP policy encoded in the URI
-  response.setHeader("Content-Security-Policy", csp, false);
-
+  if(csp){
+    response.setHeader("Content-Security-Policy", csp, false);
+  }
+  // Deliver the CORS header in the URI
+  if(cors){
+    response.setHeader("Access-Control-Allow-Origin", cors, false);
+  }
   // Send HTML to test allowed/blocked behaviors
   response.setHeader("Content-Type", "text/html", false);
+
   response.write(loadHTMLFromFile(file));
 }
--- a/dom/base/test/csp/mochitest.ini
+++ b/dom/base/test/csp/mochitest.ini
@@ -38,16 +38,23 @@ support-files =
   file_CSP_inlinestyle_main.html
   file_CSP_inlinestyle_main.html^headers^
   file_CSP_inlinestyle_main_allowed.html
   file_CSP_inlinestyle_main_allowed.html^headers^
   file_csp_invalid_source_expression.html
   file_CSP_main.html
   file_CSP_main.html^headers^
   file_CSP_main.js
+  file_CSP_web_manifest.html
+  file_CSP_web_manifest_remote.html
+  file_CSP_web_manifest_https.html
+  file_CSP_web_manifest.json
+  file_CSP_web_manifest.json^headers^
+  file_CSP_web_manifest_https.json
+  file_CSP_web_manifest_mixed_content.html
   file_bug836922_npolicies.html
   file_bug836922_npolicies.html^headers^
   file_bug836922_npolicies_ro_violation.sjs
   file_bug836922_npolicies_violation.sjs
   file_bug886164.html
   file_bug886164.html^headers^
   file_bug886164_2.html
   file_bug886164_2.html^headers^
--- a/dom/base/test/moz.build
+++ b/dom/base/test/moz.build
@@ -32,9 +32,12 @@ if CONFIG['MOZ_CHILD_PERMISSIONS']:
     ]
 
 MOCHITEST_CHROME_MANIFESTS += [
     'chrome.ini',
     'chrome/chrome.ini',
     'csp/chrome.ini',
 ]
 
-BROWSER_CHROME_MANIFESTS += ['browser.ini']
+BROWSER_CHROME_MANIFESTS += [
+    'browser.ini',
+    'csp/browser.ini',
+]
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -807,17 +807,17 @@ TryToOuterize(JSContext* cx, JS::Mutable
 // Make sure to wrap the given string value into the right compartment, as
 // needed.
 MOZ_ALWAYS_INLINE
 bool
 MaybeWrapStringValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
 {
   MOZ_ASSERT(rval.isString());
   JSString* str = rval.toString();
-  if (JS::GetTenuredGCThingZone(str) != js::GetContextZone(cx)) {
+  if (JS::GetStringZone(str) != js::GetContextZone(cx)) {
     return JS_WrapValue(cx, rval);
   }
   return true;
 }
 
 // Make sure to wrap the given object value into the right compartment as
 // needed.  This will work correctly, but possibly slowly, on all objects.
 MOZ_ALWAYS_INLINE
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -13296,16 +13296,19 @@ class CGBindingImplClass(CGClass):
                     (BuiltinTypes[IDLBuiltinType.Types.boolean],
                      [FakeArgument(BuiltinTypes[IDLBuiltinType.Types.domstring],
                                    FakeMember(),
                                    name="aName")]),
                     { "infallible": True }))
 
         wrapArgs = [Argument('JSContext*', 'aCx'),
                     Argument('JS::Handle<JSObject*>', 'aGivenProto')]
+        if not descriptor.wrapperCache:
+            wrapArgs.append(Argument('JS::MutableHandle<JSObject*>',
+                                     'aReflector'))
         self.methodDecls.insert(0,
                                 ClassMethod(wrapMethodName, "JSObject*",
                                             wrapArgs, virtual=descriptor.wrapperCache,
                                             breakAfterReturnDecl=" ",
                                             override=descriptor.wrapperCache,
                                             body=self.getWrapObjectBody()))
         if wantGetParent:
             self.methodDecls.insert(0,
@@ -13413,28 +13416,36 @@ class CGExampleClass(CGBindingImplClass)
                 NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType})
                 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
                   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
                   NS_INTERFACE_MAP_ENTRY(nsISupports)
                 NS_INTERFACE_MAP_END
 
                 """)
 
+        if self.descriptor.wrapperCache:
+            reflectorArg = ""
+            reflectorPassArg = ""
+        else:
+            reflectorArg = ", JS::MutableHandle<JSObject*> aReflector"
+            reflectorPassArg = ", aReflector"
         classImpl = ccImpl + ctordtor + "\n" + dedent("""
             JSObject*
-            ${nativeType}::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+            ${nativeType}::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto${reflectorArg})
             {
-              return ${ifaceName}Binding::Wrap(aCx, this, aGivenProto);
+              return ${ifaceName}Binding::Wrap(aCx, this, aGivenProto${reflectorPassArg});
             }
 
             """)
         return string.Template(classImpl).substitute(
             ifaceName=self.descriptor.name,
             nativeType=self.nativeLeafName(self.descriptor),
-            parentType=self.nativeLeafName(self.parentDesc) if self.parentIface else "")
+            parentType=self.nativeLeafName(self.parentDesc) if self.parentIface else "",
+            reflectorArg=reflectorArg,
+            reflectorPassArg=reflectorPassArg)
 
     @staticmethod
     def nativeLeafName(descriptor):
         return descriptor.nativeType.split('::')[-1]
 
 
 class CGExampleRoot(CGThing):
     """
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -163,16 +163,19 @@ InternalRequest::SetContentPolicyType(ns
     mContext = RequestContext::Beacon;
     break;
   case nsIContentPolicy::TYPE_FETCH:
     mContext = RequestContext::Fetch;
     break;
   case nsIContentPolicy::TYPE_IMAGESET:
     mContext = RequestContext::Imageset;
     break;
+  case nsIContentPolicy::TYPE_WEB_MANIFEST:
+    mContext = RequestContext::Manifest;
+    break;
   default:
     MOZ_ASSERT(false, "Unhandled nsContentPolicyType value");
     mContext = RequestContext::Internal;
     break;
   }
 }
 
 } // namespace dom
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -44,17 +44,17 @@ namespace dom {
  * frame             | TYPE_SUBDOCUMENT
  * hyperlink         |
  * iframe            | TYPE_SUBDOCUMENT
  * image             | TYPE_IMAGE
  * imageset          | TYPE_IMAGESET
  * import            | Not supported by Gecko
  * internal          | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER
  * location          |
- * manifest          |
+ * manifest          | TYPE_WEB_MANIFEST
  * object            | TYPE_OBJECT
  * ping              | TYPE_PING
  * plugin            | TYPE_OBJECT_SUBREQUEST
  * prefetch          |
  * script            | TYPE_SCRIPT
  * serviceworker     |
  * sharedworker      |
  * subresource       | Not supported by Gecko
--- a/dom/interfaces/security/nsIContentSecurityPolicy.idl
+++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl
@@ -15,17 +15,17 @@ interface nsIURI;
  * nsIContentSecurityPolicy
  * Describes an XPCOM component used to model and enforce CSPs.  Instances of
  * this class may have multiple policies within them, but there should only be
  * one of these per document/principal.
  */
 
 typedef unsigned short CSPDirective;
 
-[scriptable, uuid(459fe61a-203e-4460-9ced-352a9bd3aa71)]
+[scriptable, uuid(059b94e3-45c2-4794-ac2a-5b66a66b5967)]
 interface nsIContentSecurityPolicy : nsISerializable
 {
   /**
    * Directives supported by Content Security Policy.  These are enums for
    * the CSPDirective type.
    * The NO_DIRECTIVE entry is  used for checking default permissions and
    * returning failure when asking CSP which directive to check.
    *
@@ -43,16 +43,17 @@ interface nsIContentSecurityPolicy : nsI
   const unsigned short FONT_SRC_DIRECTIVE         = 8;
   const unsigned short CONNECT_SRC_DIRECTIVE      = 9;
   const unsigned short REPORT_URI_DIRECTIVE       = 10;
   const unsigned short FRAME_ANCESTORS_DIRECTIVE  = 11;
   const unsigned short REFLECTED_XSS_DIRECTIVE    = 12;
   const unsigned short BASE_URI_DIRECTIVE         = 13;
   const unsigned short FORM_ACTION_DIRECTIVE      = 14;
   const unsigned short REFERRER_DIRECTIVE         = 15;
+  const unsigned short WEB_MANIFEST_SRC_DIRECTIVE = 16;
 
   /**
    * Accessor method for a read-only string version of the policy at a given
    * index.
    */
   AString getPolicy(in unsigned long index);
 
   /**
--- a/dom/ipc/manifestMessages.js
+++ b/dom/ipc/manifestMessages.js
@@ -9,95 +9,114 @@
  * a <link rel=manifest> element. Then fetches
  * and processes the linked manifest.
  *
  * BUG: https://bugzilla.mozilla.org/show_bug.cgi?id=1083410
  */
 /*globals content, sendAsyncMessage, addMessageListener, Components*/
 'use strict';
 const {
-  utils: Cu
+  utils: Cu,
+  classes: Cc,
+  interfaces: Ci
 } = Components;
 const {
   ManifestProcessor
 } = Cu.import('resource://gre/modules/WebManifest.jsm', {});
+const {
+  Task: {
+    spawn, async
+  }
+} = Components.utils.import('resource://gre/modules/Task.jsm', {});
 
-addMessageListener('DOM:ManifestObtainer:Obtain', (aMsg) => {
-  fetchManifest()
-    .then(
-      manifest => sendAsyncMessage('DOM:ManifestObtainer:Obtain', {
-        success: true,
-        result: manifest,
-        msgId: aMsg.data.msgId
-      }),
-      error => sendAsyncMessage('DOM:ManifestObtainer:Obtain', {
-        success: false,
-        result: cloneError(error),
-        msgId: aMsg.data.msgId
-      })
-    );
-});
+addMessageListener('DOM:ManifestObtainer:Obtain', async(function* (aMsg) {
+  const response = {
+    msgId: aMsg.data.msgId,
+    success: true,
+    result: undefined
+  };
+  try {
+    response.result = yield fetchManifest();
+  } catch (err) {
+    response.success = false;
+    response.result = cloneError(err);
+  }
+  sendAsyncMessage('DOM:ManifestObtainer:Obtain', response);
+}));
 
 function cloneError(aError) {
   const clone = {
     'fileName': String(aError.fileName),
     'lineNumber': String(aError.lineNumber),
     'columnNumber': String(aError.columnNumber),
     'stack': String(aError.stack),
     'message': String(aError.message),
     'name': String(aError.name)
   };
   return clone;
 }
 
 function fetchManifest() {
-  const manifestQuery = 'link[rel~="manifest"]';
-  return new Promise((resolve, reject) => {
+  return spawn(function* () {
     if (!content || content.top !== content) {
       let msg = 'Content window must be a top-level browsing context.';
-      return reject(new Error(msg));
+      throw new Error(msg);
     }
-    const elem = content.document.querySelector(manifestQuery);
+    const elem = content.document.querySelector('link[rel~="manifest"]');
     if (!elem || !elem.getAttribute('href')) {
       let msg = 'No manifest to fetch.';
-      return reject(new Error(msg));
+      throw new Error(msg);
     }
-    // Will throw on "about:blank" and possibly other invalid URIs.
+    // Throws on malformed URLs
     const manifestURL = new content.URL(elem.href, elem.baseURI);
+    if (!canLoadManifest(elem)) {
+      let msg = `Content Security Policy: The page's settings blocked the `;
+      msg += `loading of a resource at ${elem.href}`;
+      throw new Error(msg);
+    }
     const reqInit = {
       mode: 'cors'
     };
     if (elem.crossOrigin === 'use-credentials') {
       reqInit.credentials = 'include';
     }
     const req = new content.Request(manifestURL, reqInit);
     req.setContext('manifest');
-    content
-      .fetch(req)
-      .then(resp => processResponse(resp, content))
-      .then(resolve)
-      .catch(reject);
+    const response = yield content.fetch(req);
+    const manifest = yield processResponse(response, content);
+    return manifest;
   });
 }
 
+function canLoadManifest(aElem) {
+  const contentPolicy = Cc['@mozilla.org/layout/content-policy;1']
+    .getService(Ci.nsIContentPolicy);
+  const mimeType = aElem.type || 'application/manifest+json';
+  const elemURI = BrowserUtils.makeURI(
+    aElem.href, aElem.ownerDocument.characterSet
+  );
+  const shouldLoad = contentPolicy.shouldLoad(
+    Ci.nsIContentPolicy.TYPE_WEB_MANIFEST, elemURI,
+    aElem.ownerDocument.documentURIObject,
+    aElem, mimeType, null
+  );
+  return shouldLoad === Ci.nsIContentPolicy.ACCEPT;
+}
+
 function processResponse(aResp, aContentWindow) {
-  const manifestURL = aResp.url;
-  return new Promise((resolve, reject) => {
+  return spawn(function* () {
     const badStatus = aResp.status < 200 || aResp.status >= 300;
     if (aResp.type === 'error' || badStatus) {
       let msg =
         `Fetch error: ${aResp.status} - ${aResp.statusText} at ${aResp.url}`;
-      return reject(new Error(msg));
+      throw new Error(msg);
     }
-    aResp
-      .text()
-      .then((text) => {
-        const args = {
-          jsonText: text,
-          manifestURL: manifestURL,
-          docURL: aContentWindow.location.href
-        };
-        const processor = new ManifestProcessor();
-        const manifest = processor.process(args);
-        resolve(Cu.cloneInto(manifest, content));
-      }, reject);
+    const text = yield aResp.text();
+    const args = {
+      jsonText: text,
+      manifestURL: aResp.url,
+      docURL: aContentWindow.location.href
+    };
+    const processor = new ManifestProcessor();
+    const manifest = processor.process(args);
+    return Cu.cloneInto(manifest, content);
   });
 }
--- a/dom/manifest/ManifestObtainer.js
+++ b/dom/manifest/ManifestObtainer.js
@@ -69,17 +69,24 @@ ManifestObtainer.prototype = {
         reject: reject
       });
       mm.sendAsyncMessage(MSG_KEY, {
         msgId: msgId
       });
     });
 
     function toError(aErrorClone) {
-      const error = new Error();
+      let error;
+      switch (aErrorClone.name) {
+      case 'TypeError':
+        error = new TypeError();
+        break;
+      default:
+        error = new Error();
+      }
       Object.getOwnPropertyNames(aErrorClone)
         .forEach(name => error[name] = aErrorClone[name]);
       return error;
     }
   }
 };
 this.ManifestObtainer = ManifestObtainer; // jshint ignore:line
 this.EXPORTED_SYMBOLS = ['ManifestObtainer']; // jshint ignore:line
--- a/dom/manifest/test/browser_ManifestObtainer_obtain.js
+++ b/dom/manifest/test/browser_ManifestObtainer_obtain.js
@@ -104,16 +104,61 @@ const tests = [
       const CORS = 'Access-Control-Allow-Origin=http://not-here';
       const link =
         `<link
         crossorigin
         rel="manifest"
         href='${remoteURL}?${body}&${CORS}'>`;
       return link;
     }
+  },{
+    expected: 'Trying to load from about:whatever is a TypeError.',
+    get tabURL() {
+      let query = [
+        `body=<h1>${this.expected}</h1>`,
+        'Content-Type=text/html; charset=utf-8',
+      ];
+      const URL = `${defaultURL}?${query.join('&')}`;
+      return URL;
+    },
+    run(err) {
+      Assert.strictEqual(err.name, 'TypeError', this.expected);
+    },
+    testData: `<link rel="manifest" href='about:whatever'>`
+  },
+  {
+    expected: 'Trying to load from file://whatever is a TypeError.',
+    get tabURL() {
+      let query = [
+        `body=<h1>${this.expected}</h1>`,
+        'Content-Type=text/html; charset=utf-8',
+      ];
+      const URL = `${defaultURL}?${query.join('&')}`;
+      return URL;
+    },
+    run(err) {
+      Assert.strictEqual(err.name, 'TypeError', this.expected);
+    },
+    testData: `<link rel="manifest" href='file://manifest'>`
+  },
+  //URL parsing tests
+  {
+    expected: 'Trying to load invalid URL is a TypeError.',
+    get tabURL() {
+      let query = [
+        `body=<h1>${this.expected}</h1>`,
+        'Content-Type=text/html; charset=utf-8',
+      ];
+      const URL = `${defaultURL}?${query.join('&')}`;
+      return URL;
+    },
+    run(err) {
+      Assert.strictEqual(err.name, 'TypeError', this.expected);
+    },
+    testData: `<link rel="manifest" href='http://[12.1212.21.21.12.21.12]'>`
   },
 ];
 
 add_task(function*() {
   yield new Promise(resolve => {
     SpecialPowers.pushPrefEnv({
       'set': [
         ['dom.fetch.enabled', true]
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -267,26 +267,28 @@ private:
   nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
 };
 
 /**
  * Invoke the GetUserMediaDevices success callback. Wrapped in a runnable
  * so that it may be called on the main thread. The error callback is also
  * passed so it can be released correctly.
  */
-class DeviceSuccessCallbackRunnable: public nsRunnable
+class DeviceSuccessCallbackRunnable : public nsRunnable
 {
 public:
   DeviceSuccessCallbackRunnable(
     uint64_t aWindowID,
     nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback>& aOnSuccess,
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
-    nsTArray<nsRefPtr<MediaDevice>>* aDevices)
+    nsTArray<nsRefPtr<MediaDevice>>* aDevices,
+    bool aIsGum)
     : mDevices(aDevices)
     , mWindowID(aWindowID)
+    , mIsGum(aIsGum)
     , mManager(MediaManager::GetInstance())
   {
     mOnSuccess.swap(aOnSuccess);
     mOnFailure.swap(aOnFailure);
   }
 
   ~DeviceSuccessCallbackRunnable()
   {
@@ -353,58 +355,64 @@ public:
     if (!mManager->IsWindowStillActive(mWindowID)) {
       return NS_OK;
     }
 
     nsCOMPtr<nsIWritableVariant> devices =
       do_CreateInstance("@mozilla.org/variant;1");
 
     size_t len = mDevices->Length();
-    if (len == 0) {
-      // XXX
-      // We should in the future return an empty array, and dynamically add
-      // devices to the dropdowns if things are hotplugged while the
-      // requester is up.
-      nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
-      if (window) {
-        nsRefPtr<MediaStreamError> error = new MediaStreamError(window,
-            NS_LITERAL_STRING("NotFoundError"));
-        mOnFailure->OnError(error);
+
+    if (!len) {
+      if (mIsGum) { // gUM fails on 0 devices whereas enumerateDevices doesn't.
+        // XXX
+        // We should in the future return an empty array, and dynamically add
+        // devices to the dropdowns if things are hotplugged while the
+        // requester is up.
+        nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+        if (window) {
+          nsRefPtr<MediaStreamError> error = new MediaStreamError(window,
+              NS_LITERAL_STRING("NotFoundError"));
+          mOnFailure->OnError(error);
+        }
+        return NS_OK;
       }
-      return NS_OK;
+      devices->SetAsEmptyArray(); // SetAsArray() fails on zero length arrays.
+    } else {
+      nsTArray<nsIMediaDevice*> tmp(len);
+      for (auto& device : *mDevices) {
+        if (!mOriginKey.IsEmpty()) {
+          nsString id;
+          device->GetId(id);
+          AnonymizeId(id, mOriginKey);
+          device->SetId(id);
+        }
+        tmp.AppendElement(device);
+      }
+      nsresult rv = devices->SetAsArray(nsIDataType::VTYPE_INTERFACE,
+                                        &NS_GET_IID(nsIMediaDevice),
+                                        mDevices->Length(),
+                                        const_cast<void*>(
+                                          static_cast<const void*>(tmp.Elements())
+                                        ));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
     }
-
-    nsTArray<nsIMediaDevice*> tmp(len);
-    for (auto& device : *mDevices) {
-      if (!mOriginKey.IsEmpty()) {
-        nsString id;
-        device->GetId(id);
-        AnonymizeId(id, mOriginKey);
-        device->SetId(id);
-      }
-      tmp.AppendElement(device);
-    }
-
-    devices->SetAsArray(nsIDataType::VTYPE_INTERFACE,
-                        &NS_GET_IID(nsIMediaDevice),
-                        mDevices->Length(),
-                        const_cast<void*>(
-                          static_cast<const void*>(tmp.Elements())
-                        ));
-
     mOnSuccess->OnSuccess(devices);
     return NS_OK;
   }
 
   nsCString mOriginKey;
 private:
   nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess;
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
   nsAutoPtr<nsTArray<nsRefPtr<MediaDevice>>> mDevices;
   uint64_t mWindowID;
+  bool mIsGum;
   nsRefPtr<MediaManager> mManager;
 };
 
 // Handle removing GetUserMediaCallbackMediaStreamListener from main thread
 class GetUserMediaListenerRemove: public nsRunnable
 {
 public:
   GetUserMediaListenerRemove(uint64_t aWindowID,
@@ -1507,17 +1515,17 @@ public:
                  &MediaEngine::EnumerateAudioDevices, sources,
                  mLoopbackAudioDevice.get());
       for (auto& source : sources) {
         result->AppendElement(source);
       }
     }
     nsRefPtr<DeviceSuccessCallbackRunnable> runnable =
         new DeviceSuccessCallbackRunnable(mWindowId, mOnSuccess, mOnFailure,
-                                          result.forget());
+                                          result.forget(), mPrivileged);
     if (mPrivileged) {
       NS_DispatchToMainThread(runnable);
     } else {
       // Get persistent origin-unique uuid to anonymize deviceIds back on main.
       //
       // GetOriginKey is an async API that returns a pledge (as promise-like
       // pattern). We use .Then() to pass in a lambda to run back on this
       // thread once GetOriginKey resolves asynchronously . The "runnable"
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -398,32 +398,35 @@ GMPChild::RecvStartPlugin()
   }
 
   auto platformAPI = new GMPPlatformAPI();
   InitPlatformAPI(*platformAPI, this);
 
   mGMPLoader = GMPProcessChild::GetGMPLoader();
   if (!mGMPLoader) {
     NS_WARNING("Failed to get GMPLoader");
+    delete platformAPI;
     return false;
   }
 
 #if defined(MOZ_GMP_SANDBOX) && defined(XP_MACOSX)
   if (!SetMacSandboxInfo()) {
     NS_WARNING("Failed to set Mac GMP sandbox info");
+    delete platformAPI;
     return false;
   }
 #endif
 
   if (!mGMPLoader->Load(libPath.get(),
                         libPath.Length(),
                         &mNodeId[0],
                         mNodeId.size(),
                         platformAPI)) {
     NS_WARNING("Failed to load GMP");
+    delete platformAPI;
     return false;
   }
 
   void* sh = nullptr;
   GMPAsyncShutdownHost* host = static_cast<GMPAsyncShutdownHost*>(this);
   GMPErr err = GetAPI(GMP_API_ASYNC_SHUTDOWN, host, &sh);
   if (err == GMPNoErr && sh) {
     mAsyncShutdown = reinterpret_cast<GMPAsyncShutdown*>(sh);
--- a/dom/media/gstreamer/GStreamerReader.cpp
+++ b/dom/media/gstreamer/GStreamerReader.cpp
@@ -219,20 +219,24 @@ GStreamerReader::Error(GstBus *aBus, Gst
 
   return GST_BUS_PASS;
 }
 
 void GStreamerReader::ElementAddedCb(GstBin *aPlayBin,
                                      GstElement *aElement,
                                      gpointer aUserData)
 {
-  const gchar *name =
-    gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(gst_element_get_factory(aElement)));
+  GstElementFactory *factory = gst_element_get_factory(aElement);
 
-  if (!strcmp(name, "uridecodebin")) {
+  if (!factory)
+    return;
+
+  const gchar *name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
+
+  if (name && !strcmp(name, "uridecodebin")) {
     g_signal_connect(G_OBJECT(aElement), "autoplug-sort",
                      G_CALLBACK(GStreamerReader::ElementFilterCb), aUserData);
   }
 }
 
 GValueArray *GStreamerReader::ElementFilterCb(GstURIDecodeBin *aBin,
                                               GstPad *aPad,
                                               GstCaps *aCaps,
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -55,16 +55,19 @@ const kUDP_WAKEUP_WS_STATUS_CODE = 4774;
                                           // by server to signal that it can
                                           // wake client up using UDP.
 
 const kCHILD_PROCESS_MESSAGES = ["Push:Register", "Push:Unregister",
                                  "Push:Registration"];
 
 const kWS_MAX_WENTDOWN = 2;
 
+// 1 minute is the least allowed ping interval
+const kWS_MIN_PING_INTERVAL = 60000;
+
 // This is a singleton
 this.PushDB = function PushDB() {
   debug("PushDB()");
 
   // set the indexeddb database
   this.initDBHelper(kPUSHDB_DB_NAME, kPUSHDB_DB_VERSION,
                     [kPUSHDB_STORE_NAME]);
 };
@@ -798,17 +801,21 @@ this.PushService = {
     if (!this._recalculatePing && wsWentDown) {
       debug('Websocket disconnected without ping adaptative algorithm running');
       this._wsWentDownCounter++;
       if (this._wsWentDownCounter > kWS_MAX_WENTDOWN) {
         debug('Too many disconnects. Reenabling ping adaptative algoritm');
         this._wsWentDownCounter = 0;
         this._recalculatePing = true;
         this._lastGoodPingInterval = Math.floor(lastTriedPingInterval / 2);
-        nextPingInterval = this._lastGoodPingInterval;
+        if (this._lastGoodPingInterval < kWS_MIN_PING_INTERVAL) {
+          nextPingInterval = kWS_MIN_PING_INTERVAL;
+        } else {
+          nextPingInterval = this._lastGoodPingInterval;
+        }
         prefs.set('pingInterval', nextPingInterval);
         this._save(ns, nextPingInterval);
         return;
       }
 
       debug('We do not need to recalculate the ping, based on previous data');
     }
 
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -144,16 +144,19 @@ CSP_ContentTypeToDirective(nsContentPoli
       return nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE;
 
     case nsIContentPolicy::TYPE_FONT:
       return nsIContentSecurityPolicy::FONT_SRC_DIRECTIVE;
 
     case nsIContentPolicy::TYPE_MEDIA:
       return nsIContentSecurityPolicy::MEDIA_SRC_DIRECTIVE;
 
+    case nsIContentPolicy::TYPE_WEB_MANIFEST:
+      return nsIContentSecurityPolicy::WEB_MANIFEST_SRC_DIRECTIVE;
+
     case nsIContentPolicy::TYPE_SUBDOCUMENT:
       return nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE;
 
     case nsIContentPolicy::TYPE_WEBSOCKET:
     case nsIContentPolicy::TYPE_XMLHTTPREQUEST:
     case nsIContentPolicy::TYPE_BEACON:
     case nsIContentPolicy::TYPE_FETCH:
       return nsIContentSecurityPolicy::CONNECT_SRC_DIRECTIVE;
@@ -831,16 +834,20 @@ nsCSPDirective::toDomCSPStruct(mozilla::
       outCSP.mReport_uri.Value() = srcs;
       return;
 
     case nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE:
       outCSP.mFrame_ancestors.Construct();
       outCSP.mFrame_ancestors.Value() = srcs;
       return;
 
+    case nsIContentSecurityPolicy::WEB_MANIFEST_SRC_DIRECTIVE:
+      outCSP.mManifest_src.Construct();
+      outCSP.mManifest_src.Value() = srcs;
+      return;
     // not supporting REFLECTED_XSS_DIRECTIVE
 
     case nsIContentSecurityPolicy::BASE_URI_DIRECTIVE:
       outCSP.mBase_uri.Construct();
       outCSP.mBase_uri.Value() = srcs;
       return;
 
     case nsIContentSecurityPolicy::FORM_ACTION_DIRECTIVE:
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -59,35 +59,39 @@ void CSP_LogMessage(const nsAString& aMe
 #define EVAL_VIOLATION_OBSERVER_TOPIC           "violated base restriction: Code will not be created from strings"
 #define SCRIPT_NONCE_VIOLATION_OBSERVER_TOPIC   "Inline Script had invalid nonce"
 #define STYLE_NONCE_VIOLATION_OBSERVER_TOPIC    "Inline Style had invalid nonce"
 #define SCRIPT_HASH_VIOLATION_OBSERVER_TOPIC    "Inline Script had invalid hash"
 #define STYLE_HASH_VIOLATION_OBSERVER_TOPIC     "Inline Style had invalid hash"
 
 // these strings map to the CSPDirectives in nsIContentSecurityPolicy
 // NOTE: When implementing a new directive, you will need to add it here but also
-// add a corresponding entry to the constants in nsIContentSecurityPolicy.idl and
-// also create an entry for the new directive in nsCSPDirective::toDomCSPStruct().
+// add a corresponding entry to the constants in nsIContentSecurityPolicy.idl
+// and also create an entry for the new directive in
+// nsCSPDirective::toDomCSPStruct() and add it to CSPDictionaries.webidl.
+// Order of elements below important! Make sure it matches the order as in
+// nsIContentSecurityPolicy.idl
 static const char* CSPStrDirectives[] = {
   "-error-",    // NO_DIRECTIVE
   "default-src",     // DEFAULT_SRC_DIRECTIVE
   "script-src",      // SCRIPT_SRC_DIRECTIVE
   "object-src",      // OBJECT_SRC_DIRECTIVE
   "style-src",       // STYLE_SRC_DIRECTIVE
   "img-src",         // IMG_SRC_DIRECTIVE
   "media-src",       // MEDIA_SRC_DIRECTIVE
   "frame-src",       // FRAME_SRC_DIRECTIVE
   "font-src",        // FONT_SRC_DIRECTIVE
   "connect-src",     // CONNECT_SRC_DIRECTIVE
   "report-uri",      // REPORT_URI_DIRECTIVE
   "frame-ancestors", // FRAME_ANCESTORS_DIRECTIVE
   "reflected-xss",   // REFLECTED_XSS_DIRECTIVE
   "base-uri",        // BASE_URI_DIRECTIVE
   "form-action",     // FORM_ACTION_DIRECTIVE
-  "referrer"         // REFERRER_DIRECTIVE
+  "referrer",        // REFERRER_DIRECTIVE
+  "manifest-src"     // MANIFEST_SRC_DIRECTIVE
 };
 
 inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)
 {
   return CSPStrDirectives[static_cast<uint32_t>(aDir)];
 }
 
 inline CSPDirective CSP_StringToCSPDirective(const nsAString& aDir)
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -434,16 +434,17 @@ nsMixedContentBlocker::ShouldLoad(bool a
     case TYPE_CSP_REPORT:
     case TYPE_DTD:
     case TYPE_FETCH:
     case TYPE_FONT:
     case TYPE_OBJECT:
     case TYPE_SCRIPT:
     case TYPE_STYLESHEET:
     case TYPE_SUBDOCUMENT:
+    case TYPE_WEB_MANIFEST:
     case TYPE_XBL:
     case TYPE_XMLHTTPREQUEST:
     case TYPE_XSLT:
     case TYPE_OTHER:
       break;
 
 
     // This content policy works as a whitelist.
--- a/dom/webidl/CSPDictionaries.webidl
+++ b/dom/webidl/CSPDictionaries.webidl
@@ -19,13 +19,14 @@ dictionary CSP {
   sequence<DOMString> font-src;
   sequence<DOMString> connect-src;
   sequence<DOMString> report-uri;
   sequence<DOMString> frame-ancestors;
   // sequence<DOMString> reflected-xss; // not suppored in Firefox
   sequence<DOMString> base-uri;
   sequence<DOMString> form-action;
   sequence<DOMString> referrer;
+  sequence<DOMString> manifest-src;
 };
 
 dictionary CSPPolicies {
   sequence<CSP> csp-policies;
 };
--- a/dom/webidl/Selection.webidl
+++ b/dom/webidl/Selection.webidl
@@ -61,16 +61,19 @@ partial interface Selection {
   [ChromeOnly]
   const short ENDOFPRECEDINGLINE = 0;
   [ChromeOnly]
   const short STARTOFNEXTLINE = 1;
 
   [ChromeOnly,Throws]
   attribute boolean interlinePosition;
 
+  [Throws]
+  attribute short? caretBidiLevel;
+
   [ChromeOnly,Throws]
   DOMString  toStringWithFormat(DOMString formatType, unsigned long flags, long wrapColumn);
   [ChromeOnly,Throws]
   void  addSelectionListener(nsISelectionListener newListener);
   [ChromeOnly,Throws]
   void  removeSelectionListener(nsISelectionListener listenerToRemove);
 
   [ChromeOnly]
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -1044,31 +1044,32 @@ ContinueInstallTask::ContinueAfterWorker
 NS_IMETHODIMP
 ServiceWorkerManager::Register(nsIDOMWindow* aWindow,
                                nsIURI* aScopeURI,
                                nsIURI* aScriptURI,
                                nsISupports** aPromise)
 {
   AssertIsOnMainThread();
 
-  // XXXnsm Don't allow chrome callers for now, we don't support chrome
-  // ServiceWorkers.
-  MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
-
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
-
-  nsCOMPtr<nsPIDOMWindow> outerWindow = window->GetOuterWindow();
-  bool serviceWorkersTestingEnabled =
-    outerWindow->GetServiceWorkersTestingEnabled();
+  MOZ_ASSERT(window);
 
   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
   if (!doc) {
     return NS_ERROR_FAILURE;
   }
 
+  // Don't allow service workers to register when the *document* is chrome for
+  // now.
+  MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
+
+  nsCOMPtr<nsPIDOMWindow> outerWindow = window->GetOuterWindow();
+  bool serviceWorkersTestingEnabled =
+    outerWindow->GetServiceWorkersTestingEnabled();
+
   nsCOMPtr<nsIURI> documentURI = doc->GetBaseURI();
 
   bool authenticatedOrigin = false;
   if (Preferences::GetBool("dom.serviceWorkers.testing.enabled") ||
       serviceWorkersTestingEnabled) {
     authenticatedOrigin = true;
   }
 
@@ -1469,25 +1470,28 @@ public:
 // automatically reject the Promise.
 NS_IMETHODIMP
 ServiceWorkerManager::GetRegistrations(nsIDOMWindow* aWindow,
                                        nsISupports** aPromise)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
-  // XXXnsm Don't allow chrome callers for now, we don't support chrome
-  // ServiceWorkers.
-  MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
-
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
-  if (!window) {
+  MOZ_ASSERT(window);
+
+  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
+  if (!doc) {
     return NS_ERROR_FAILURE;
   }
 
+  // Don't allow service workers to register when the *document* is chrome for
+  // now.
+  MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
+
   nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);
   ErrorResult result;
   nsRefPtr<Promise> promise = Promise::Create(sgo, result);
   if (result.Failed()) {
     return result.StealNSResult();
   }
 
   nsCOMPtr<nsIRunnable> runnable =
@@ -1570,25 +1574,28 @@ public:
 NS_IMETHODIMP
 ServiceWorkerManager::GetRegistration(nsIDOMWindow* aWindow,
                                       const nsAString& aDocumentURL,
                                       nsISupports** aPromise)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
-  // XXXnsm Don't allow chrome callers for now, we don't support chrome
-  // ServiceWorkers.
-  MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
-
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
-  if (!window) {
+  MOZ_ASSERT(window);
+
+  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
+  if (!doc) {
     return NS_ERROR_FAILURE;
   }
 
+  // Don't allow service workers to register when the *document* is chrome for
+  // now.
+  MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
+
   nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);
   ErrorResult result;
   nsRefPtr<Promise> promise = Promise::Create(sgo, result);
   if (result.Failed()) {
     return result.StealNSResult();
   }
 
   nsCOMPtr<nsIRunnable> runnable =
@@ -1779,25 +1786,28 @@ ServiceWorkerManager::SendPushSubscripti
 
 NS_IMETHODIMP
 ServiceWorkerManager::GetReadyPromise(nsIDOMWindow* aWindow,
                                       nsISupports** aPromise)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
-  // XXXnsm Don't allow chrome callers for now, we don't support chrome
-  // ServiceWorkers.
-  MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
-
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
-  if (!window) {
+  MOZ_ASSERT(window);
+
+  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
+  if (!doc) {
     return NS_ERROR_FAILURE;
   }
 
+  // Don't allow service workers to register when the *document* is chrome for
+  // now.
+  MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
+
   MOZ_ASSERT(!mPendingReadyPromises.Contains(window));
 
   nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);
   ErrorResult result;
   nsRefPtr<Promise> promise = Promise::Create(sgo, result);
   if (result.Failed()) {
     return result.StealNSResult();
   }
--- a/editor/libeditor/nsHTMLEditRules.cpp
+++ b/editor/libeditor/nsHTMLEditRules.cpp
@@ -609,21 +609,23 @@ nsHTMLEditRules::WillDoAction(Selection*
       *aCancel = true;
       return NS_OK;
     }
   }
 
   switch (info->action) {
     case EditAction::insertText:
     case EditAction::insertIMEText:
+      UndefineCaretBidiLevel(aSelection);
       return WillInsertText(info->action, aSelection, aCancel, aHandled,
                             info->inString, info->outString, info->maxLength);
     case EditAction::loadHTML:
       return WillLoadHTML(aSelection, aCancel);
     case EditAction::insertBreak:
+      UndefineCaretBidiLevel(aSelection);
       return WillInsertBreak(aSelection, aCancel, aHandled);
     case EditAction::deleteSelection:
       return WillDeleteSelection(aSelection, info->collapsedAction,
                                  info->stripWrappers, aCancel, aHandled);
     case EditAction::makeList:
       return WillMakeList(aSelection, info->blockType, info->entireList,
                           info->bulletType, aCancel, aHandled);
     case EditAction::indent:
--- a/editor/libeditor/nsTextEditRules.cpp
+++ b/editor/libeditor/nsTextEditRules.cpp
@@ -247,19 +247,21 @@ nsTextEditRules::WillDoAction(Selection*
   *aCancel = false;
   *aHandled = false;
 
   // my kingdom for dynamic cast
   nsTextRulesInfo *info = static_cast<nsTextRulesInfo*>(aInfo);
 
   switch (info->action) {
     case EditAction::insertBreak:
+      UndefineCaretBidiLevel(aSelection);
       return WillInsertBreak(aSelection, aCancel, aHandled, info->maxLength);
     case EditAction::insertText:
     case EditAction::insertIMEText:
+      UndefineCaretBidiLevel(aSelection);
       return WillInsertText(info->action, aSelection, aCancel, aHandled,
                             info->inString, info->outString, info->maxLength);
     case EditAction::deleteSelection:
       return WillDeleteSelection(aSelection, info->collapsedAction,
                                  aCancel, aHandled);
     case EditAction::undo:
       return WillUndo(aSelection, aCancel, aHandled);
     case EditAction::redo:
--- a/editor/libeditor/nsTextEditRules.h
+++ b/editor/libeditor/nsTextEditRules.h
@@ -188,16 +188,18 @@ protected:
                                      bool                     *aTruncated);
 
   /** Remove IME composition text from password buffer */
   void RemoveIMETextFromPWBuf(int32_t &aStart, nsAString *aIMEString);
 
   nsresult CreateMozBR(nsIDOMNode* inParent, int32_t inOffset,
                        nsIDOMNode** outBRNode = nullptr);
 
+  void UndefineCaretBidiLevel(Selection* aSelection);
+
   nsresult CheckBidiLevelForDeletion(mozilla::dom::Selection* aSelection,
                                      nsIDOMNode           *aSelNode,
                                      int32_t               aSelOffset,
                                      nsIEditor::EDirection aAction,
                                      bool                 *aCancel);
 
   nsresult HideLastPWInput();
 
--- a/editor/libeditor/nsTextEditRulesBidi.cpp
+++ b/editor/libeditor/nsTextEditRulesBidi.cpp
@@ -75,8 +75,24 @@ nsTextEditRules::CheckBidiLevelForDeleti
 
     // Set the bidi level of the caret to that of the
     // character that will be (or would have been) deleted
     frameSelection->SetCaretBidiLevel(levelOfDeletion);
   }
   return NS_OK;
 }
 
+void
+nsTextEditRules::UndefineCaretBidiLevel(Selection* aSelection)
+{
+  /**
+   * After inserting text the caret Bidi level must be set to the level of the
+   * inserted text.This is difficult, because we cannot know what the level is
+   * until after the Bidi algorithm is applied to the whole paragraph.
+   *
+   * So we set the caret Bidi level to UNDEFINED here, and the caret code will
+   * set it correctly later
+   */
+  nsRefPtr<nsFrameSelection> frameSelection = aSelection->GetFrameSelection();
+  if (frameSelection) {
+    frameSelection->UndefineCaretBidiLevel();
+  }
+}
--- a/extensions/permissions/nsContentBlocker.cpp
+++ b/extensions/permissions/nsContentBlocker.cpp
@@ -34,17 +34,21 @@ static const char *kTypeString[] = {"oth
                                     "ping",
                                     "xmlhttprequest",
                                     "objectsubrequest",
                                     "dtd",
                                     "font",
                                     "media",
                                     "websocket",
                                     "csp_report",
-                                    "xslt"};
+                                    "xslt",
+                                    "beacon",
+                                    "fetch",
+                                    "imageset",
+                                    "manifest"};
 
 #define NUMBER_OF_TYPES MOZ_ARRAY_LENGTH(kTypeString)
 uint8_t nsContentBlocker::mBehaviorPref[NUMBER_OF_TYPES];
 
 NS_IMPL_ISUPPORTS(nsContentBlocker, 
                   nsIContentPolicy,
                   nsIObserver,
                   nsISupportsWeakReference)
--- a/gfx/2d/FilterNodeD2D1.cpp
+++ b/gfx/2d/FilterNodeD2D1.cpp
@@ -544,18 +544,18 @@ FilterNodeD2D1::Create(ID2D1DeviceContex
     return MakeAndAddRef<FilterNodeConvolveD2D1>(aDC);
   }
 
   RefPtr<ID2D1Effect> effect;
   HRESULT hr;
 
   hr = aDC->CreateEffect(GetCLDIDForFilterType(aType), byRef(effect));
 
-  if (FAILED(hr)) {
-    gfxWarning() << "Failed to create effect for FilterType: " << hexa(hr);
+  if (FAILED(hr) || !effect) {
+    gfxCriticalErrorOnce() << "Failed to create effect for FilterType: " << hexa(hr);
     return nullptr;
   }
 
   RefPtr<FilterNodeD2D1> filter = new FilterNodeD2D1(effect, aType);
 
   if (IsTransferFilterType(aType) || aType == FilterType::COLOR_MATRIX) {
     // These filters can produce non-transparent output from transparent
     // input pixels, and we want them to have an unbounded output region.
--- a/gfx/2d/Matrix.cpp
+++ b/gfx/2d/Matrix.cpp
@@ -222,16 +222,91 @@ Rect Matrix4x4::ProjectRectBounds(const 
 
   if (max_x < min_x || max_y < min_y) {
     return Rect(0, 0, 0, 0);
   }
 
   return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
 }
 
+size_t
+Matrix4x4::TransformAndClipRect(const Rect& aRect, const Rect& aClip,
+                                Point* aVerts) const
+{
+  // Initialize a double-buffered array of points in homogenous space with
+  // the input rectangle, aRect.
+  Point4D points[2][kTransformAndClipRectMaxVerts];
+  Point4D* dstPoint = points[0];
+  *dstPoint++ = *this * Point4D(aRect.x, aRect.y, 0, 1);
+  *dstPoint++ = *this * Point4D(aRect.XMost(), aRect.y, 0, 1);
+  *dstPoint++ = *this * Point4D(aRect.XMost(), aRect.YMost(), 0, 1);
+  *dstPoint++ = *this * Point4D(aRect.x, aRect.YMost(), 0, 1);
+
+  // View frustum clipping planes are described as normals originating from
+  // the 0,0,0,0 origin.
+  Point4D planeNormals[4];
+  planeNormals[0] = Point4D(1.0, 0.0, 0.0, -aClip.x);
+  planeNormals[1] = Point4D(-1.0, 0.0, 0.0, aClip.XMost());
+  planeNormals[2] = Point4D(0.0, 1.0, 0.0, -aClip.y);
+  planeNormals[3] = Point4D(0.0, -1.0, 0.0, aClip.YMost());
+
+  // Iterate through each clipping plane and clip the polygon.
+  // In each pass, we double buffer, alternating between points[0] and
+  // points[1].
+  for (int plane=0; plane < 4; plane++) {
+    planeNormals[plane].Normalize();
+
+    Point4D* srcPoint = points[plane & 1];
+    Point4D* srcPointEnd = dstPoint;
+    dstPoint = points[~plane & 1];
+
+    Point4D* prevPoint = srcPointEnd - 1;
+    float prevDot = planeNormals[plane].DotProduct(*prevPoint);
+    while (srcPoint < srcPointEnd) {
+      float nextDot = planeNormals[plane].DotProduct(*srcPoint);
+
+      if ((nextDot >= 0.0) != (prevDot >= 0.0)) {
+        // An intersection with the clipping plane has been detected.
+        // Interpolate to find the intersecting point and emit it.
+        float t = -prevDot / (nextDot - prevDot);
+        *dstPoint++ = *srcPoint * t + *prevPoint * (1.0 - t);
+      }
+
+      if (nextDot >= 0.0) {
+        // Emit any source points that are on the positive side of the
+        // clipping plane.
+        *dstPoint++ = *srcPoint;
+      }
+
+      prevPoint = srcPoint++;
+      prevDot = nextDot;
+    }
+  }
+
+  size_t dstPointCount = 0;
+  size_t srcPointCount = dstPoint - points[0];
+  for (Point4D* srcPoint = points[0]; srcPoint < points[0] + srcPointCount; srcPoint++) {
+
+    Point p;
+    if (srcPoint->w == 0.0) {
+      // If a point lies on the intersection of the clipping planes at
+      // (0,0,0,0), we must avoid a division by zero w component.
+      p = Point(0.0, 0.0);
+    } else {
+      p = srcPoint->As2DPoint();
+    }
+    // Emit only unique points
+    if (dstPointCount == 0 || p != aVerts[dstPointCount - 1]) {
+      aVerts[dstPointCount++] = p;
+    }
+  }
+
+  return dstPointCount;
+}
+
 bool
 Matrix4x4::Invert()
 {
   Float det = Determinant();
   if (!det) {
     return false;
   }
 
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -494,16 +494,29 @@ public:
     float z = -(aPoint.x * _13 + aPoint.y * _23 + _43) / _33;
 
     // Compute the transformed point
     return *this * Point4D(aPoint.x, aPoint.y, z, 1);
   }
 
   Rect ProjectRectBounds(const Rect& aRect, const Rect &aClip) const;
 
+  /**
+   * TransformAndClipRect projects a rectangle and clips against view frustum
+   * clipping planes in homogenous space so that its projected vertices are
+   * constrained within the 2d rectangle passed in aClip.
+   * The resulting vertices are populated in aVerts.  aVerts must be
+   * pre-allocated to hold at least kTransformAndClipRectMaxVerts Points.
+   * The vertex count is returned by TransformAndClipRect.  It is possible to
+   * emit fewer that 3 vertices, indicating that aRect will not be visible
+   * within aClip.
+   */
+  size_t TransformAndClipRect(const Rect& aRect, const Rect& aClip, Point* aVerts) const;
+  static const size_t kTransformAndClipRectMaxVerts = 32;
+
   static Matrix4x4 From2D(const Matrix &aMatrix) {
     Matrix4x4 matrix;
     matrix._11 = aMatrix._11;
     matrix._12 = aMatrix._12;
     matrix._21 = aMatrix._21;
     matrix._22 = aMatrix._22;
     matrix._41 = aMatrix._31;
     matrix._42 = aMatrix._32;
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -292,20 +292,34 @@ public:
    */
   virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) = 0;
 
   /**
    * Tell the compositor to draw a quad. What to do draw and how it is
    * drawn is specified by aEffectChain. aRect is the quad to draw, in user space.
    * aTransform transforms from user space to screen space. If texture coords are
    * required, these will be in the primary effect in the effect chain.
+   * aVisibleRect is used to determine which edges should be antialiased,
+   * without applying the effect to the inner edges of a tiled layer.
    */
   virtual void DrawQuad(const gfx::Rect& aRect, const gfx::Rect& aClipRect,
                         const EffectChain& aEffectChain,
-                        gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform) = 0;
+                        gfx::Float aOpacity, const gfx::Matrix4x4& aTransform,
+                        const gfx::Rect& aVisibleRect) = 0;
+
+  /**
+   * Overload of DrawQuad, with aVisibleRect defaulted to the value of aRect.
+   * Use this when you are drawing a single quad that is not part of a tiled
+   * layer.
+   */
+  void DrawQuad(const gfx::Rect& aRect, const gfx::Rect& aClipRect,
+                        const EffectChain& aEffectChain,
+                        gfx::Float aOpacity, const gfx::Matrix4x4& aTransform) {
+      DrawQuad(aRect, aClipRect, aEffectChain, aOpacity, aTransform, aRect);
+  }
 
   /*
    * Clear aRect on current render target.
    */
   virtual void ClearRect(const gfx::Rect& aRect) = 0;
 
   /**
    * Start a new frame.
--- a/gfx/layers/LayerScope.cpp
+++ b/gfx/layers/LayerScope.cpp
@@ -173,47 +173,151 @@ public:
     void DispatchDebugData();
 private:
     nsTArray<nsRefPtr<LayerScopeWebSocketHandler> > mHandlers;
     nsCOMPtr<nsIThread> mDebugSenderThread;
     nsRefPtr<DebugDataSender> mCurrentSender;
     nsCOMPtr<nsIServerSocket> mServerSocket;
 };
 
-// Static class to create and destory LayerScopeWebSocketManager object
-class WebSocketHelper
-{
+class DrawSession {
 public:
-    static void CreateServerSocket()
-    {
-        // Create Web Server Socket (which has to be on the main thread)
-        MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-        if (!sWebSocketManager) {
-            sWebSocketManager = new LayerScopeWebSocketManager();
+    DrawSession()
+      : mOffsetX(0.0)
+      , mOffsetY(0.0)
+      , mRects(0)
+    { }
+
+    float mOffsetX;
+    float mOffsetY;
+    gfx::Matrix4x4 mMVMatrix;
+    size_t mRects;
+    gfx::Rect mLayerRects[4];
+};
+
+class ContentMonitor {
+public:
+    using THArray = nsTArray<const TextureHost *>;
+
+    // Notify the content of a TextureHost was changed.
+    void SetChangedHost(const TextureHost* host) {
+        if (THArray::NoIndex == mChangedHosts.IndexOf(host)) {
+            mChangedHosts.AppendElement(host);
+        }
+    }
+
+    // Clear changed flag of a host.
+    void ClearChangedHost(const TextureHost* host) {
+        if (THArray::NoIndex != mChangedHosts.IndexOf(host)) {
+          mChangedHosts.RemoveElement(host);
         }
     }
 
-    static void DestroyServerSocket()
+    // Return true iff host is a new one or the content of it had been changed.
+    bool IsChangedOrNew(const TextureHost* host) {
+        if (THArray::NoIndex == mSeenHosts.IndexOf(host)) {
+            mSeenHosts.AppendElement(host);
+            return true;
+        }
+
+        if (decltype(mChangedHosts)::NoIndex != mChangedHosts.IndexOf(host)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    void Empty() {
+        mSeenHosts.SetLength(0);
+        mChangedHosts.SetLength(0);
+    }
+private:
+    THArray mSeenHosts;
+    THArray mChangedHosts;
+};
+
+// Hold all singleton objects used by LayerScope
+class LayerScopeManager
+{
+public:
+    void CreateServerSocket()
     {
-        // Destroy Web Server Socket
-        if (sWebSocketManager) {
-            sWebSocketManager->RemoveAllConnections();
+        //  WebSocketManager must be created on the main thread.
+        if (NS_IsMainThread()) {
+            mWebSocketManager = mozilla::MakeUnique<LayerScopeWebSocketManager>();
+        } else {
+            // Dispatch creation to main thread, and make sure we
+            // dispatch this only once after booting
+            static bool dispatched = false;
+            if (dispatched) {
+                return;
+            }
+
+            DebugOnly<nsresult> rv =
+              NS_DispatchToMainThread(new CreateServerSocketRunnable(this));
+            MOZ_ASSERT(NS_SUCCEEDED(rv),
+                  "Failed to dispatch WebSocket Creation to main thread");
+            dispatched = true;
         }
     }
 
-    static LayerScopeWebSocketManager* GetSocketManager()
+    void DestroyServerSocket()
+    {
+        // Destroy Web Server Socket
+        if (mWebSocketManager) {
+            mWebSocketManager->RemoveAllConnections();
+        }
+    }
+
+    LayerScopeWebSocketManager* GetSocketManager()
     {
-        return sWebSocketManager;
+        return mWebSocketManager.get();
+    }
+
+    ContentMonitor* GetContentMonitor()
+    {
+        if (!mContentMonitor.get()) {
+            mContentMonitor = mozilla::MakeUnique<ContentMonitor>();
+        }
+
+        return mContentMonitor.get();
+    }
+
+    void NewDrawSession() {
+        mSession = mozilla::MakeUnique<DrawSession>();
+    }
+
+    DrawSession& CurrentSession() {
+        return *mSession;
     }
 
 private:
-    static StaticAutoPtr<LayerScopeWebSocketManager> sWebSocketManager;
+    friend class CreateServerSocketRunnable;
+    class CreateServerSocketRunnable : public nsRunnable
+    {
+    public:
+        explicit CreateServerSocketRunnable(LayerScopeManager *aLayerScopeManager)
+            : mLayerScopeManager(aLayerScopeManager)
+        {
+        }
+        NS_IMETHOD Run() {
+            mLayerScopeManager->mWebSocketManager =
+                mozilla::MakeUnique<LayerScopeWebSocketManager>();
+            return NS_OK;
+        }
+    private:
+        LayerScopeManager* mLayerScopeManager;
+    };
+
+    mozilla::UniquePtr<LayerScopeWebSocketManager> mWebSocketManager;
+    mozilla::UniquePtr<DrawSession> mSession;
+    mozilla::UniquePtr<ContentMonitor> mContentMonitor;
 };
 
-StaticAutoPtr<LayerScopeWebSocketManager> WebSocketHelper::sWebSocketManager;
+LayerScopeManager gLayerScopeManager;
 
 /*
  * DebugGLData is the base class of
  * 1. DebugGLFrameStatusData (Frame start/end packet)
  * 2. DebugGLColorData (Color data packet)
  * 3. DebugGLTextureData (Texture data packet)
  * 4. DebugGLLayersData (Layers Tree data packet)
  * 5. DebugGLMetaData (Meta data packet)
@@ -225,23 +329,23 @@ public:
     { }
 
     virtual ~DebugGLData() { }
 
     virtual bool Write() = 0;
 
 protected:
     static bool WriteToStream(Packet& aPacket) {
-        if (!WebSocketHelper::GetSocketManager())
+        if (!gLayerScopeManager.GetSocketManager())
             return true;
 
         uint32_t size = aPacket.ByteSize();
         auto data = MakeUnique<uint8_t[]>(size);
         aPacket.SerializeToArray(data.get(), size);
-        return WebSocketHelper::GetSocketManager()->WriteAll(data.get(), size);
+        return gLayerScopeManager.GetSocketManager()->WriteAll(data.get(), size);
     }
 
     Packet::DataType mDataType;
 };
 
 class DebugGLFrameStatusData final: public DebugGLData
 {
 public:
@@ -285,66 +389,74 @@ public:
           mState(aState)
     {
     }
 
     virtual bool Write() override {
         return WriteToStream(mPacket);
     }
 
-    bool TryPack() {
+    bool TryPack(bool packData) {
         android::sp<android::GraphicBuffer> buffer = mState.mSurface;
         MOZ_ASSERT(buffer.get());
 
         mPacket.set_type(mDataType);
         TexturePacket* tp = mPacket.mutable_texture();
         tp->set_layerref(mLayerRef);
         tp->set_name(mName);
         tp->set_target(mTarget);
 
-        int format = buffer->getPixelFormat();
-        if (HAL_PIXEL_FORMAT_RGBA_8888 != format &&
-            HAL_PIXEL_FORMAT_RGBX_8888 != format) {
-            return false;
-        }
-
-        uint8_t* grallocData;
-        if (BAD_VALUE == buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN |
-                                       GRALLOC_USAGE_SW_WRITE_NEVER,
-                                       reinterpret_cast<void**>(&grallocData))) {
+        int pFormat = buffer->getPixelFormat();
+        if (HAL_PIXEL_FORMAT_RGBA_8888 != pFormat &&
+            HAL_PIXEL_FORMAT_RGBX_8888 != pFormat) {
             return false;
         }
 
         int32_t stride = buffer->getStride() * 4;
         int32_t height = buffer->getHeight();
         int32_t width = buffer->getWidth();
         int32_t sourceSize = stride * height;
-        bool    ret = false;
+        if (sourceSize <= 0) {
+            return false;
+        }
+
+        uint32_t dFormat = mState.FormatRBSwapped() ?
+                           LOCAL_GL_BGRA : LOCAL_GL_RGBA;
+        tp->set_dataformat(dFormat);
+        tp->set_dataformat((1 << 16 | tp->dataformat()));
+        tp->set_width(width);
+        tp->set_height(height);
+        tp->set_stride(stride);
 
-        if (sourceSize > 0) {
-            auto compressedData = MakeUnique<char[]>(LZ4::maxCompressedSize(sourceSize));
+        if (packData) {
+            uint8_t* grallocData = nullptr;
+            if (BAD_VALUE == buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN |
+                                           GRALLOC_USAGE_SW_WRITE_NEVER,
+                                           reinterpret_cast<void**>(&grallocData)))
+            {
+                return false;
+            }
+            // Do not return before buffer->unlock();
+            auto compressedData =
+                 MakeUnique<char[]>(LZ4::maxCompressedSize(sourceSize));
             int compressedSize = LZ4::compress((char*)grallocData,
                                                sourceSize,
                                                compressedData.get());
 
             if (compressedSize > 0) {
-                uint32_t format = mState.FormatRBSwapped() ?
-                  LOCAL_GL_BGRA : LOCAL_GL_RGBA;
-                tp->set_dataformat(format);
-                tp->set_dataformat((1 << 16 | tp->dataformat()));
-                tp->set_width(width);
-                tp->set_height(height);
-                tp->set_stride(stride);
                 tp->set_data(compressedData.get(), compressedSize);
-                ret = true;
-            }
+            } else {
+                buffer->unlock();
+                return false;
+             }
+
+            buffer->unlock();
         }
 
-        buffer->unlock();
-        return ret;
+        return true;
     }
 
 private:
     uint64_t mLayerRef;
     GLenum mTarget;
     GLuint mName;
     const LayerRenderState &mState;
     Packet mPacket;
@@ -571,21 +683,22 @@ public:
 
     DebugListener() { }
 
     /* nsIServerSocketListener */
 
     NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ,
                                    nsISocketTransport *aTransport) override
     {
-        if (!WebSocketHelper::GetSocketManager())
+        if (!gLayerScopeManager.GetSocketManager())
             return NS_OK;
 
         printf_stderr("*** LayerScope: Accepted connection\n");
-        WebSocketHelper::GetSocketManager()->AddConnection(aTransport);
+        gLayerScopeManager.GetSocketManager()->AddConnection(aTransport);
+        gLayerScopeManager.GetContentMonitor()->Empty();
         return NS_OK;
     }
 
     NS_IMETHODIMP OnStopListening(nsIServerSocket *aServ,
                                   nsresult aStatus) override
     {
         return NS_OK;
     }
@@ -614,55 +727,44 @@ public:
         if (mList.isEmpty())
             return;
 
         DebugGLData *d;
         while ((d = mList.popFirst()) != nullptr)
             delete d;
     }
 
-    /* nsIRunnable impl; send the data */
-
     NS_IMETHODIMP Run() override {
         DebugGLData *d;
         nsresult rv = NS_OK;
 
         while ((d = mList.popFirst()) != nullptr) {
             UniquePtr<DebugGLData> cleaner(d);
             if (!d->Write()) {
                 rv = NS_ERROR_FAILURE;
                 break;
             }
         }
 
         Cleanup();
 
         if (NS_FAILED(rv)) {
-            WebSocketHelper::DestroyServerSocket();
+            gLayerScopeManager.DestroyServerSocket();
         }
 
         return NS_OK;
     }
 
 protected:
     LinkedList<DebugGLData> mList;
 };
 
 NS_IMPL_ISUPPORTS(DebugDataSender, nsIRunnable);
 
 
-class CreateServerSocketRunnable : public nsRunnable
-{
-public:
-    NS_IMETHOD Run() {
-        WebSocketHelper::CreateServerSocket();
-        return NS_OK;
-    }
-};
-
 /*
  * LayerScope SendXXX Structure
  * 1. SendLayer
  * 2. SendEffectChain
  *   1. SendTexturedEffect
  *      -> SendTextureSource
  *   2. SendYCbCrEffect
  *      -> SendTextureSource
@@ -794,17 +896,17 @@ SenderHelper::SendLayer(LayerComposite* 
 }
 
 void
 SenderHelper::SendColor(void* aLayerRef,
                         const gfxRGBA& aColor,
                         int aWidth,
                         int aHeight)
 {
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight));
 }
 
 GLuint
 SenderHelper::GetTextureID(GLContext* aGLContext,
                            TextureSourceOGL* aSource) {
     GLenum textureTarget = aSource->GetTextureTarget();
     aSource->BindTexture(LOCAL_GL_TEXTURE0, gfx::Filter::LINEAR);
@@ -843,17 +945,17 @@ SenderHelper::SendTextureSource(GLContex
     gfx::IntSize size = aSource->GetSize();
 
     // By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding
     // texture correctly. texID is used for tracking in DebugGLTextureData.
     RefPtr<DataSourceSurface> img =
         aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget,
                                                          size,
                                                          shaderConfig, aFlipY);
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
                                aTexID, img));
 
     sTextureIdList.push_back(aTexID);
 }
 
 #ifdef MOZ_WIDGET_GONK
 bool
@@ -864,23 +966,29 @@ SenderHelper::SendGraphicBuffer(void* aL
     if (!aEffect->mState.mSurface.get()) {
         return false;
     }
 
     GLenum target = aSource->GetTextureTarget();
     mozilla::UniquePtr<DebugGLGraphicBuffer> package =
         MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, aTexID, aEffect->mState);
 
-    if (!package->TryPack()) {
+    // The texure content in this TexureHost is not altered,
+    // we don't need to send it again.
+    bool changed = gLayerScopeManager.GetContentMonitor()->IsChangedOrNew(
+        aEffect->mState.mTexture);
+    if (!package->TryPack(changed)) {
         return false;
     }
 
     // Transfer ownership to SocketManager.
-    WebSocketHelper::GetSocketManager()->AppendDebugData(package.release());
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(package.release());
     sTextureIdList.push_back(aTexID);
+
+    gLayerScopeManager.GetContentMonitor()->ClearChangedHost(aEffect->mState.mTexture);
     return true;
 }
 #endif
 
 void
 SenderHelper::SendTexturedEffect(GLContext* aGLContext,
                                  void* aLayerRef,
                                  const TexturedEffect* aEffect)
@@ -892,19 +1000,20 @@ SenderHelper::SendTexturedEffect(GLConte
 
     GLuint texID = GetTextureID(aGLContext, source);
     if (IsTextureIdContainsInList(texID)) {
         return;
     }
 
 #ifdef MOZ_WIDGET_GONK
     if (SendGraphicBuffer(aLayerRef, source, texID, aEffect)) {
-         return;
+        return;
     }
 #endif
+    // Fallback texture sending path.
     // Render to texture and read pixels back.
     SendTextureSource(aGLContext, aLayerRef, source, texID, false);
 }
 
 void
 SenderHelper::SendYCbCrEffect(GLContext* aGLContext,
                               void* aLayerRef,
                               const EffectYCbCr* aEffect)
@@ -971,16 +1080,26 @@ SenderHelper::SendEffectChain(GLContext*
         default:
             break;
     }
 
     //const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EffectTypes::MASK];
     // TODO:
 }
 
+void
+LayerScope::ContentChanged(TextureHost *host)
+{
+    if (!CheckSendable()) {
+      return;
+    }
+
+    gLayerScopeManager.GetContentMonitor()->SetChangedHost(host);
+}
+
 // ----------------------------------------------
 // LayerScopeWebSocketHandler implementation
 // ----------------------------------------------
 void
 LayerScopeWebSocketHandler::OpenStream(nsISocketTransport* aTransport)
 {
     MOZ_ASSERT(aTransport);
 
@@ -1378,17 +1497,17 @@ LayerScopeWebSocketHandler::HandleDataFr
             break;
     }
     return true;
 }
 
 void
 LayerScopeWebSocketHandler::CloseConnection()
 {
-    WebSocketHelper::GetSocketManager()->CleanDebugData();
+    gLayerScopeManager.GetSocketManager()->CleanDebugData();
     if (mInputStream) {
         mInputStream->AsyncWait(nullptr, 0, 0, nullptr);
         mInputStream = nullptr;
     }
     if (mOutputStream) {
         mOutputStream = nullptr;
     }
     if (mTransport) {
@@ -1448,126 +1567,79 @@ LayerScopeWebSocketManager::DispatchDebu
 // ----------------------------------------------
 void
 LayerScope::Init()
 {
     if (!gfxPrefs::LayerScopeEnabled()) {
         return;
     }
 
-    if (NS_IsMainThread()) {
-        WebSocketHelper::CreateServerSocket();
-    } else {
-        // Dispatch creation to main thread, and make sure we
-        // dispatch this only once after booting
-        static bool dispatched = false;
-        if (dispatched) {
-            return;
-        }
-        DebugOnly<nsresult> rv = NS_DispatchToMainThread(new CreateServerSocketRunnable());
-        MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to dispatch WebSocket Creation to main thread");
-        dispatched = true;
-    }
+    gLayerScopeManager.CreateServerSocket();
 }
 
-class DrawSession {
-public:
-    NS_INLINE_DECL_REFCOUNTING(DrawSession)
-
-    DrawSession()
-      : mOffsetX(0.0),
-        mOffsetY(0.0),
-        mRects(0)
-    { }
-
-    float mOffsetX;
-    float mOffsetY;
-    gfx::Matrix4x4 mMVMatrix;
-    size_t mRects;
-    gfx::Rect mLayerRects[4];
-private:
-    ~DrawSession() {}
-};
-
-class DrawSessionHolder {
-public:
-    static void setSession(DrawSession *aSession) {
-        mSession = aSession;
-    }
-
-    static DrawSession& current() {
-        return *mSession;
-    }
-
-private:
-    static nsRefPtr<DrawSession> mSession;
-};
-
-nsRefPtr<DrawSession> DrawSessionHolder::mSession;
-
 void
 LayerScope::DrawBegin()
 {
     if (!CheckSendable()) {
         return;
     }
 
-    DrawSessionHolder::setSession(new DrawSession());
+    gLayerScopeManager.NewDrawSession();
 }
 
 void LayerScope::SetRenderOffset(float aX, float aY)
 {
     if (!CheckSendable()) {
         return;
     }
 
-    DrawSessionHolder::current().mOffsetX = aX;
-    DrawSessionHolder::current().mOffsetY = aY;
+    gLayerScopeManager.CurrentSession().mOffsetX = aX;
+    gLayerScopeManager.CurrentSession().mOffsetY = aY;
 }
 
 void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix)
 {
     if (!CheckSendable()) {
         return;
     }
 
-    DrawSessionHolder::current().mMVMatrix = aMatrix;
+    gLayerScopeManager.CurrentSession().mMVMatrix = aMatrix;
 }
 
 void LayerScope::SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects)
 {
     if (!CheckSendable()) {
         return;
     }
 
     MOZ_ASSERT(aRects > 0 && aRects <= 4);
     MOZ_ASSERT(aLayerRects);
 
-    DrawSessionHolder::current().mRects = aRects;
+    gLayerScopeManager.CurrentSession().mRects = aRects;
 
     for (size_t i = 0; i < aRects; i++){
-        DrawSessionHolder::current().mLayerRects[i] = aLayerRects[i];
+        gLayerScopeManager.CurrentSession().mLayerRects[i] = aLayerRects[i];
     }
 }
 
 void
 LayerScope::DrawEnd(gl::GLContext* aGLContext,
                     const EffectChain& aEffectChain,
                     int aWidth,
                     int aHeight)
 {
     // Protect this public function
     if (!CheckSendable()) {
         return;
     }
 
     // 1. Send parameters of draw call, such as uniforms and attributes of
     // vertex adnd fragment shader.
-    DrawSession& draws = DrawSessionHolder::current();
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    DrawSession& draws = gLayerScopeManager.CurrentSession();
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLDrawData(draws.mOffsetX, draws.mOffsetY,
                             draws.mMVMatrix, draws.mRects,
                             draws.mLayerRects,
                             aEffectChain.mLayerRef));
 
     // 2. Send textures.
     SenderHelper::SendEffectChain(aGLContext, aEffectChain, aWidth, aHeight);
 }
@@ -1586,52 +1658,52 @@ LayerScope::SendLayer(LayerComposite* aL
 
 void
 LayerScope::SendLayerDump(UniquePtr<Packet> aPacket)
 {
     // Protect this public function
     if (!CheckSendable() || !SenderHelper::GetLayersTreeSendable()) {
         return;
     }
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLLayersData(Move(aPacket)));
 }
 
 bool
 LayerScope::CheckSendable()
 {
     // Only compositor threads check LayerScope status
     MOZ_ASSERT(CompositorParent::IsInCompositorThread() || gIsGtest);
 
     if (!gfxPrefs::LayerScopeEnabled()) {
         return false;
     }
-    if (!WebSocketHelper::GetSocketManager()) {
+    if (!gLayerScopeManager.GetSocketManager()) {
         Init();
         return false;
     }
-    if (!WebSocketHelper::GetSocketManager()->IsConnected()) {
+    if (!gLayerScopeManager.GetSocketManager()->IsConnected()) {
         return false;
     }
     return true;
 }
 
 void
 LayerScope::CleanLayer()
 {
     if (CheckSendable()) {
-        WebSocketHelper::GetSocketManager()->CleanDebugData();
+        gLayerScopeManager.GetSocketManager()->CleanDebugData();
     }
 }
 
 void
 LayerScope::SetHWComposed()
 {
     if (CheckSendable()) {
-        WebSocketHelper::GetSocketManager()->AppendDebugData(
+        gLayerScopeManager.GetSocketManager()->AppendDebugData(
             new DebugGLMetaData(Packet::META, true));
     }
 }
 
 // ----------------------------------------------
 // LayerScopeAutoFrame implementation
 // ----------------------------------------------
 LayerScopeAutoFrame::LayerScopeAutoFrame(int64_t aFrameStamp)
@@ -1650,26 +1722,26 @@ void
 LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp)
 {
     SenderHelper::ClearTextureIdList();
 
     if (!LayerScope::CheckSendable()) {
         return;
     }
 
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLFrameStatusData(Packet::FRAMESTART, aFrameStamp));
 }
 
 void
 LayerScopeAutoFrame::EndFrame()
 {
     if (!LayerScope::CheckSendable()) {
         return;
     }
 
-    WebSocketHelper::GetSocketManager()->AppendDebugData(
+    gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLFrameStatusData(Packet::FRAMEEND));
-    WebSocketHelper::GetSocketManager()->DispatchDebugData();
+    gLayerScopeManager.GetSocketManager()->DispatchDebugData();
 }
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/LayerScope.h
+++ b/gfx/layers/LayerScope.h
@@ -35,16 +35,17 @@ public:
     static void SendLayer(LayerComposite* aLayer,
                           int aWidth,
                           int aHeight);
     static void SendLayerDump(UniquePtr<layerscope::Packet> aPacket);
     static bool CheckSendable();
     static void CleanLayer();
     static void SetHWComposed();
 
+    static void ContentChanged(TextureHost *host);
 private:
     static void Init();
 };
 
 // Perform BeginFrame and EndFrame automatically
 class LayerScopeAutoFrame {
 public:
     explicit LayerScopeAutoFrame(int64_t aFrameStamp);
--- a/gfx/layers/TextureDIB.cpp
+++ b/gfx/layers/TextureDIB.cpp
@@ -292,17 +292,17 @@ DIBTextureHost::DIBTextureHost(TextureFl
   MOZ_ASSERT(mSurface);
 
   mSize = mSurface->GetSize();
   mFormat = ImageFormatToSurfaceFormat(
     gfxPlatform::GetPlatform()->OptimalFormatForContent(mSurface->GetContentType()));
 }
 
 void
-DIBTextureHost::Updated(const nsIntRegion* aRegion)
+DIBTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
 {
   if (!mCompositor) {
     // This can happen if we send textures to a compositable that isn't yet
     // attached to a layer.
     return;
   }
 
   if (!mTextureSource) {
@@ -326,17 +326,17 @@ TextureHostFileMapping::TextureHostFileM
 }
 
 TextureHostFileMapping::~TextureHostFileMapping()
 {
   ::CloseHandle(mFileMapping);
 }
 
 void
-TextureHostFileMapping::Updated(const nsIntRegion* aRegion)
+TextureHostFileMapping::UpdatedInternal(const nsIntRegion* aRegion)
 {
   if (!mCompositor) {
     // This can happen if we send textures to a compositable that isn't yet
     // attached to a layer.
     return;
   }
 
   if (!mTextureSource) {
--- a/gfx/layers/TextureDIB.h
+++ b/gfx/layers/TextureDIB.h
@@ -150,43 +150,43 @@ protected:
 };
 
 class DIBTextureHost : public TextureHostDirectUpload
 {
 public:
   DIBTextureHost(TextureFlags aFlags,
                  const SurfaceDescriptorDIB& aDescriptor);
 
-  virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
-
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
   {
     return nullptr; // TODO: cf bug 872568
   }
 
 protected:
+  virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
+
   nsRefPtr<gfxWindowsSurface> mSurface;
 };
 
 class TextureHostFileMapping : public TextureHostDirectUpload
 {
 public:
   TextureHostFileMapping(TextureFlags aFlags,
                          const SurfaceDescriptorFileMapping& aDescriptor);
   ~TextureHostFileMapping();
 
-  virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
-
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
   {
     MOZ_CRASH(); // Not implemented! It would be tricky to keep track of the
                  // scope of the file mapping. We could do this through UserData
                  // on the DataSourceSurface but we don't need this right now.
   }
 
 protected:
+  virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
+
   HANDLE mFileMapping;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_TEXTUREDIB_H */
--- a/gfx/layers/TiledLayerBuffer.h
+++ b/gfx/layers/TiledLayerBuffer.h
@@ -536,32 +536,32 @@ TiledLayerBuffer<Derived, Tile>::Update(
 
       if (tileDrawRegion.IsEmpty()) {
         // We have a tile but it doesn't hit the draw region
         // because we can reuse all of the content from the
         // previous buffer.
 #ifdef DEBUG
         int currTileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
         int currTileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
-        int index = currTileX * mRetainedHeight + currTileY;
+        int index = TileIndex(currTileX, currTileY);
         // If allocating a tile failed we can run into this assertion.
         // Rendering is going to be glitchy but we don't want to crash.
         NS_ASSERTION(!newValidRegion.Intersects(tileRect) ||
                      !newRetainedTiles.
                                     SafeElementAt(index, AsDerived().GetPlaceholderTile()).IsPlaceholderTile(),
                      "Unexpected placeholder tile");
 
 #endif
         y += height;
         continue;
       }
 
       int tileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
       int tileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
-      int index = tileX * mRetainedHeight + tileY;
+      int index = TileIndex(tileX, tileY);
       MOZ_ASSERT(index >= 0 &&
                  static_cast<unsigned>(index) < newRetainedTiles.Length(),
                  "index out of range");
 
       Tile newTile = newRetainedTiles[index];
 
       // Try to reuse a tile from the old retained tiles that had no partially
       // valid content.
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -318,17 +318,18 @@ RoundOut(Rect r)
   return IntRect(r.x, r.y, r.width, r.height);
 }
 
 void
 BasicCompositor::DrawQuad(const gfx::Rect& aRect,
                           const gfx::Rect& aClipRect,
                           const EffectChain &aEffectChain,
                           gfx::Float aOpacity,
-                          const gfx::Matrix4x4 &aTransform)
+                          const gfx::Matrix4x4& aTransform,
+                          const gfx::Rect& aVisibleRect)
 {
   RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget;
 
   // For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing,
   // |dest| is a temporary surface.
   RefPtr<DrawTarget> dest = buffer;
 
   buffer->PushClipRect(aClipRect);
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -79,17 +79,18 @@ public:
   {
     return mRenderTarget;
   }
 
   virtual void DrawQuad(const gfx::Rect& aRect,
                         const gfx::Rect& aClipRect,
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
-                        const gfx::Matrix4x4 &aTransform) override;
+                        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,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) override;
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -123,16 +123,17 @@ CompositableClient::FromIPDLActor(PCompo
   return static_cast<CompositableChild*>(aActor)->mCompositableClient;
 }
 
 CompositableClient::CompositableClient(CompositableForwarder* aForwarder,
                                        TextureFlags aTextureFlags)
 : mCompositableChild(nullptr)
 , mForwarder(aForwarder)
 , mTextureFlags(aTextureFlags)
+, mDestroyed(false)
 {
   MOZ_COUNT_CTOR(CompositableClient);
 }
 
 CompositableClient::~CompositableClient()
 {
   MOZ_COUNT_DTOR(CompositableClient);
   Destroy();
@@ -164,16 +165,18 @@ CompositableClient::Connect()
   }
   GetForwarder()->Connect(this);
   return true;
 }
 
 void
 CompositableClient::Destroy()
 {
+  mDestroyed = true;
+
   if (!mCompositableChild) {
     return;
   }
   // Send pending AsyncMessages before deleting CompositableChild.
   // They might have dependency to the mCompositableChild.
   mForwarder->SendPendingAsyncMessges();
   // Delete CompositableChild.
   mCompositableChild->mCompositableClient = nullptr;
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -144,16 +144,18 @@ public:
 
   /**
    * Establishes the connection with compositor side through IPDL
    */
   virtual bool Connect();
 
   void Destroy();
 
+  bool IsDestroyed() { return mDestroyed; }
+
   PCompositableChild* GetIPDLActor() const;
 
   // should only be called by a CompositableForwarder
   virtual void SetIPDLActor(CompositableChild* aChild);
 
   CompositableForwarder* GetForwarder() const
   {
     return mForwarder;
@@ -227,16 +229,17 @@ public:
 
   static void DumpTextureClient(std::stringstream& aStream, TextureClient* aTexture);
 protected:
   CompositableChild* mCompositableChild;
   CompositableForwarder* mForwarder;
   // Some layers may want to enforce some flags to all their textures
   // (like disallowing tiling)
   TextureFlags mTextureFlags;
+  bool mDestroyed;
   RefPtr<TextureClientRecycleAllocator> mTextureClientRecycler;
 
   friend class CompositableChild;
 };
 
 /**
  * Helper to call RemoveTexture at the end of a scope.
  */
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -535,16 +535,17 @@ public:
   TiledContentClient(ClientTiledPaintedLayer* aPaintedLayer,
                      ClientLayerManager* aManager);
 
 protected:
   ~TiledContentClient()
   {
     MOZ_COUNT_DTOR(TiledContentClient);
 
+    mDestroyed = true;
     mTiledBuffer.Release();
     mLowPrecisionTiledBuffer.Release();
   }
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
 
   virtual void Dump(std::stringstream& aStream,
                     const char* aPrefix="",
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -348,16 +348,23 @@ TextureHost::PrintInfo(std::stringstream
     RefPtr<gfx::DataSourceSurface> dSurf = GetAsSurface();
     if (dSurf) {
       aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get();
     }
   }
 #endif
 }
 
+void
+TextureHost::Updated(const nsIntRegion* aRegion)
+{
+    LayerScope::ContentChanged(this);
+    UpdatedInternal(aRegion);
+}
+
 TextureSource::TextureSource()
 : mCompositableCount(0)
 {
     MOZ_COUNT_CTOR(TextureSource);
 }
 
 TextureSource::~TextureSource()
 {
@@ -396,17 +403,17 @@ BufferTextureHost::InitSize()
     }
   }
 }
 
 BufferTextureHost::~BufferTextureHost()
 {}
 
 void
-BufferTextureHost::Updated(const nsIntRegion* aRegion)
+BufferTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
 {
   ++mUpdateSerial;
   // If the last frame wasn't uploaded yet, and we -don't- have a partial update,
   // we still need to update the full surface.
   if (aRegion && !mNeedsFullUpdate) {
     mMaybeUpdatedRegion = mMaybeUpdatedRegion.Or(mMaybeUpdatedRegion, *aRegion);
   } else {
     mNeedsFullUpdate = true;
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -383,17 +383,17 @@ public:
    * Is called before compositing if the shared data has changed since last
    * composition.
    * This method should be overload in cases like when we need to do a texture
    * upload for example.
    *
    * @param aRegion The region that has been changed, if nil, it means that the
    * entire surface should be updated.
    */
-  virtual void Updated(const nsIntRegion* aRegion = nullptr) {}
+   void Updated(const nsIntRegion* aRegion = nullptr);
 
   /**
    * Sets this TextureHost's compositor.
    * A TextureHost can change compositor on certain occasions, in particular if
    * it belongs to an async Compositable.
    * aCompositor can be null, in which case the TextureHost must cleanup  all
    * of it's device textures.
    */
@@ -533,16 +533,18 @@ public:
 
 protected:
   FenceHandle mReleaseFenceHandle;
 
   FenceHandle mAcquireFenceHandle;
 
   void RecycleTexture(TextureFlags aFlags);
 
+  virtual void UpdatedInternal(const nsIntRegion *Region) {}
+
   PTextureParent* mActor;
   TextureFlags mFlags;
   int mCompositableCount;
 
   friend class TextureParent;
 };
 
 /**
@@ -565,18 +567,16 @@ public:
                     TextureFlags aFlags);
 
   ~BufferTextureHost();
 
   virtual uint8_t* GetBuffer() = 0;
 
   virtual size_t GetBufferSize() = 0;
 
-  virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
-
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
   virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
 
   virtual void DeallocateDeviceData() override;
 
@@ -598,16 +598,18 @@ public:
   virtual bool HasInternalBuffer() const override { return true; }
 
 protected:
   bool Upload(nsIntRegion *aRegion = nullptr);
   bool MaybeUpload(nsIntRegion *aRegion = nullptr);
 
   void InitSize();
 
+  virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
+
   RefPtr<Compositor> mCompositor;
   RefPtr<DataTextureSource> mFirstSource;
   nsIntRegion mMaybeUpdatedRegion;
   gfx::IntSize mSize;
   // format of the data that is shared with the content process.
   gfx::SurfaceFormat mFormat;
   uint32_t mUpdateSerial;
   bool mLocked;
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -208,18 +208,18 @@ TiledLayerBufferComposite::UseTiles(cons
     // if we changed a tile's front buffer (causing mSharedLock to
     // go into mPreviousSharedLock, and then did not composite that tile until
     // the next transaction, either because the tile is offscreen or because the
     // two transactions happened with no composition in between (over-production).
     tile.ReadUnlockPrevious();
 
     if (tile.mTextureHost && !tile.mTextureHost->HasInternalBuffer()) {
       MOZ_ASSERT(tile.mSharedLock);
-      int tileX = i % oldRetainedWidth + oldFirstTileX;
-      int tileY = i / oldRetainedWidth + oldFirstTileY;
+      int tileX = i / oldRetainedHeight + oldFirstTileX;
+      int tileY = i % oldRetainedHeight + oldFirstTileY;
 
       if (tileX >= newFirstTileX && tileY >= newFirstTileY &&
           tileX < (newFirstTileX + newRetainedWidth) &&
           tileY < (newFirstTileY + newRetainedHeight)) {
         // This tile still exist in the new buffer
         tile.mPreviousSharedLock = tile.mSharedLock;
         tile.mSharedLock = nullptr;
       } else {
@@ -232,28 +232,28 @@ TiledLayerBufferComposite::UseTiles(cons
     // By now we should not have anything in mSharedLock.
     MOZ_ASSERT(!tile.mSharedLock);
   }
 
   // Step 2, move the tiles in mRetainedTiles at places that correspond to where
   // they should be with the new retained with and height rather than the
   // old one.
   for (size_t i = 0; i < tileDescriptors.Length(); i++) {
-    int tileX = i % newRetainedWidth + newFirstTileX;
-    int tileY = i / newRetainedWidth + newFirstTileY;
+    int tileX = i / newRetainedHeight + newFirstTileX;
+    int tileY = i % newRetainedHeight + newFirstTileY;
 
     // First, get the already existing tiles to the right place in the array,
     // and use placeholders where there was no tiles.
     if (tileX < oldFirstTileX || tileY < oldFirstTileY ||
         tileX >= (oldFirstTileX + oldRetainedWidth) ||
         tileY >= (oldFirstTileY + oldRetainedHeight)) {
       mRetainedTiles[i] = GetPlaceholderTile();
     } else {
-      mRetainedTiles[i] = oldTiles[(tileY - oldFirstTileY) * oldRetainedWidth +
-                                   (tileX - oldFirstTileX)];
+      mRetainedTiles[i] = oldTiles[(tileX - oldFirstTileX) * oldRetainedHeight +
+                                   (tileY - oldFirstTileY)];
       // If we hit this assertion it means we probably mixed something up in the
       // logic that tries to reuse tiles on the compositor side. It is most likely
       // benign, but we are missing some fast paths so let's try to make it not happen.
       MOZ_ASSERT(tileX == mRetainedTiles[i].x && tileY == mRetainedTiles[i].y);
     }
   }
 
   // It is important to remove the duplicated reference to tiles before calling
@@ -329,18 +329,18 @@ TiledLayerBufferComposite::UseTiles(cons
         // It is okay to unlock it because we just destroyed the texture source.
         tile.ReadUnlockPrevious();
         tile = GetPlaceholderTile();
 
         break;
       }
     }
 
-    tile.x = i % newRetainedWidth + newFirstTileX;
-    tile.y = i / newRetainedWidth + newFirstTileY;
+    tile.x = i / newRetainedHeight + newFirstTileX;
+    tile.y = i % newRetainedHeight + newFirstTileY;
   }
 
   mFirstTileX = newFirstTileX;
   mFirstTileY = newFirstTileY;
   mRetainedWidth = newRetainedWidth;
   mRetainedHeight = newRetainedHeight;
   mValidRegion = aTiles.validRegion();
 
@@ -430,17 +430,18 @@ TiledContentHost::RenderTile(TileHost& a
                              const gfxRGBA* aBackgroundColor,
                              EffectChain& aEffectChain,
                              float aOpacity,
                              const gfx::Matrix4x4& aTransform,
                              const gfx::Filter& aFilter,
                              const gfx::Rect& aClipRect,
                              const nsIntRegion& aScreenRegion,
                              const IntPoint& aTextureOffset,
-                             const nsIntSize& aTextureBounds)
+                             const nsIntSize& aTextureBounds,
+                             const gfx::Rect& aVisibleRect)
 {
   if (aTile.IsPlaceholderTile()) {
     // This shouldn't ever happen, but let's fail semi-gracefully. No need
     // to warn, the texture update would have already caught this.
     return;
   }
 
   if (aBackgroundColor) {
@@ -485,17 +486,17 @@ TiledContentHost::RenderTile(TileHost& a
     Rect graphicsRect(rect->x, rect->y, rect->width, rect->height);
     Rect textureRect(rect->x - aTextureOffset.x, rect->y - aTextureOffset.y,
                      rect->width, rect->height);
 
     effect->mTextureCoords = Rect(textureRect.x / aTextureBounds.width,
                                   textureRect.y / aTextureBounds.height,
                                   textureRect.width / aTextureBounds.width,
                                   textureRect.height / aTextureBounds.height);
-    mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, aOpacity, aTransform);
+    mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, aOpacity, aTransform, aVisibleRect);
   }
   DiagnosticFlags flags = DiagnosticFlags::CONTENT | DiagnosticFlags::TILE;
   if (aTile.mTextureHostOnWhite) {
     flags |= DiagnosticFlags::COMPONENT_ALPHA;
   }
   mCompositor->DrawDiagnostics(flags,
                                aScreenRegion, aClipRect, aTransform, mFlashCounter);
   aTile.ReadUnlockPrevious();
@@ -577,17 +578,19 @@ TiledContentHost::RenderLayerBuffer(Tile
 
         if (!tileDrawRegion.IsEmpty()) {
           tileDrawRegion.ScaleRoundOut(resolution, resolution);
           IntPoint tileOffset((x - tileStartX) * resolution,
                                 (y - tileStartY) * resolution);
           gfx::IntSize tileSize = aLayerBuffer.GetTileSize();
           RenderTile(tileTexture, aBackgroundColor, aEffectChain, aOpacity, aTransform,
                      aFilter, aClipRect, tileDrawRegion, tileOffset,
-                     nsIntSize(tileSize.width, tileSize.height));
+                     nsIntSize(tileSize.width, tileSize.height),
+                     gfx::Rect(visibleRect.x, visibleRect.y,
+                               visibleRect.width, visibleRect.height));
           if (tileTexture.mTextureHostOnWhite) {
             componentAlphaDiagnostic = DiagnosticFlags::COMPONENT_ALPHA;
           }
         }
       }
       tileY++;
       y += h;
     }
--- a/gfx/layers/composite/TiledContentHost.h
+++ b/gfx/layers/composite/TiledContentHost.h
@@ -278,17 +278,18 @@ private:
                   const gfxRGBA* aBackgroundColor,
                   EffectChain& aEffectChain,
                   float aOpacity,
                   const gfx::Matrix4x4& aTransform,
                   const gfx::Filter& aFilter,
                   const gfx::Rect& aClipRect,
                   const nsIntRegion& aScreenRegion,
                   const gfx::IntPoint& aTextureOffset,
-                  const gfx::IntSize& aTextureBounds);
+                  const gfx::IntSize& aTextureBounds,
+                  const gfx::Rect& aVisibleRect);
 
   void EnsureTileStore() {}
 
   TiledLayerBufferComposite    mTiledBuffer;
   TiledLayerBufferComposite    mLowPrecisionTiledBuffer;
 };
 
 }
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -736,17 +736,18 @@ CompositorD3D11::DrawVRDistortion(const 
   mContext->IASetInputLayout(mAttachments->mInputLayout);
 }
 
 void
 CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
                           const gfx::Rect& aClipRect,
                           const EffectChain& aEffectChain,
                           gfx::Float aOpacity,
-                          const gfx::Matrix4x4& aTransform)
+                          const gfx::Matrix4x4& aTransform,
+                          const gfx::Rect& aVisibleRect)
 {
   if (mCurrentClip.IsEmpty()) {
     return;
   }
 
   MOZ_ASSERT(mCurrentRT, "No render target");
 
   if (aEffectChain.mPrimaryEffect->mType == EffectTypes::VR_DISTORTION) {
@@ -1018,17 +1019,17 @@ CompositorD3D11::BeginFrame(const nsIntR
     return;
   }
 
   nsIntSize oldSize = mSize;
   UpdateRenderTarget();
 
   // Failed to create a render target or the view.
   if (!mDefaultRT || !mDefaultRT->mRTView ||
-      mSize.width == 0 || mSize.height == 0) {
+      mSize.width <= 0 || mSize.height <= 0) {
     *aRenderBoundsOut = Rect();
     return;
   }
 
   mContext->IASetInputLayout(mAttachments->mInputLayout);
 
   ID3D11Buffer* buffer = mAttachments->mVertexBuffer;
   UINT size = sizeof(Vertex);
@@ -1087,16 +1088,20 @@ void
 CompositorD3D11::EndFrame()
 {
   if (!mDefaultRT) {
     return;
   }
 
   nsIntSize oldSize = mSize;
   EnsureSize();
+  if (mSize.width <= 0 || mSize.height <= 0) {
+    return;
+  }
+
   UINT presentInterval = 0;
 
   if (gfxWindowsPlatform::GetPlatform()->IsWARP()) {
     // When we're using WARP we cannot present immediately as it causes us
     // to tear when rendering. When not using WARP it appears the DWM takes
     // care of tearing for us.
     presentInterval = 1;
   }
@@ -1175,16 +1180,17 @@ CompositorD3D11::EnsureSize()
 bool
 CompositorD3D11::VerifyBufferSize()
 {
   DXGI_SWAP_CHAIN_DESC swapDesc;
   HRESULT hr;
 
   hr = mSwapChain->GetDesc(&swapDesc);
   if (Failed(hr)) {
+    gfxCriticalError() << "Failed to get the description " << hexa(hr);
     return false;
   }
 
   if ((swapDesc.BufferDesc.Width == mSize.width &&
        swapDesc.BufferDesc.Height == mSize.height) ||
       mSize.width <= 0 || mSize.height <= 0) {
     return true;
   }
@@ -1205,22 +1211,30 @@ CompositorD3D11::VerifyBufferSize()
 
   return Succeeded(hr);
 }
 
 void
 CompositorD3D11::UpdateRenderTarget()
 {
   EnsureSize();
-  VerifyBufferSize();
+  if (!VerifyBufferSize()) {
+    gfxCriticalError(gfxCriticalError::DefaultOptions(false)) << "Failed VerifyBufferSize in UpdateRenderTarget";
+    return;
+  }
 
   if (mDefaultRT) {
     return;
   }
 
+  if (mSize.width <= 0 || mSize.height <= 0) {
+    gfxCriticalError(gfxCriticalError::DefaultOptions(false)) << "Invalid size in UpdateRenderTarget " << mSize;
+    return;
+  }
+
   HRESULT hr;
 
   nsRefPtr<ID3D11Texture2D> backBuf;
 
   hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)backBuf.StartAssignment());
   if (hr == DXGI_ERROR_INVALID_CALL) {
     // This happens on some GPUs/drivers when there's a TDR.
     if (mDevice->GetDeviceRemovedReason() != S_OK) {
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -89,17 +89,18 @@ public:
   }
 
   virtual void ClearRect(const gfx::Rect& aRect) override;
 
   virtual void DrawQuad(const gfx::Rect &aRect,
                         const gfx::Rect &aClipRect,
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
-                        const gfx::Matrix4x4 &aTransform) override;
+                        const gfx::Matrix4x4& aTransform,
+                        const gfx::Rect& aVisibleRect) override;
 
   /* Helper for when the primary effect is VR_DISTORTION */
   void DrawVRDistortion(const gfx::Rect &aRect,
                         const gfx::Rect &aClipRect,
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
                         const gfx::Matrix4x4 &aTransform);
 
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -236,17 +236,18 @@ CompositorD3D9::ClearRect(const gfx::Rec
                   0x00000000, 0, 0);
 }
 
 void
 CompositorD3D9::DrawQuad(const gfx::Rect &aRect,
                          const gfx::Rect &aClipRect,
                          const EffectChain &aEffectChain,
                          gfx::Float aOpacity,
-                         const gfx::Matrix4x4 &aTransform)
+                         const gfx::Matrix4x4& aTransform,
+                         const gfx::Rect& aVisibleRect)
 {
   if (!mDeviceManager) {
     return;
   }
 
   IDirect3DDevice9* d3d9Device = device();
   MOZ_ASSERT(d3d9Device, "We should be able to get a device now");
 
--- a/gfx/layers/d3d9/CompositorD3D9.h
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -52,17 +52,18 @@ public:
   virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) override {}
 
   virtual void ClearRect(const gfx::Rect& aRect) override;
 
   virtual void DrawQuad(const gfx::Rect &aRect,
                         const gfx::Rect &aClipRect,
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
-                        const gfx::Matrix4x4 &aTransform) override;
+                        const gfx::Matrix4x4& aTransform,
+                        const gfx::Rect& aVisibleRect) override;
 
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::Rect *aClipRectIn,
                           const gfx::Rect& aRenderBounds,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) override;
 
   virtual void EndFrame() override;
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -909,17 +909,17 @@ DataTextureSourceD3D9::UpdateFromTexture
       return false;
     }
   }
   mIsTiled = false;
   return true;
 }
 
 void
-TextureHostD3D9::Updated(const nsIntRegion* aRegion)
+TextureHostD3D9::UpdatedInternal(const nsIntRegion* aRegion)
 {
   MOZ_ASSERT(mTexture);
   if (!mTexture) {
     return;
   }
 
   if (!mTextureSource) {
     mTextureSource = new DataTextureSourceD3D9(mFormat, mSize, mCompositor,
--- a/gfx/layers/d3d9/TextureD3D9.h
+++ b/gfx/layers/d3d9/TextureD3D9.h
@@ -303,31 +303,31 @@ public:
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
 
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
-  virtual void Updated(const nsIntRegion* aRegion) override;
-
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() override
   {
     return nullptr;
   }
 
   virtual bool HasInternalBuffer() const override { return true; }
 
 protected:
   TextureHostD3D9(TextureFlags aFlags);
   IDirect3DDevice9* GetDevice();
 
+  virtual void UpdatedInternal(const nsIntRegion* aRegion) override;
+
   RefPtr<DataTextureSourceD3D9> mTextureSource;
   RefPtr<IDirect3DTexture9> mTexture;
   RefPtr<CompositorD3D9> mCompositor;
   gfx::IntSize mSize;
   gfx::SurfaceFormat mFormat;
   bool mIsLocked;
 };
 
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -423,17 +423,17 @@ ShadowLayerForwarder::RemoveTextureFromC
   HoldUntilTransaction(aTexture);
 }
 
 void
 ShadowLayerForwarder::RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker,
                                                      CompositableClient* aCompositable,
                                                      TextureClient* aTexture)
 {
-  if (mTxn->Opened()) {
+  if (mTxn->Opened() && !aCompositable->IsDestroyed()) {
     mTxn->AddEdit(OpRemoveTextureAsync(CompositableClient::GetTrackersHolderId(aCompositable->GetIPDLActor()),
                                        aAsyncTransactionTracker->GetId(),
                                        nullptr, aCompositable->GetIPDLActor(),
                                        nullptr, aTexture->GetIPDLActor()));
   } else {
     // If the function is called outside of transaction,
     // OpRemoveTextureAsync message is stored as pending message.
 #ifdef MOZ_WIDGET_GONK
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -42,17 +42,17 @@ EXPORTS += [
     'opengl/TexturePoolOGL.h',
     'protobuf/LayerScopePacket.pb.h',
     'ReadbackLayer.h',
     'TiledLayerBuffer.h',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     SOURCES += [
-	    'D3D11ShareHandleImage.cpp',
+        'D3D11ShareHandleImage.cpp',
     ]
     UNIFIED_SOURCES += [
         'D3D9SurfaceImage.cpp',
         'IMFYCbCrImage.cpp',
         'TextureDIB.cpp',
     ]
     EXPORTS.mozilla.layers += [
         'TextureDIB.h',
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -82,17 +82,17 @@ CompositorOGL::CompositorOGL(nsIWidget *
                              int aSurfaceHeight, bool aUseExternalSurfaceSize)
   : mWidget(aWidget)
   , mWidgetSize(-1, -1)
   , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mHasBGRA(0)
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   , mFrameInProgress(false)
   , mDestroyed(false)
-  , mHeight(0)
+  , mViewportSize(0, 0)
   , mCurrentProgram(nullptr)
 {
   MOZ_COUNT_CTOR(CompositorOGL);
   SetBackend(LayersBackend::LAYERS_OPENGL);
 }
 
 CompositorOGL::~CompositorOGL()
 {
@@ -436,17 +436,17 @@ CompositorOGL::BindAndDrawQuadWithTextur
 }
 
 void
 CompositorOGL::PrepareViewport(const gfx::IntSize& aSize)
 {
   // Set the viewport correctly.
   mGLContext->fViewport(0, 0, aSize.width, aSize.height);
 
-  mHeight = aSize.height;
+  mViewportSize = aSize;
 
   // We flip the view matrix around so that everything is right-side up; we're
   // drawing directly into the window's back buffer, so this keeps things
   // looking correct.
   // XXX: We keep track of whether the window size changed, so we could skip
   // this update if it hadn't changed since the last call.
 
   // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
@@ -570,17 +570,17 @@ CalculatePOTSize(const IntSize& aSize, G
 
   return IntSize(NextPowerOfTwo(aSize.width), NextPowerOfTwo(aSize.height));
 }
 
 void
 CompositorOGL::ClearRect(const gfx::Rect& aRect)
 {
   // Map aRect to OGL coordinates, origin:bottom-left
-  GLint y = mHeight - (aRect.y + aRect.height);
+  GLint y = mViewportSize.height - (aRect.y + aRect.height);
 
   ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
   ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height);
   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
 }
 
 void
@@ -765,17 +765,18 @@ CompositorOGL::CreateFBOWithTexture(cons
   *aFBO = fbo;
   *aTexture = tex;
 }
 
 ShaderConfigOGL
 CompositorOGL::GetShaderConfigFor(Effect *aEffect,
                                   MaskType aMask,
                                   gfx::CompositionOp aOp,
-                                  bool aColorMatrix) const
+                                  bool aColorMatrix,
+                                  bool aDEAAEnabled) const
 {
   ShaderConfigOGL config;
 
   switch(aEffect->mType) {
   case EffectTypes::SOLID_COLOR:
     config.SetRenderColor(true);
     break;
   case EffectTypes::YCBCR:
@@ -816,16 +817,17 @@ CompositorOGL::GetShaderConfigFor(Effect
       config.SetPremultiply(true);
     }
     break;
   }
   }
   config.SetColorMatrix(aColorMatrix);
   config.SetMask2D(aMask == MaskType::Mask2d);
   config.SetMask3D(aMask == MaskType::Mask3d);
+  config.SetDEAA(aDEAAEnabled);
   return config;
 }
 
 ShaderProgramOGL*
 CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig)
 {
   std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig);
   if (iter != mPrograms.end())
@@ -897,22 +899,51 @@ static bool SetBlendMode(GLContext* aGL,
       return false;
   }
 
   aGL->fBlendFuncSeparate(srcBlend, dstBlend,
                           srcAlphaBlend, dstAlphaBlend);
   return true;
 }
 
+gfx::Point3D
+CompositorOGL::GetLineCoefficients(const gfx::Point& aPoint1,
+                                   const gfx::Point& aPoint2)
+{
+  // Return standard coefficients for a line between aPoint1 and aPoint2
+  // for standard line equation:
+  //
+  // Ax + By + C = 0
+  //
+  // A = (p1.y – p2.y)
+  // B = (p2.x – p1.x)
+  // C = (p1.x * p2.y) – (p2.x * p1.y)
+
+  gfx::Point3D coeffecients;
+  coeffecients.x = aPoint1.y - aPoint2.y;
+  coeffecients.y = aPoint2.x - aPoint1.x;
+  coeffecients.z = aPoint1.x * aPoint2.y - aPoint2.x * aPoint1.y;
+
+  coeffecients *= 1.0f / sqrtf(coeffecients.x * coeffecients.x +
+                               coeffecients.y * coeffecients.y);
+
+  // Offset outwards by 0.5 pixel as the edge is considered to be 1 pixel
+  // wide and included within the interior of the polygon
+  coeffecients.z += 0.5f;
+
+  return coeffecients;
+}
+
 void
 CompositorOGL::DrawQuad(const Rect& aRect,
                         const Rect& aClipRect,
                         const EffectChain &aEffectChain,
                         Float aOpacity,
-                        const gfx::Matrix4x4 &aTransform)
+                        const gfx::Matrix4x4& aTransform,
+                        const gfx::Rect& aVisibleRect)
 {
   PROFILER_LABEL("CompositorOGL", "DrawQuad",
     js::ProfileEntry::Category::GRAPHICS);
 
   MOZ_ASSERT(mFrameInProgress, "frame not started");
   MOZ_ASSERT(mCurrentRenderTarget, "No destination");
 
   if (aEffectChain.mPrimaryEffect->mType == EffectTypes::VR_DISTORTION) {
@@ -995,18 +1026,25 @@ CompositorOGL::DrawQuad(const Rect& aRec
 
   gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER;
   if (aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE]) {
     EffectBlendMode *blendEffect =
       static_cast<EffectBlendMode*>(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get());
     blendMode = blendEffect->mBlendMode;
   }
 
+  // Only apply DEAA to quads that have been transformed such that aliasing
+  // could be visible
+  bool bEnableAA = gfxPrefs::LayersDEAAEnabled() &&
+                   !aTransform.Is2DIntegerTranslation();
+
   bool colorMatrix = aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX];
-  ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType, blendMode, colorMatrix);
+  ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect,
+                                              maskType, blendMode, colorMatrix,
+                                              bEnableAA);
   config.SetOpacity(aOpacity != 1.f);
   ShaderProgramOGL *program = GetShaderProgramFor(config);
   ActivateProgram(program);
   program->SetProjectionMatrix(mProjMatrix);
   program->SetLayerTransform(aTransform);
   LayerScope::SetLayerTransform(aTransform);
   if (colorMatrix) {
       EffectColorMatrix* effectColorMatrix =
@@ -1023,16 +1061,84 @@ CompositorOGL::DrawQuad(const Rect& aRec
   if (config.mFeatures & ENABLE_TEXTURE_RECT) {
     TexturedEffect* texturedEffect =
         static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
     TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
     // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
     program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
   }
 
+  // XXX kip - These calculations could be performed once per layer rather than
+  //           for every tile.  This might belong in Compositor.cpp once DEAA
+  //           is implemented for DirectX.
+  if (bEnableAA) {
+    // Calculate the transformed vertices of aVisibleRect in screen space
+    // pixels, mirroring the calculations in the vertex shader
+    Matrix4x4 flatTransform = aTransform;
+    flatTransform.PostTranslate(-offset.x, -offset.y, 0.0f);
+    flatTransform *= mProjMatrix;
+
+    Rect viewportClip = Rect(-1.0f, -1.0f, 2.0f, 2.0f);
+    size_t edgeCount = 0;
+    Point3D coefficients[4];
+
+    Point points[Matrix4x4::kTransformAndClipRectMaxVerts];
+    size_t pointCount = flatTransform.TransformAndClipRect(aVisibleRect, viewportClip, points);
+    for (size_t i = 0; i < pointCount; i++) {
+      points[i] = Point((points[i].x * 0.5f + 0.5f) * mViewportSize.width,
+                        (points[i].y * 0.5f + 0.5f) * mViewportSize.height);
+    }
+    if (pointCount > 2) {
+      // Use shoelace formula on a triangle in the clipped quad to determine if
+      // winding order is reversed.  Iterate through the triangles until one is
+      // found with a non-zero area.
+      float winding = 0.0f;
+      size_t wp = 0;
+      while (winding == 0.0f && wp < pointCount) {
+        int wp1 = (wp + 1) % pointCount;
+        int wp2 = (wp + 2) % pointCount;
+        winding = (points[wp1].x - points[wp].x) * (points[wp1].y + points[wp].y) +
+                  (points[wp2].x - points[wp1].x) * (points[wp2].y + points[wp1].y) +
+                  (points[wp].x - points[wp2].x) * (points[wp].y + points[wp2].y);
+        wp++;
+      }
+      bool frontFacing = winding >= 0.0f;
+
+      // Calculate the line coefficients used by the DEAA shader to determine the
+      // sub-pixel coverage of the edge pixels
+      for (size_t i=0; i<pointCount; i++) {
+        const Point& p1 = points[i];
+        const Point& p2 = points[(i + 1) % pointCount];
+        // Create a DEAA edge for any non-straight lines, to a maximum of 4
+        if (p1.x != p2.x && p1.y != p2.y && edgeCount < 4) {
+          if (frontFacing) {
+            coefficients[edgeCount++] = GetLineCoefficients(p2, p1);
+          } else {
+            coefficients[edgeCount++] = GetLineCoefficients(p1, p2);
+          }
+        }
+      }
+    }
+
+    // The coefficients that are not needed must not cull any fragments.
+    // We fill these unused coefficients with a clipping plane that has no
+    // effect.
+    for (size_t i = edgeCount; i < 4; i++) {
+      coefficients[i] = Point3D(0.0f, 1.0f, mViewportSize.height);
+    }
+
+    // Set uniforms required by DEAA shader
+    Matrix4x4 transformInverted = aTransform;
+    transformInverted.Invert();
+    program->SetLayerTransformInverse(transformInverted);
+    program->SetDEAAEdges(coefficients);
+    program->SetVisibleCenter(aVisibleRect.Center());
+    program->SetViewportSize(mViewportSize);
+  }
+
   bool didSetBlendMode = false;
 
   switch (aEffectChain.mPrimaryEffect->mType) {
     case EffectTypes::SOLID_COLOR: {
       program->SetRenderColor(color);
 
       if (maskType != MaskType::MaskNone) {
         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
@@ -1121,19 +1227,17 @@ CompositorOGL::DrawQuad(const Rect& aRec
       // this, so apply a flip here to cancel the other one out.
       Matrix transform;
       transform.PreTranslate(0.0, 1.0);
       transform.PreScale(1.0f, -1.0f);
       program->SetTextureTransform(Matrix4x4::From2D(transform));
       program->SetTextureUnit(0);
 
       if (maskType != MaskType::MaskNone) {
-        sourceMask->BindTexture(LOCAL_GL_TEXTURE1, gfx::Filter::LINEAR);
-        program->SetMaskTextureUnit(1);
-        program->SetMaskLayerTransform(maskQuadTransform);
+        BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
       }
 
       if (config.mFeatures & ENABLE_TEXTURE_RECT) {
         // 2DRect case, get the multiplier right for a sampler2DRect
         program->SetTexCoordMultiplier(aRect.width, aRect.height);
       }
 
       // Drawing is always flipped, but when copying between surfaces we want to avoid
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -224,17 +224,18 @@ public:
 
   virtual void SetRenderTarget(CompositingRenderTarget *aSurface) override;
   virtual CompositingRenderTarget* GetCurrentRenderTarget() const override;
 
   virtual void DrawQuad(const gfx::Rect& aRect,
                         const gfx::Rect& aClipRect,
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
-                        const gfx::Matrix4x4 &aTransform) override;
+                        const gfx::Matrix4x4& aTransform,
+                        const gfx::Rect& aVisibleRect) override;
 
   virtual void EndFrame() override;
   virtual void SetDispAcquireFence(Layer* aLayer) override;
   virtual FenceHandle GetReleaseFence() override;
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) override;
 
   virtual bool SupportsPartialTextureUpdate() override;
 
@@ -330,17 +331,17 @@ private:
   /** Widget associated with this compositor */
   nsIWidget *mWidget;
   gfx::IntSize mWidgetSize;
   nsRefPtr<GLContext> mGLContext;
   UniquePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
   gfx::Matrix4x4 mProjMatrix;
 
   /** The size of the surface we are rendering to */
-  nsIntSize mSurfaceSize;
+  gfx::IntSize mSurfaceSize;
 
   ScreenPoint mRenderOffset;
 
   already_AddRefed<mozilla::gl::GLContext> CreateContext();
 
   /** Texture target to use for FBOs */
   GLenum mFBOTextureTarget;
 
@@ -382,17 +383,18 @@ private:
                           const gfx::Rect *aClipRectIn,
                           const gfx::Rect& aRenderBounds,
                           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) const;
+                                     bool aColorMatrix = false,
+                                     bool aDEAAEnabled = false) const;
   ShaderProgramOGL* GetShaderProgramFor(const ShaderConfigOGL &aConfig);
 
   /**
    * Create a FBO backed by a texture.
    * Note that the texture target type will be
    * of the type returned by FBOTextureTarget; different
    * shaders are required to sample from the different
    * texture types.
@@ -413,17 +415,18 @@ private:
     layerRects[0] = aLayerRect;
     textureRects[0] = aTextureRect;
     BindAndDrawQuads(aProg, 1, layerRects, textureRects);
   }
   void BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
                                       const gfx::Rect& aRect,
                                       const gfx::Rect& aTexCoordRect,
                                       TextureSource *aTexture);
-
+  gfx::Point3D GetLineCoefficients(const gfx::Point& aPoint1,
+                                   const gfx::Point& aPoint2);
   void ActivateProgram(ShaderProgramOGL *aProg);
   void CleanupResources();
 
   /**
    * Copies the content of our backbuffer to the set transaction target.
    * Does not restore the target FBO, so only call from EndFrame.
    */
   void CopyToTarget(gfx::DrawTarget* aTarget, const nsIntPoint& aTopLeft, const gfx::Matrix& aWorldMatrix);
@@ -432,29 +435,29 @@ private:
    * Implements the flipping of the y-axis to convert from layers/compositor
    * coordinates to OpenGL coordinates.
    *
    * Indeed, the only coordinate system that OpenGL knows has the y-axis
    * pointing upwards, but the layers/compositor coordinate system has the
    * y-axis pointing downwards, for good reason as Web pages are typically
    * scrolled downwards. So, some flipping has to take place; FlippedY does it.
    */
-  GLint FlipY(GLint y) const { return mHeight - y; }
+  GLint FlipY(GLint y) const { return mViewportSize.height - y; }
 
   RefPtr<CompositorTexturePoolOGL> mTexturePool;
 
   ContextStateTrackerOGL mContextStateTracker;
 
   bool mDestroyed;
 
   /**
-   * Height of the OpenGL context's primary framebuffer in pixels. Used by
-   * FlipY for the y-flipping calculation.
+   * Size of the OpenGL context's primary framebuffer in pixels. Used by
+   * FlipY for the y-flipping calculation and by the DEAA shader.
    */
-  GLint mHeight;
+  gfx::IntSize mViewportSize;
 
   FenceHandle mReleaseFenceHandle;
   ShaderProgramOGL *mCurrentProgram;
 
   CompositorOGLVRObjects mVR;
 };
 
 }
--- a/gfx/layers/opengl/GrallocTextureHost.h
+++ b/gfx/layers/opengl/GrallocTextureHost.h
@@ -19,18 +19,16 @@ class GrallocTextureHostOGL : public Tex
 {
   friend class GrallocBufferActor;
 public:
   GrallocTextureHostOGL(TextureFlags aFlags,
                         const NewSurfaceDescriptorGralloc& aDescriptor);
 
   virtual ~GrallocTextureHostOGL();
 
-  virtual void Updated(const nsIntRegion* aRegion) override {}
-
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
   virtual void SetCompositor(Compositor* aCompositor) override;
 
   virtual void DeallocateSharedData() override;
 
--- a/gfx/layers/opengl/OGLShaderProgram.cpp
+++ b/gfx/layers/opengl/OGLShaderProgram.cpp
@@ -25,16 +25,17 @@ using namespace std;
 #define GAUSSIAN_KERNEL_STEP 0.2
 
 void
 AddUniforms(ProgramProfileOGL& aProfile)
 {
     // This needs to be kept in sync with the KnownUniformName enum
     static const char *sKnownUniformNames[] = {
         "uLayerTransform",
+        "uLayerTransformInverse",
         "uMaskTransform",
         "uLayerRects",
         "uMatrixProj",
         "uTextureTransform",
         "uTextureRects",
         "uRenderTargetOffset",
         "uLayerOpacity",
         "uTexture",
@@ -48,16 +49,19 @@ AddUniforms(ProgramProfileOGL& aProfile)
         "uTexCoordMultiplier",
         "uTexturePass2",
         "uColorMatrix",
         "uColorMatrixVector",
         "uBlurRadius",
         "uBlurOffset",
         "uBlurAlpha",
         "uBlurGaussianKernel",
+        "uSSEdges",
+        "uViewportSize",
+        "uVisibleCenter",
         nullptr
     };
 
     for (int i = 0; sKnownUniformNames[i] != nullptr; ++i) {
         aProfile.mUniforms[i].mNameString = sKnownUniformNames[i];
         aProfile.mUniforms[i].mName = (KnownUniform::KnownUniformName) i;
     }
 }
@@ -137,29 +141,40 @@ ShaderConfigOGL::SetMask3D(bool aEnabled
 }
 
 void
 ShaderConfigOGL::SetPremultiply(bool aEnabled)
 {
   SetFeature(ENABLE_PREMULTIPLY, aEnabled);
 }
 
+void
+ShaderConfigOGL::SetDEAA(bool aEnabled)
+{
+  SetFeature(ENABLE_DEAA, aEnabled);
+}
+
 /* static */ ProgramProfileOGL
 ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
 {
   ProgramProfileOGL result;
   ostringstream fs, vs;
 
   AddUniforms(result);
 
   vs << "uniform mat4 uMatrixProj;" << endl;
   vs << "uniform vec4 uLayerRects[4];" << endl;
   vs << "uniform mat4 uLayerTransform;" << endl;
-  vs << "uniform vec4 uRenderTargetOffset;" << endl;
-
+  if (aConfig.mFeatures & ENABLE_DEAA) {
+    vs << "uniform mat4 uLayerTransformInverse;" << endl;
+    vs << "uniform vec3 uSSEdges[4];" << endl;
+    vs << "uniform vec2 uVisibleCenter;" << endl;
+    vs << "uniform vec2 uViewportSize;" << endl;
+  }
+  vs << "uniform vec2 uRenderTargetOffset;" << endl;
   vs << "attribute vec4 aCoord;" << endl;
 
   if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
     vs << "uniform mat4 uTextureTransform;" << endl;
     vs << "uniform vec4 uTextureRects[4];" << endl;
     vs << "varying vec2 vTexCoord;" << endl;
   }
 
@@ -169,37 +184,88 @@ ProgramProfileOGL::GetProfileFor(ShaderC
     vs << "varying vec3 vMaskCoord;" << endl;
   }
 
   vs << "void main() {" << endl;
   vs << "  int vertexID = int(aCoord.w);" << endl;
   vs << "  vec4 layerRect = uLayerRects[vertexID];" << endl;
   vs << "  vec4 finalPosition = vec4(aCoord.xy * layerRect.zw + layerRect.xy, 0.0, 1.0);" << endl;
   vs << "  finalPosition = uLayerTransform * finalPosition;" << endl;
-  vs << "  finalPosition.xyz /= finalPosition.w;" << endl;
+
+  if (aConfig.mFeatures & ENABLE_DEAA) {
+    // XXX kip - The DEAA shader could be made simpler if we switch to
+    //           using dynamic vertex buffers instead of sending everything
+    //           in through uniforms.  This would enable passing information
+    //           about how to dilate each vertex explicitly and eliminate the
+    //           need to extrapolate this with the sub-pixel coverage
+    //           calculation in the vertex shader.
+
+    // Calculate the screen space position of this vertex, in screen pixels
+    vs << "  vec4 ssPos = finalPosition;" << endl;
+    vs << "  ssPos.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
+    vs << "  ssPos = uMatrixProj * ssPos;" << endl;
+    vs << "  ssPos.xy = ((ssPos.xy/ssPos.w)*0.5+0.5)*uViewportSize;" << endl;
+
+    if (aConfig.mFeatures & ENABLE_MASK_2D ||
+        aConfig.mFeatures & ENABLE_MASK_3D ||
+        !(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
+      vs << "  vec4 coordAdjusted;" << endl;
+      vs << "  coordAdjusted.xy = aCoord.xy;" << endl;
+    }
 
-  if (aConfig.mFeatures & ENABLE_MASK_3D) {
-    vs << "  vMaskCoord.xy = (uMaskTransform * vec4(finalPosition.xyz, 1.0)).xy;" << endl;
-    // correct for perspective correct interpolation, see comment in D3D10 shader
-    vs << "  vMaskCoord.z = 1.0;" << endl;
-    vs << "  vMaskCoord *= finalPosition.w;" << endl;
-  } else if (aConfig.mFeatures & ENABLE_MASK_2D) {
-    vs << "  vMaskCoord.xy = (uMaskTransform * finalPosition).xy;" << endl;
-  }
+    // It is necessary to dilate edges away from uVisibleCenter to ensure that
+    // fragments with less than 50% sub-pixel coverage will be shaded.
+    // This offset is applied when the sub-pixel coverage of the vertex is
+    // less than 100%.  Expanding by 0.5 pixels in screen space is sufficient
+    // to include these pixels.
+    vs << "  if (dot(uSSEdges[0], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
+    vs << "      dot(uSSEdges[1], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
+    vs << "      dot(uSSEdges[2], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
+    vs << "      dot(uSSEdges[3], vec3(ssPos.xy, 1.0)) < 1.5) {" << endl;
+    // If the shader reaches this branch, then this vertex is on the edge of
+    // the layer's visible rect and should be dilated away from the center of
+    // the visible rect.  We don't want to hit this for inner facing
+    // edges between tiles, as the pixels may be covered twice without clipping
+    // against uSSEdges.  If all edges were dilated, it would result in
+    // artifacts visible within semi-transparent layers with multiple tiles.
+    vs << "    vec4 visibleCenter = uLayerTransform * vec4(uVisibleCenter, 0.0, 1.0);" << endl;
+    vs << "    vec2 dilateDir = finalPosition.xy / finalPosition.w - visibleCenter.xy / visibleCenter.w;" << endl;
+    vs << "    vec2 offset = sign(dilateDir) * 0.5;" << endl;
+    vs << "    finalPosition.xy += offset * finalPosition.w;" << endl;
+    if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
+      // We must adjust the texture coordinates to compensate for the dilation
+      vs << "    coordAdjusted = uLayerTransformInverse * finalPosition;" << endl;
+      vs << "    coordAdjusted /= coordAdjusted.w;" << endl;
+      vs << "    coordAdjusted.xy -= layerRect.xy;" << endl;
+      vs << "    coordAdjusted.xy /= layerRect.zw;" << endl;
+    }
+    vs << "  }" << endl;
 
-  vs << "  finalPosition = finalPosition - uRenderTargetOffset;" << endl;
-  vs << "  finalPosition.xyz *= finalPosition.w;" << endl;
-  vs << "  finalPosition = uMatrixProj * finalPosition;" << endl;
+    if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
+      vs << "  vec4 textureRect = uTextureRects[vertexID];" << endl;
+      vs << "  vec2 texCoord = coordAdjusted.xy * textureRect.zw + textureRect.xy;" << endl;
+      vs << "  vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
+    }
 
-  if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
+  } else if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
     vs << "  vec4 textureRect = uTextureRects[vertexID];" << endl;
     vs << "  vec2 texCoord = aCoord.xy * textureRect.zw + textureRect.xy;" << endl;
     vs << "  vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
   }
-
+  if (aConfig.mFeatures & ENABLE_MASK_2D ||
+      aConfig.mFeatures & ENABLE_MASK_3D) {
+    vs << "  vMaskCoord.xy = (uMaskTransform * (finalPosition / finalPosition.w)).xy;" << endl;
+    if (aConfig.mFeatures & ENABLE_MASK_3D) {
+      // correct for perspective correct interpolation, see comment in D3D10 shader
+      vs << "  vMaskCoord.z = 1.0;" << endl;
+      vs << "  vMaskCoord *= finalPosition.w;" << endl;
+    }
+  }
+  vs << "  finalPosition.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
+  vs << "  finalPosition = uMatrixProj * finalPosition;" << endl;
   vs << "  gl_Position = finalPosition;" << endl;
   vs << "}" << endl;
 
   if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
     fs << "#extension GL_ARB_texture_rectangle : require" << endl;
   }
   if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) {
     fs << "#extension GL_OES_EGL_image_external : require" << endl;
@@ -256,16 +322,20 @@ ProgramProfileOGL::GetProfileFor(ShaderC
   }
 
   if (aConfig.mFeatures & ENABLE_MASK_2D ||
       aConfig.mFeatures & ENABLE_MASK_3D) {
     fs << "varying vec3 vMaskCoord;" << endl;
     fs << "uniform sampler2D uMaskTexture;" << endl;
   }
 
+  if (aConfig.mFeatures & ENABLE_DEAA) {
+    fs << "uniform vec3 uSSEdges[4];" << endl;
+  }
+
   if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
     fs << "vec4 sample(vec2 coord) {" << endl;
     fs << "  vec4 color;" << endl;
     if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
       fs << "  COLOR_PRECISION float y = texture2D(uYTexture, coord).r;" << endl;
       fs << "  COLOR_PRECISION float cb = texture2D(uCbTexture, coord).r;" << endl;
       fs << "  COLOR_PRECISION float cr = texture2D(uCrTexture, coord).r;" << endl;
 
@@ -348,16 +418,26 @@ For [0,1] instead of [0,255], and to 5 p
     }
     if (aConfig.mFeatures & ENABLE_OPACITY) {
       fs << "  color *= uLayerOpacity;" << endl;
     }
     if (aConfig.mFeatures & ENABLE_PREMULTIPLY) {
       fs << " color.rgb *= color.a;" << endl;
     }
   }
+  if (aConfig.mFeatures & ENABLE_DEAA) {
+    // Calculate the sub-pixel coverage of the pixel and modulate its opacity
+    // by that amount to perform DEAA.
+    fs << "  vec3 ssPos = vec3(gl_FragCoord.xy, 1.0);" << endl;
+    fs << "  float deaaCoverage = clamp(dot(uSSEdges[0], ssPos), 0.0, 1.0);" << endl;
+    fs << "  deaaCoverage *= clamp(dot(uSSEdges[1], ssPos), 0.0, 1.0);" << endl;
+    fs << "  deaaCoverage *= clamp(dot(uSSEdges[2], ssPos), 0.0, 1.0);" << endl;
+    fs << "  deaaCoverage *= clamp(dot(uSSEdges[3], ssPos), 0.0, 1.0);" << endl;
+    fs << "  color *= deaaCoverage;" << endl;
+  }
   if (aConfig.mFeatures & ENABLE_MASK_3D) {
     fs << "  vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;" << endl;
     fs << "  COLOR_PRECISION float mask = texture2D(uMaskTexture, maskCoords).r;" << endl;
     fs << "  color *= mask;" << endl;
   } else if (aConfig.mFeatures & ENABLE_MASK_2D) {
     fs << "  COLOR_PRECISION float mask = texture2D(uMaskTexture, vMaskCoord.xy).r;" << endl;
     fs << "  color *= mask;" << endl;
   } else {
--- a/gfx/layers/opengl/OGLShaderProgram.h
+++ b/gfx/layers/opengl/OGLShaderProgram.h
@@ -35,26 +35,28 @@ enum ShaderFeatures {
   ENABLE_TEXTURE_COMPONENT_ALPHA=0x10,
   ENABLE_TEXTURE_NO_ALPHA=0x20,
   ENABLE_TEXTURE_RB_SWAP=0x40,
   ENABLE_OPACITY=0x80,
   ENABLE_BLUR=0x100,
   ENABLE_COLOR_MATRIX=0x200,
   ENABLE_MASK_2D=0x400,
   ENABLE_MASK_3D=0x800,
-  ENABLE_PREMULTIPLY=0x1000
+  ENABLE_PREMULTIPLY=0x1000,
+  ENABLE_DEAA=0x2000
 };
 
 class KnownUniform {
 public:
   // this needs to be kept in sync with strings in 'AddUniforms'
   enum KnownUniformName {
     NotAKnownUniform = -1,
 
     LayerTransform = 0,
+    LayerTransformInverse,
     MaskTransform,
     LayerRects,
     MatrixProj,
     TextureTransform,
     TextureRects,
     RenderTargetOffset,
     LayerOpacity,
     Texture,
@@ -68,16 +70,19 @@ public:
     TexCoordMultiplier,
     TexturePass2,
     ColorMatrix,
     ColorMatrixVector,
     BlurRadius,
     BlurOffset,
     BlurAlpha,
     BlurGaussianKernel,
+    SSEdges,
+    ViewportSize,
+    VisibleCenter,
 
     KnownUniformCount
   };
 
   KnownUniform()
   {
     mName = NotAKnownUniform;
     mNameString = nullptr;
@@ -158,16 +163,40 @@ public:
 
     if (memcmp(mValue.f16v, fp, sizeof(float) * cnt) != 0) {
       memcpy(mValue.f16v, fp, sizeof(float) * cnt);
       return true;
     }
     return false;
   }
 
+  bool UpdateArrayUniform(int cnt, const gfx::Point3D* points) {
+    if (mLocation == -1) return false;
+    if (cnt > 4) {
+      return false;
+    }
+
+    float fp[12];
+    float *d = fp;
+    for(int i=0; i < cnt; i++) {
+      // Note: Do not want to make assumptions about .x, .y, .z member packing.
+      // If gfx::Point3D is updated to make this guarantee, SIMD optimizations
+      // may be possible
+      *d++ = points[i].x;
+      *d++ = points[i].y;
+      *d++ = points[i].z;
+    }
+
+    if (memcmp(mValue.f16v, fp, sizeof(float) * cnt * 3) != 0) {
+      memcpy(mValue.f16v, fp, sizeof(float) * cnt * 3);
+      return true;
+    }
+    return false;
+  }
+
   KnownUniformName mName;
   const char *mNameString;
   int32_t mLocation;
 
   union {
     int i1;
     float f1;
     float f16v[16];
@@ -187,16 +216,17 @@ public:
   void SetOpacity(bool aEnabled);
   void SetYCbCr(bool aEnabled);
   void SetComponentAlpha(bool aEnabled);
   void SetColorMatrix(bool aEnabled);
   void SetBlur(bool aEnabled);
   void SetMask2D(bool aEnabled);
   void SetMask3D(bool aEnabled);
   void SetPremultiply(bool aEnabled);
+  void SetDEAA(bool aEnabled);
 
   bool operator< (const ShaderConfigOGL& other) const {
     return mFeatures < other.mFeatures;
   }
 
 public:
   void SetFeature(int aBitmask, bool aState) {
     if (aState)
@@ -298,20 +328,38 @@ public:
    * The following set of methods set a uniform argument to the shader program.
    * Not all uniforms may be set for all programs, and such uses will throw
    * an assertion.
    */
   void SetLayerTransform(const gfx::Matrix4x4& aMatrix) {
     SetMatrixUniform(KnownUniform::LayerTransform, aMatrix);
   }
 
+  void SetLayerTransformInverse(const gfx::Matrix4x4& aMatrix) {
+    SetMatrixUniform(KnownUniform::LayerTransformInverse, aMatrix);
+  }
+
   void SetMaskLayerTransform(const gfx::Matrix4x4& aMatrix) {
     SetMatrixUniform(KnownUniform::MaskTransform, aMatrix);
   }
 
+  void SetDEAAEdges(const gfx::Point3D* aEdges) {
+    SetArrayUniform(KnownUniform::SSEdges, 4, aEdges);
+  }
+
+  void SetViewportSize(const gfx::IntSize& aSize) {
+    float vals[2] = { (float)aSize.width, (float)aSize.height };
+    SetUniform(KnownUniform::ViewportSize, 2, vals);
+  }
+
+  void SetVisibleCenter(const gfx::Point& aVisibleCenter) {
+    float vals[2] = { aVisibleCenter.x, aVisibleCenter.y };
+    SetUniform(KnownUniform::VisibleCenter, 2, vals);
+  }
+
   void SetLayerRects(const gfx::Rect* aRects) {
     float vals[16] = { aRects[0].x, aRects[0].y, aRects[0].width, aRects[0].height,
                        aRects[1].x, aRects[1].y, aRects[1].width, aRects[1].height,
                        aRects[2].x, aRects[2].y, aRects[2].width, aRects[2].height,
                        aRects[3].x, aRects[3].y, aRects[3].width, aRects[3].height };
     SetUniform(KnownUniform::LayerRects, 16, vals);
   }
 
@@ -328,23 +376,23 @@ public:
     float vals[16] = { aRects[0].x, aRects[0].y, aRects[0].width, aRects[0].height,
                        aRects[1].x, aRects[1].y, aRects[1].width, aRects[1].height,
                        aRects[2].x, aRects[2].y, aRects[2].width, aRects[2].height,
                        aRects[3].x, aRects[3].y, aRects[3].width, aRects[3].height };
     SetUniform(KnownUniform::TextureRects, 16, vals);
   }
 
   void SetRenderOffset(const nsIntPoint& aOffset) {
-    float vals[4] = { float(aOffset.x), float(aOffset.y), 0.0f, 0.0f };
-    SetUniform(KnownUniform::RenderTargetOffset, 4, vals);
+    float vals[4] = { float(aOffset.x), float(aOffset.y) };
+    SetUniform(KnownUniform::RenderTargetOffset, 2, vals);
   }
 
   void SetRenderOffset(float aX, float aY) {
-    float vals[4] = { aX, aY, 0.0f, 0.0f };
-    SetUniform(KnownUniform::RenderTargetOffset, 4, vals);
+    float vals[2] = { aX, aY };
+    SetUniform(KnownUniform::RenderTargetOffset, 2, vals);
   }
 
   void SetLayerOpacity(float aOpacity) {
     SetUniform(KnownUniform::LayerOpacity, aOpacity);
   }
 
   void SetTextureUnit(GLint aUnit) {
     SetUniform(KnownUniform::Texture, aUnit);
@@ -492,16 +540,27 @@ protected:
     NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
 
     KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
     if (ku.UpdateArrayUniform(aLength, aFloatValues)) {
       mGL->fUniform1fv(ku.mLocation, aLength, ku.mValue.f16v);
     }
   }
 
+  void SetArrayUniform(KnownUniform::KnownUniformName aKnownUniform, int aLength, const gfx::Point3D *aPointValues)
+  {
+    ASSERT_THIS_PROGRAM;
+    NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
+
+    KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
+    if (ku.UpdateArrayUniform(aLength, aPointValues)) {
+      mGL->fUniform3fv(ku.mLocation, aLength, ku.mValue.f16v);
+    }
+  }
+
   void SetUniform(KnownUniform::KnownUniformName aKnownUniform, GLint aIntValue) {
     ASSERT_THIS_PROGRAM;
     NS_ASSERTION(aKnownUniform >= 0 && aKnownUniform < KnownUniform::KnownUniformCount, "Invalid known uniform");
 
     KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
     if (ku.UpdateUniform(aIntValue)) {
       mGL->fUniform1i(ku.mLocation, aIntValue);
     }
--- a/gfx/src/FilterSupport.cpp
+++ b/gfx/src/FilterSupport.cpp
@@ -97,131 +97,164 @@ namespace gfx {
 // Some convenience FilterNode creation functions.
 
 namespace FilterWrappers {
 
   static TemporaryRef<FilterNode>
   Unpremultiply(DrawTarget* aDT, FilterNode* aInput)
   {
     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::UNPREMULTIPLY);
-    filter->SetInput(IN_UNPREMULTIPLY_IN, aInput);
-    return filter.forget();
+    if (filter) {
+      filter->SetInput(IN_UNPREMULTIPLY_IN, aInput);
+      return filter.forget();
+    }
+    return nullptr;
   }
 
   static TemporaryRef<FilterNode>
   Premultiply(DrawTarget* aDT, FilterNode* aInput)
   {
     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::PREMULTIPLY);
-    filter->SetInput(IN_PREMULTIPLY_IN, aInput);
-    return filter.forget();
+    if (filter) {
+      filter->SetInput(IN_PREMULTIPLY_IN, aInput);
+      return filter.forget();
+    }
+    return nullptr;
   }
 
   static TemporaryRef<FilterNode>
   LinearRGBToSRGB(DrawTarget* aDT, FilterNode* aInput)
   {
     RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, glinearRGBTosRGBMap, 256);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, glinearRGBTosRGBMap, 256);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, glinearRGBTosRGBMap, 256);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
-    transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
-    return transfer.forget();
+    if (transfer) {
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, glinearRGBTosRGBMap, 256);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, glinearRGBTosRGBMap, 256);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, glinearRGBTosRGBMap, 256);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
+      transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
+      return transfer.forget();
+    }
+    return nullptr;
   }
 
   static TemporaryRef<FilterNode>
   SRGBToLinearRGB(DrawTarget* aDT, FilterNode* aInput)
   {
     RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, gsRGBToLinearRGBMap, 256);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, gsRGBToLinearRGBMap, 256);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, gsRGBToLinearRGBMap, 256);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
-    transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
-    return transfer.forget();
+    if (transfer) {
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, gsRGBToLinearRGBMap, 256);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, gsRGBToLinearRGBMap, 256);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, gsRGBToLinearRGBMap, 256);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
+      transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
+      return transfer.forget();
+    }
+    return nullptr;
   }
 
   static TemporaryRef<FilterNode>
   Crop(DrawTarget* aDT, FilterNode* aInputFilter, const IntRect& aRect)
   {
     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CROP);
-    filter->SetAttribute(ATT_CROP_RECT, Rect(aRect));
-    filter->SetInput(IN_CROP_IN, aInputFilter);
-    return filter.forget();
+    if (filter) {
+      filter->SetAttribute(ATT_CROP_RECT, Rect(aRect));
+      filter->SetInput(IN_CROP_IN, aInputFilter);
+      return filter.forget();
+    }
+    return nullptr;
   }
 
   static TemporaryRef<FilterNode>
   Offset(DrawTarget* aDT, FilterNode* aInputFilter, const IntPoint& aOffset)
   {
     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
-    filter->SetAttribute(ATT_TRANSFORM_MATRIX, Matrix::Translation(aOffset.x, aOffset.y));
-    filter->SetInput(IN_TRANSFORM_IN, aInputFilter);
-    return filter.forget();
+    if (filter) {
+      filter->SetAttribute(ATT_TRANSFORM_MATRIX, Matrix::Translation(aOffset.x, aOffset.y));
+      filter->SetInput(IN_TRANSFORM_IN, aInputFilter);
+      return filter.forget();
+    }
+    return nullptr;
   }
 
   static TemporaryRef<FilterNode>
   GaussianBlur(DrawTarget* aDT, FilterNode* aInputFilter, const Size& aStdDeviation)
   {
     float stdX = float(std::min(aStdDeviation.width, kMaxStdDeviation));
     float stdY = float(std::min(aStdDeviation.height, kMaxStdDeviation));
     if (stdX == stdY) {
       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::GAUSSIAN_BLUR);
-      filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, stdX);
-      filter->SetInput(IN_GAUSSIAN_BLUR_IN, aInputFilter);
-      return filter.forget();
+      if (filter) {
+        filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, stdX);
+        filter->SetInput(IN_GAUSSIAN_BLUR_IN, aInputFilter);
+        return filter.forget();
+      }
+      return nullptr;
     }
     RefPtr<FilterNode> filterH = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
     RefPtr<FilterNode> filterV = aDT->CreateFilter(FilterType::DIRECTIONAL_BLUR);
-    filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_X);
-    filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdX);
-    filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_Y);
-    filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdY);
-    filterH->SetInput(IN_DIRECTIONAL_BLUR_IN, aInputFilter);
-    filterV->SetInput(IN_DIRECTIONAL_BLUR_IN, filterH);
-    return filterV.forget();
+    if (filterH && filterV) {
+      filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_X);
+      filterH->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdX);
+      filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_DIRECTION, (uint32_t)BLUR_DIRECTION_Y);
+      filterV->SetAttribute(ATT_DIRECTIONAL_BLUR_STD_DEVIATION, stdY);
+      filterH->SetInput(IN_DIRECTIONAL_BLUR_IN, aInputFilter);
+      filterV->SetInput(IN_DIRECTIONAL_BLUR_IN, filterH);
+      return filterV.forget();
+    }
+    return nullptr;
   }
 
   static TemporaryRef<FilterNode>
   Clear(DrawTarget* aDT)
   {
     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
-    filter->SetAttribute(ATT_FLOOD_COLOR, Color(0,0,0,0));
-    return filter.forget();
+    if (filter) {
+      filter->SetAttribute(ATT_FLOOD_COLOR, Color(0, 0, 0, 0));
+      return filter.forget();
+    }
+    return nullptr;
   }
 
   static TemporaryRef<FilterNode>
   ForSurface(DrawTarget* aDT, SourceSurface* aSurface,
              const IntPoint& aSurfacePosition)
   {
     RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TRANSFORM);
-    filter->SetAttribute(ATT_TRANSFORM_MATRIX,
-      Matrix::Translation(aSurfacePosition.x, aSurfacePosition.y));
-    filter->SetInput(IN_TRANSFORM_IN, aSurface);
-    return filter.forget();
+    if (filter) {
+      filter->SetAttribute(ATT_TRANSFORM_MATRIX,
+        Matrix::Translation(aSurfacePosition.x, aSurfacePosition.y));
+      filter->SetInput(IN_TRANSFORM_IN, aSurface);
+      return filter.forget();
+    }
+    return nullptr;
   }
 
   static TemporaryRef<FilterNode>
   ToAlpha(DrawTarget* aDT, FilterNode* aInput)
   {
     float zero = 0.0f;
     RefPtr<FilterNode> transfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, &zero, 1);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, &zero, 1);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, &zero, 1);
-    transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
-    transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
-    return transfer.forget();
+    if (transfer) {
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, &zero, 1);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, &zero, 1);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, &zero, 1);
+      transfer->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true);
+      transfer->SetInput(IN_DISCRETE_TRANSFER_IN, aInput);
+      return transfer.forget();
+    }
+    return nullptr;
   }
 
 }
 
 // A class that wraps a FilterNode and handles conversion between different
 // color models. Create FilterCachedColorModels with your original filter and
 // the color model that this filter outputs in natively, and then call
 // ->ForColorModel(colorModel) in order to get a FilterNode which outputs to
@@ -530,16 +563,19 @@ ConvertComponentTransferFunctionToFilter
   {
     const nsTArray<float>& tableValues =
       aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
     if (tableValues.Length() < 2)
       return;
 
     if (!aTableTransfer) {
       aTableTransfer = aDT->CreateFilter(FilterType::TABLE_TRANSFER);
+      if (!aTableTransfer) {
+        return;
+      }
       DisableAllTransfers(aTableTransfer);
     }
     filter = aTableTransfer;
     static const TableTransferAtts tableAtt[4] = {
       ATT_TABLE_TRANSFER_TABLE_R,
       ATT_TABLE_TRANSFER_TABLE_G,
       ATT_TABLE_TRANSFER_TABLE_B,
       ATT_TABLE_TRANSFER_TABLE_A
@@ -553,16 +589,19 @@ ConvertComponentTransferFunctionToFilter
   {
     const nsTArray<float>& tableValues =
       aFunctionAttributes.GetFloats(eComponentTransferFunctionTableValues);
     if (tableValues.Length() < 1)
       return;
 
     if (!aDiscreteTransfer) {
       aDiscreteTransfer = aDT->CreateFilter(FilterType::DISCRETE_TRANSFER);
+      if (!aDiscreteTransfer) {
+        return;
+      }
       DisableAllTransfers(aDiscreteTransfer);
     }
     filter = aDiscreteTransfer;
     static const DiscreteTransferAtts tableAtt[4] = {
       ATT_DISCRETE_TRANSFER_TABLE_R,
       ATT_DISCRETE_TRANSFER_TABLE_G,
       ATT_DISCRETE_TRANSFER_TABLE_B,
       ATT_DISCRETE_TRANSFER_TABLE_A
@@ -584,16 +623,19 @@ ConvertComponentTransferFunctionToFilter
     static const LinearTransferAtts interceptAtt[4] = {
       ATT_LINEAR_TRANSFER_INTERCEPT_R,
       ATT_LINEAR_TRANSFER_INTERCEPT_G,
       ATT_LINEAR_TRANSFER_INTERCEPT_B,
       ATT_LINEAR_TRANSFER_INTERCEPT_A
     };
     if (!aLinearTransfer) {
       aLinearTransfer = aDT->CreateFilter(FilterType::LINEAR_TRANSFER);
+      if (!aLinearTransfer) {
+        return;
+      }
       DisableAllTransfers(aLinearTransfer);
     }
     filter = aLinearTransfer;
     filter->SetAttribute(disableAtt[aChannel], false);
     float slope = aFunctionAttributes.GetFloat(eComponentTransferFunctionSlope);
     float intercept = aFunctionAttributes.GetFloat(eComponentTransferFunctionIntercept);
     filter->SetAttribute(slopeAtt[aChannel], slope);
     filter->SetAttribute(interceptAtt[aChannel], intercept);
@@ -617,16 +659,19 @@ ConvertComponentTransferFunctionToFilter
     static const GammaTransferAtts offsetAtt[4] = {
       ATT_GAMMA_TRANSFER_OFFSET_R,
       ATT_GAMMA_TRANSFER_OFFSET_G,
       ATT_GAMMA_TRANSFER_OFFSET_B,
       ATT_GAMMA_TRANSFER_OFFSET_A
     };
     if (!aGammaTransfer) {
       aGammaTransfer = aDT->CreateFilter(FilterType::GAMMA_TRANSFER);
+      if (!aGammaTransfer) {
+        return;
+      }
       DisableAllTransfers(aGammaTransfer);
     }
     filter = aGammaTransfer;
     filter->SetAttribute(disableAtt[aChannel], false);
     float amplitude = aFunctionAttributes.GetFloat(eComponentTransferFunctionAmplitude);
     float exponent = aFunctionAttributes.GetFloat(eComponentTransferFunctionExponent);
     float offset = aFunctionAttributes.GetFloat(eComponentTransferFunctionOffset);
     filter->SetAttribute(amplitudeAtt[aChannel], amplitude);
@@ -667,20 +712,26 @@ FilterNodeFromPrimitiveDescription(const
     {
       uint32_t mode = atts.GetUint(eBlendBlendmode);
       RefPtr<FilterNode> filter;
       if (mode == SVG_FEBLEND_MODE_UNKNOWN) {
         return nullptr;
       }
       if (mode == SVG_FEBLEND_MODE_NORMAL) {
         filter = aDT->CreateFilter(FilterType::COMPOSITE);
+        if (!filter) {
+          return nullptr;
+        }
         filter->SetInput(IN_COMPOSITE_IN_START, aSources[1]);
         filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
       } else {
         filter = aDT->CreateFilter(FilterType::BLEND);
+        if (!filter) {
+          return nullptr;
+        }
         static const uint8_t blendModes[SVG_FEBLEND_MODE_LUMINOSITY + 1] = {
           0,
           0,
           BLEND_MODE_MULTIPLY,
           BLEND_MODE_SCREEN,
           BLEND_MODE_DARKEN,
           BLEND_MODE_LIGHTEN,
           BLEND_MODE_OVERLAY,
@@ -712,16 +763,19 @@ FilterNodeFromPrimitiveDescription(const
         return filter.forget();
       }
       Matrix5x4 matrix(colorMatrix[0], colorMatrix[5], colorMatrix[10],  colorMatrix[15],
                        colorMatrix[1], colorMatrix[6], colorMatrix[11],  colorMatrix[16],
                        colorMatrix[2], colorMatrix[7], colorMatrix[12],  colorMatrix[17],
                        colorMatrix[3], colorMatrix[8], colorMatrix[13],  colorMatrix[18],
                        colorMatrix[4], colorMatrix[9], colorMatrix[14],  colorMatrix[19]);
       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COLOR_MATRIX);
+      if (!filter) {
+        return nullptr;
+      }
       filter->SetAttribute(ATT_COLOR_MATRIX_MATRIX, matrix);
       filter->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE, (uint32_t)ALPHA_MODE_STRAIGHT);
       filter->SetInput(IN_COLOR_MATRIX_IN, aSources[0]);
       return filter.forget();
     }
 
     case PrimitiveType::Morphology:
     {
@@ -739,33 +793,42 @@ FilterNodeFromPrimitiveDescription(const
       // Clamp radii to prevent completely insane values:
       rx = std::min(rx, kMorphologyMaxRadius);
       ry = std::min(ry, kMorphologyMaxRadius);
 
       MorphologyOperator op = atts.GetUint(eMorphologyOperator) == SVG_OPERATOR_ERODE ?
         MORPHOLOGY_OPERATOR_ERODE : MORPHOLOGY_OPERATOR_DILATE;
 
       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::MORPHOLOGY);
+      if (!filter) {
+        return nullptr;
+      }
       filter->SetAttribute(ATT_MORPHOLOGY_RADII, IntSize(rx, ry));
       filter->SetAttribute(ATT_MORPHOLOGY_OPERATOR, (uint32_t)op);
       filter->SetInput(IN_MORPHOLOGY_IN, aSources[0]);
       return filter.forget();
     }
 
     case PrimitiveType::Flood:
     {
       Color color = atts.GetColor(eFloodColor);
       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::FLOOD);
+      if (!filter) {
+        return nullptr;
+      }
       filter->SetAttribute(ATT_FLOOD_COLOR, color);
       return filter.forget();
     }
 
     case PrimitiveType::Tile:
     {
       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TILE);
+      if (!filter) {
+        return nullptr;
+      }
       filter->SetAttribute(ATT_TILE_SOURCE_RECT, aSourceRegions[0]);
       filter->SetInput(IN_TILE_IN, aSources[0]);
       return filter.forget();
     }
 
     case PrimitiveType::ComponentTransfer:
     {
       RefPtr<FilterNode> filters[4]; // one for each FILTER_*_TRANSFER type
@@ -792,16 +855,19 @@ FilterNodeFromPrimitiveDescription(const
       }
 
       return lastFilter.forget();
     }
 
     case PrimitiveType::ConvolveMatrix:
     {
       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CONVOLVE_MATRIX);
+      if (!filter) {
+        return nullptr;
+      }
       filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE, atts.GetIntSize(eConvolveMatrixKernelSize));
       const nsTArray<float>& matrix = atts.GetFloats(eConvolveMatrixKernelMatrix);
       filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX,
                            matrix.Elements(), matrix.Length());
       filter->SetAttribute(ATT_CONVOLVE_MATRIX_DIVISOR,
                            atts.GetFloat(eConvolveMatrixDivisor));
       filter->SetAttribute(ATT_CONVOLVE_MATRIX_BIAS,
                            atts.GetFloat(eConvolveMatrixBias));
@@ -829,16 +895,19 @@ FilterNodeFromPrimitiveDescription(const
     {
       return FilterWrappers::Offset(aDT, aSources[0],
                                     atts.GetIntPoint(eOffsetOffset));
     }
 
     case PrimitiveType::DisplacementMap:
     {
       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::DISPLACEMENT_MAP);
+      if (!filter) {
+        return nullptr;
+      }
       filter->SetAttribute(ATT_DISPLACEMENT_MAP_SCALE,
                            atts.GetFloat(eDisplacementMapScale));
       static const uint8_t channel[SVG_CHANNEL_A+1] = {
         COLOR_CHANNEL_R, // SVG_CHANNEL_UNKNOWN
         COLOR_CHANNEL_R, // SVG_CHANNEL_R
         COLOR_CHANNEL_G, // SVG_CHANNEL_G
         COLOR_CHANNEL_B, // SVG_CHANNEL_B
         COLOR_CHANNEL_A  // SVG_CHANNEL_A
@@ -850,16 +919,19 @@ FilterNodeFromPrimitiveDescription(const
       filter->SetInput(IN_DISPLACEMENT_MAP_IN, aSources[0]);
       filter->SetInput(IN_DISPLACEMENT_MAP_IN2, aSources[1]);
       return filter.forget();
     }
 
     case PrimitiveType::Turbulence:
     {
       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::TURBULENCE);
+      if (!filter) {
+        return nullptr;
+      }
       filter->SetAttribute(ATT_TURBULENCE_BASE_FREQUENCY,
                            atts.GetSize(eTurbulenceBaseFrequency));
       filter->SetAttribute(ATT_TURBULENCE_NUM_OCTAVES,
                            atts.GetUint(eTurbulenceNumOctaves));
       filter->SetAttribute(ATT_TURBULENCE_STITCHABLE,
                            atts.GetBool(eTurbulenceStitchable));
       filter->SetAttribute(ATT_TURBULENCE_SEED,
                            (uint32_t)atts.GetFloat(eTurbulenceSeed));
@@ -876,23 +948,29 @@ FilterNodeFromPrimitiveDescription(const
     }
 
     case PrimitiveType::Composite:
     {
       RefPtr<FilterNode> filter;
       uint32_t op = atts.GetUint(eCompositeOperator);
       if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
         filter = aDT->CreateFilter(FilterType::ARITHMETIC_COMBINE);
+        if (!filter) {
+          return nullptr;
+        }
         const nsTArray<float>& coefficients = atts.GetFloats(eCompositeCoefficients);
         filter->SetAttribute(ATT_ARITHMETIC_COMBINE_COEFFICIENTS,
                              coefficients.Elements(), coefficients.Length());
         filter->SetInput(IN_ARITHMETIC_COMBINE_IN, aSources[0]);
         filter->SetInput(IN_ARITHMETIC_COMBINE_IN2, aSources[1]);
       } else {
         filter = aDT->CreateFilter(FilterType::COMPOSITE);
+        if (!filter) {
+          return nullptr;
+        }
         static const uint8_t operators[SVG_FECOMPOSITE_OPERATOR_ARITHMETIC] = {
           COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_UNKNOWN
           COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_OVER
           COMPOSITE_OPERATOR_IN,   // SVG_FECOMPOSITE_OPERATOR_IN
           COMPOSITE_OPERATOR_OUT,  // SVG_FECOMPOSITE_OPERATOR_OUT
           COMPOSITE_OPERATOR_ATOP, // SVG_FECOMPOSITE_OPERATOR_ATOP
           COMPOSITE_OPERATOR_XOR   // SVG_FECOMPOSITE_OPERATOR_XOR
         };
@@ -908,16 +986,19 @@ FilterNodeFromPrimitiveDescription(const
       if (aSources.Length() == 0) {
         return nullptr;
       }
       if (aSources.Length() == 1) {
         RefPtr<FilterNode> filter(aSources[0]);
         return filter.forget();
       }
       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
+      if (!filter) {
+        return nullptr;
+      }
       filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
       for (size_t i = 0; i < aSources.Length(); i++) {
         filter->SetInput(IN_COMPOSITE_IN_START + i, aSources[i]);
       }
       return filter.forget();
     }
 
     case PrimitiveType::GaussianBlur:
@@ -929,31 +1010,40 @@ FilterNodeFromPrimitiveDescription(const
     case PrimitiveType::DropShadow:
     {
       RefPtr<FilterNode> alpha = FilterWrappers::ToAlpha(aDT, aSources[0]);
       RefPtr<FilterNode> blur = FilterWrappers::GaussianBlur(aDT, alpha,
                                   atts.GetSize(eDropShadowStdDeviation));
       RefPtr<FilterNode> offsetBlur = FilterWrappers::Offset(aDT, blur,
                                         atts.GetIntPoint(eDropShadowOffset));
       RefPtr<FilterNode> flood = aDT->CreateFilter(FilterType::FLOOD);
+      if (!flood) {
+        return nullptr;
+      }
       Color color = atts.GetColor(eDropShadowColor);
       if (aDescription.InputColorSpace(0) == ColorSpace::LinearRGB) {
         color = Color(gsRGBToLinearRGBMap[uint8_t(color.r * 255)],
                       gsRGBToLinearRGBMap[uint8_t(color.g * 255)],
                       gsRGBToLinearRGBMap[uint8_t(color.b * 255)],
                       color.a);
       }
       flood->SetAttribute(ATT_FLOOD_COLOR, color);
 
       RefPtr<FilterNode> composite = aDT->CreateFilter(FilterType::COMPOSITE);
+      if (!composite) {
+        return nullptr;
+      }
       composite->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_IN);
       composite->SetInput(IN_COMPOSITE_IN_START, offsetBlur);
       composite->SetInput(IN_COMPOSITE_IN_START + 1, flood);
 
       RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::COMPOSITE);
+      if (!filter) {
+        return nullptr;
+      }
       filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER);
       filter->SetInput(IN_COMPOSITE_IN_START, composite);
       filter->SetInput(IN_COMPOSITE_IN_START + 1, aSources[0]);
       return filter.forget();
     }
 
     case PrimitiveType::DiffuseLighting:
     case PrimitiveType::SpecularLighting:
@@ -976,16 +1066,19 @@ FilterNodeFromPrimitiveDescription(const
       }
 
       static const FilterType filterType[2][DISTANT+1] = {
         { FilterType::POINT_DIFFUSE, FilterType::SPOT_DIFFUSE, FilterType::DISTANT_DIFFUSE },
         { FilterType::POINT_SPECULAR, FilterType::SPOT_SPECULAR, FilterType::DISTANT_SPECULAR }
       };
       RefPtr<FilterNode> filter =
         aDT->CreateFilter(filterType[isSpecular][lightType]);
+      if (!filter) {
+        return nullptr;
+      }
 
       filter->SetAttribute(ATT_LIGHTING_COLOR,
                            atts.GetColor(eLightingColor));
       filter->SetAttribute(ATT_LIGHTING_SURFACE_SCALE,
                            atts.GetFloat(eLightingSurfaceScale));
       filter->SetAttribute(ATT_LIGHTING_KERNEL_UNIT_LENGTH,
                            atts.GetSize(eLightingKernelUnitLength));
 
@@ -1035,16 +1128,19 @@ FilterNodeFromPrimitiveDescription(const
       }
 
       // Pull the image from the additional image list using the index that's
       // stored in the primitive description.
       RefPtr<SourceSurface> inputImage =
         aInputImages[atts.GetUint(eImageInputIndex)];
 
       RefPtr<FilterNode> transform = aDT->CreateFilter(FilterType::TRANSFORM);
+      if (!transform) {
+        return nullptr;
+      }
       transform->SetInput(IN_TRANSFORM_IN, inputImage);
       transform->SetAttribute(ATT_TRANSFORM_MATRIX, TM);
       transform->SetAttribute(ATT_TRANSFORM_FILTER, atts.GetUint(eImageFilter));
       return transform.forget();
     }
 
     case PrimitiveType::ToAlpha:
     {
@@ -1245,17 +1341,20 @@ FilterSupport::RenderFilterDescription(D
                                        nsTArray<RefPtr<SourceSurface>>& aAdditionalImages,
                                        const Point& aDestPoint,
                                        const DrawOptions& aOptions)
 {
   RefPtr<FilterNode> resultFilter =
     FilterNodeGraphFromDescription(aDT, aFilter, aRenderRect,
                                    aSourceGraphic, aSourceGraphicRect, aFillPaint, aFillPaintRect,
                                    aStrokePaint, aStrokePaintRect, aAdditionalImages);
-
+  if (!resultFilter) {
+    gfxWarning() << "Filter is NULL.";
+    return;
+  }
   aDT->DrawFilter(resultFilter, aRenderRect, aDestPoint, aOptions);
 }
 
 static nsIntRegion
 UnionOfRegions(const nsTArray<nsIntRegion>& aRegions)
 {
   nsIntRegion result;
   for (size_t i = 0; i < aRegions.Length(); i++) {
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -1140,17 +1140,20 @@ gfxFcPlatformFontList::GetFontList(nsIAt
         aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("sans-serif"));
     if (serif)
         aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("serif"));
 }
 
 gfxFontFamily*
 gfxFcPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle)
 {
-    return FindGenericFamily(NS_LITERAL_STRING("serif"), nsGkAtoms::x_western);
+    // Get the default font by using a fake name to retrieve the first
+    // scalable font that fontconfig suggests for the given language.
+    return FindGenericFamily(NS_LITERAL_STRING("-moz-default"),
+                             aStyle->language);
 }
 
 gfxFontEntry*
 gfxFcPlatformFontList::LookupLocalFont(const nsAString& aFontName,
                                        uint16_t aWeight,
                                        int16_t aStretch,
                                        bool aItalic)
 {
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -288,16 +288,17 @@ private:
 #else
   // If MOZ_GFX_OPTIMIZE_MOBILE is not defined, we actually take the
   // preference value, defaulting to true.
   DECL_GFX_PREF(Once, "layers.componentalpha.enabled",         ComponentAlphaEnabled, bool, true);
 #endif
   DECL_GFX_PREF(Live, "layers.composer2d.enabled",             Composer2DCompositionEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.d3d11.disable-warp",             LayersD3D11DisableWARP, bool, false);
   DECL_GFX_PREF(Once, "layers.d3d11.force-warp",               LayersD3D11ForceWARP, bool, false);
+  DECL_GFX_PREF(Live, "layers.deaa.enabled",                   LayersDEAAEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.draw-bigimage-borders",          DrawBigImageBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.draw-borders",                   DrawLayerBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.draw-tile-borders",              DrawTileBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.draw-layer-info",                DrawLayerInfo, bool, false);
   DECL_GFX_PREF(Live, "layers.dump",                           LayersDump, bool, false);
   DECL_GFX_PREF(Live, "layers.dump-texture",                   LayersDumpTexture, bool, false);
 #ifdef MOZ_DUMP_PAINTING
   DECL_GFX_PREF(Live, "layers.dump-client-layers",             DumpClientLayers, bool, false);
--- a/ipc/app/moz.build
+++ b/ipc/app/moz.build
@@ -66,17 +66,17 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_
     USE_LIBS += [
         'mozsandbox',
     ]
 
     # gcc lto likes to put the top level asm in syscall.cc in a different partition
     # from the function using it which breaks the build.  Work around that by
     # forcing there to be only one partition.
     if '-flto' in CONFIG['OS_CXXFLAGS'] and not CONFIG['CLANG_CXX']:
-	LDFLAGS += ['--param lto-partitions=1']
+        LDFLAGS += ['--param lto-partitions=1']
 
 if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] == 'Darwin':
     USE_LIBS += [
         'mozsandbox',
     ]
 
 if CONFIG['_MSC_VER']:
     # Always enter a Windows program through wmain, whether or not we're
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -323,20 +323,26 @@ IsInsideNursery(const js::gc::Cell* cell
 }
 
 } /* namespace gc */
 } /* namespace js */
 
 namespace JS {
 
 static MOZ_ALWAYS_INLINE Zone*
-GetTenuredGCThingZone(void* thing)
+GetTenuredGCThingZone(GCCellPtr thing)
 {
-    MOZ_ASSERT(!js::gc::IsInsideNursery((js::gc::Cell*)thing));
-    return js::gc::detail::GetGCThingZone(uintptr_t(thing));
+    MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell()));
+    return js::gc::detail::GetGCThingZone(thing.unsafeAsUIntPtr());
+}
+
+static MOZ_ALWAYS_INLINE Zone*
+GetStringZone(JSString* str)
+{
+    return js::gc::detail::GetGCThingZone(uintptr_t(str));
 }
 
 extern JS_PUBLIC_API(Zone*)
 GetObjectZone(JSObject* obj);
 
 static MOZ_ALWAYS_INLINE bool
 ObjectIsTenured(JSObject* obj)
 {
@@ -379,17 +385,17 @@ namespace gc {
 
 static MOZ_ALWAYS_INLINE bool
 IsIncrementalBarrierNeededOnTenuredGCThing(JS::shadow::Runtime* rt, const JS::GCCellPtr thing)
 {
     MOZ_ASSERT(thing);
     MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell()));
     if (!rt->needsIncrementalBarrier())
         return false;
-    JS::Zone* zone = JS::GetTenuredGCThingZone(thing.asCell());
+    JS::Zone* zone = JS::GetTenuredGCThingZone(thing);
     return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier();
 }
 
 /*
  * Create an object providing access to the garbage collector's internal notion
  * of the current state of memory (both GC heap memory and GCthing-controlled
  * malloc memory.
  */
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -228,101 +228,66 @@ js::Allocate(ExclusiveContext* cx)
     template type* js::Allocate<type, CanGC>(ExclusiveContext* cx);
 FOR_ALL_NON_OBJECT_GC_LAYOUTS(DECL_ALLOCATOR_INSTANCES)
 #undef DECL_ALLOCATOR_INSTANCES
 
 template <typename T, AllowGC allowGC>
 /* static */ T*
 GCRuntime::tryNewTenuredThing(ExclusiveContext* cx, AllocKind kind, size_t thingSize)
 {
+    // Bump allocate in the arena's current free-list span.
     T* t = reinterpret_cast<T*>(cx->arenas()->allocateFromFreeList(kind, thingSize));
-    if (!t)
-        t = reinterpret_cast<T*>(refillFreeListFromAnyThread<allowGC>(cx, kind, thingSize));
+    if (MOZ_UNLIKELY(!t)) {
+        // Get the next available free list and allocate out of it. This may
+        // acquire a new arena, which will lock the chunk list. If there are no
+        // chunks available it may also allocate new memory directly.
+        t = reinterpret_cast<T*>(refillFreeListFromAnyThread(cx, kind, thingSize));
+
+        if (MOZ_UNLIKELY(!t && allowGC && cx->isJSContext())) {
+            // We have no memory available for a new chunk; perform an
+            // all-compartments, non-incremental, shrinking GC and wait for
+            // sweeping to finish.
+            JSRuntime *rt = cx->asJSContext()->runtime();
+            JS::PrepareForFullGC(rt);
+            AutoKeepAtoms keepAtoms(cx->perThreadData);
+            rt->gc.gc(GC_SHRINK, JS::gcreason::LAST_DITCH);
+            rt->gc.waitBackgroundSweepOrAllocEnd();
+
+            t = tryNewTenuredThing<T, NoGC>(cx, kind, thingSize);
+            if (!t)
+                ReportOutOfMemory(cx);
+        }
+    }
 
     checkIncrementalZoneState(cx, t);
     TraceTenuredAlloc(t, kind);
     return t;
 }
 
-template <AllowGC allowGC>
 /* static */ void*
 GCRuntime::refillFreeListFromAnyThread(ExclusiveContext* cx, AllocKind thingKind, size_t thingSize)
 {
     MOZ_ASSERT(cx->arenas()->freeLists[thingKind].isEmpty());
 
     if (cx->isJSContext())
-        return refillFreeListFromMainThread<allowGC>(cx->asJSContext(), thingKind, thingSize);
+        return refillFreeListFromMainThread(cx->asJSContext(), thingKind, thingSize);
 
     return refillFreeListOffMainThread(cx, thingKind);
 }
 
-template <AllowGC allowGC>
 /* static */ void*
 GCRuntime::refillFreeListFromMainThread(JSContext* cx, AllocKind thingKind, size_t thingSize)
 {
-    JSRuntime* rt = cx->runtime();
-    MOZ_ASSERT(!rt->isHeapBusy(), "allocating while under GC");
-    MOZ_ASSERT_IF(allowGC, !rt->currentThreadHasExclusiveAccess());
-
-    // Try to allocate; synchronize with background GC threads if necessary.
-    void* thing = tryRefillFreeListFromMainThread(cx, thingKind);
-    if (MOZ_LIKELY(thing))
-        return thing;
-
-    // Perform a last-ditch GC to hopefully free up some memory.
-    {
-        // If we are doing a fallible allocation, percolate up the OOM
-        // instead of reporting it.
-        if (!allowGC)
-            return nullptr;
-
-        JS::PrepareForFullGC(rt);
-        AutoKeepAtoms keepAtoms(cx->perThreadData);
-        rt->gc.gc(GC_SHRINK, JS::gcreason::LAST_DITCH);
-    }
-
-    // Retry the allocation after the last-ditch GC.
-    // Note that due to GC callbacks we might already have allocated an arena
-    // for this thing kind!
-    thing = cx->arenas()->allocateFromFreeList(thingKind, thingSize);
-    if (!thing)
-        thing = tryRefillFreeListFromMainThread(cx, thingKind);
-    if (thing)
-        return thing;
-
-    // We are really just totally out of memory.
-    MOZ_ASSERT(allowGC, "A fallible allocation must not report OOM on failure.");
-    ReportOutOfMemory(cx);
-    return nullptr;
-}
-
-/* static */ void*
-GCRuntime::tryRefillFreeListFromMainThread(JSContext* cx, AllocKind thingKind)
-{
-    ArenaLists* arenas = cx->arenas();
-    Zone* zone = cx->zone();
+    ArenaLists *arenas = cx->arenas();
+    Zone *zone = cx->zone();
+    MOZ_ASSERT(!cx->runtime()->isHeapBusy(), "allocating while under GC");
 
     AutoMaybeStartBackgroundAllocation maybeStartBGAlloc;
 
-    void* thing = arenas->allocateFromArena(zone, thingKind, maybeStartBGAlloc);
-    if (MOZ_LIKELY(thing))
-        return thing;
-
-    // Even if allocateFromArena failed due to OOM, a background
-    // finalization or allocation task may be running freeing more memory
-    // or adding more available memory to our free pool; wait for them to
-    // finish, then try to allocate again in case they made more memory
-    // available.
-    cx->runtime()->gc.waitBackgroundSweepOrAllocEnd();
-
-    thing = arenas->allocateFromArena(zone, thingKind, maybeStartBGAlloc);
-    if (thing)
-        return thing;
-
-    return nullptr;
+    return arenas->allocateFromArena(zone, thingKind, maybeStartBGAlloc);
 }
 
 /* static */ void*
 GCRuntime::refillFreeListOffMainThread(ExclusiveContext* cx, AllocKind thingKind)
 {
     ArenaLists* arenas = cx->arenas();
     Zone* zone = cx->zone();
     JSRuntime* rt = zone->runtimeFromAnyThread();
@@ -331,22 +296,17 @@ GCRuntime::refillFreeListOffMainThread(E
 
     // If we're off the main thread, we try to allocate once and return
     // whatever value we get. We need to first ensure the main thread is not in
     // a GC session.
     AutoLockHelperThreadState lock;
     while (rt->isHeapBusy())
         HelperThreadState().wait(GlobalHelperThreadState::PRODUCER);
 
-    void* thing = arenas->allocateFromArena(zone, thingKind, maybeStartBGAlloc);
-    if (thing)
-        return thing;
-
-    ReportOutOfMemory(cx);
-    return nullptr;
+    return arenas->allocateFromArena(zone, thingKind, maybeStartBGAlloc);
 }
 
 TenuredCell*
 ArenaLists::allocateFromArena(JS::Zone* zone, AllocKind thingKind,
                               AutoMaybeStartBackgroundAllocation& maybeStartBGAlloc)
 {
     JSRuntime* rt = zone->runtimeFromAnyThread();
     mozilla::Maybe<AutoLockGC> maybeLock;
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -39,28 +39,28 @@ struct AutoFinishGC
 
 /*
  * This class should be used by any code that needs to exclusive access to the
  * heap in order to trace through it...
  */
 class AutoTraceSession
 {
   public:
-    explicit AutoTraceSession(JSRuntime* rt, HeapState state = Tracing);
+    explicit AutoTraceSession(JSRuntime* rt, JS::HeapState state = JS::HeapState::Tracing);
     ~AutoTraceSession();
 
   protected:
     AutoLockForExclusiveAccess lock;
     JSRuntime* runtime;
 
   private:
     AutoTraceSession(const AutoTraceSession&) = delete;
     void operator=(const AutoTraceSession&) = delete;
 
-    HeapState prevState;
+    JS::HeapState prevState;
 };
 
 struct AutoPrepareForTracing
 {
     AutoFinishGC finish;
     AutoTraceSession session;
     AutoCopyFreeListToArenas copy;
 
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -589,22 +589,16 @@ class GCRuntime
 
     bool addRoot(Value* vp, const char* name);
     void removeRoot(Value* vp);
     void setMarkStackLimit(size_t limit);
 
     void setParameter(JSGCParamKey key, uint32_t value);
     uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock);
 
-    bool isHeapBusy() { return heapState != js::Idle; }
-    bool isHeapMajorCollecting() { return heapState == js::MajorCollecting; }
-    bool isHeapMinorCollecting() { return heapState == js::MinorCollecting; }
-    bool isHeapCollecting() { return isHeapMajorCollecting() || isHeapMinorCollecting(); }
-    bool isHeapCompacting() { return isHeapMajorCollecting() && state() == COMPACT; }
-
     bool triggerGC(JS::gcreason::Reason reason);
     void maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock);
     bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason);
     bool maybeGC(Zone* zone);
     void maybePeriodicFullGC();
     void minorGC(JS::gcreason::Reason reason) {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_MINOR_GC);
         minorGCImpl(reason, nullptr);
@@ -661,17 +655,18 @@ class GCRuntime
     void clearSelectedForMarking();
     void setDeterministic(bool enable);
 #endif
 
     size_t maxMallocBytesAllocated() { return maxMallocBytes; }
 
   public:
     // Internal public interface
-    js::gc::State state() { return incrementalState; }
+    js::gc::State state() const { return incrementalState; }
+    bool isHeapCompacting() const { return state() == COMPACT; }
     bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); }
     void waitBackgroundSweepEnd() { helperState.waitBackgroundSweepEnd(); }
     void waitBackgroundSweepOrAllocEnd() {
         helperState.waitBackgroundSweepEnd();
         allocTask.cancel(GCParallelTask::CancelAndWait);
     }
 
     void requestMinorGC(JS::gcreason::Reason reason);
@@ -867,23 +862,20 @@ class GCRuntime
                      AutoMaybeStartBackgroundAllocation& maybeStartBGAlloc);
     ArenaHeader* allocateArena(Chunk* chunk, Zone* zone, AllocKind kind, const AutoLockGC& lock);
     void arenaAllocatedDuringGC(JS::Zone* zone, ArenaHeader* arena);
 
     // Allocator internals
     bool gcIfNeededPerAllocation(JSContext* cx);
     template <typename T>
     static void checkIncrementalZoneState(ExclusiveContext* cx, T* t);
-    template <AllowGC allowGC>
     static void* refillFreeListFromAnyThread(ExclusiveContext* cx, AllocKind thingKind,
                                              size_t thingSize);
-    template <AllowGC allowGC>
     static void* refillFreeListFromMainThread(JSContext* cx, AllocKind thingKind,
                                               size_t thingSize);
-    static void* tryRefillFreeListFromMainThread(JSContext* cx, AllocKind thingKind);
     static void* refillFreeListOffMainThread(ExclusiveContext* cx, AllocKind thingKind);
 
     /*
      * Return the list of chunks that can be released outside the GC lock.
      * Must be called either during the GC or with the GC lock taken.
      */
     ChunkPool expireEmptyChunkPool(bool shrinkBuffers, const AutoLockGC& lock);
     void freeEmptyChunks(JSRuntime* rt, const AutoLockGC& lock);
@@ -1207,18 +1199,16 @@ class GCRuntime
      * stuff. At various times we check this counter and, if it has changed, we
      * run an immediate, non-incremental GC to clean up the dead
      * zones. This should happen very rarely.
      */
     unsigned objectsMarkedInDeadZones;
 
     bool poked;
 
-    volatile js::HeapState heapState;
-
     /*
      * These options control the zealousness of the GC. The fundamental values
      * are nextScheduled and gcDebugCompartmentGC. At every allocation,
      * nextScheduled is decremented. When it reaches zero, we do either a full
      * or a compartmental GC, based on debugCompartmentGC.
      *
      * At this point, if zeal_ is one of the types that trigger periodic
      * collection, then nextScheduled is reset to the value of zealFrequency.
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -370,33 +370,18 @@ js::Nursery::forwardBufferPointer(HeapSl
 }
 
 js::TenuringTracer::TenuringTracer(JSRuntime* rt, Nursery* nursery)
   : JSTracer(rt, JSTracer::TracerKindTag::Tenuring, TraceWeakMapKeysValues)
   , nursery_(*nursery)
   , tenuredSize(0)
   , head(nullptr)
   , tail(&head)
-  , savedRuntimeNeedBarrier(rt->needsIncrementalBarrier())
 {
     rt->gc.incGcNumber();
-
-    // We disable the runtime needsIncrementalBarrier() check so that
-    // pre-barriers do not fire on objects that have been relocated. The
-    // pre-barrier's call to obj->zone() will try to look through shape_,
-    // which is now the relocation magic and will crash. However,
-    // zone->needsIncrementalBarrier() must still be set correctly so that
-    // allocations we make in minor GCs between incremental slices will
-    // allocate their objects marked.
-    rt->setNeedsIncrementalBarrier(false);
-}
-
-js::TenuringTracer::~TenuringTracer()
-{
-    runtime()->setNeedsIncrementalBarrier(savedRuntimeNeedBarrier);
 }
 
 #define TIME_START(name) int64_t timestampStart_##name = enableProfiling_ ? PRMJ_Now() : 0
 #define TIME_END(name) int64_t timestampEnd_##name = enableProfiling_ ? PRMJ_Now() : 0
 #define TIME_TOTAL(name) (timestampEnd_##name - timestampStart_##name)
 
 void
 js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList* pretenureGroups)
@@ -421,17 +406,17 @@ js::Nursery::collect(JSRuntime* rt, JS::
     rt->gc.incMinorGcNumber();
 
     rt->gc.stats.count(gcstats::STAT_MINOR_GC);
 
     TraceMinorGCStart();
 
     int64_t timestampStart_total = PRMJ_Now();
 
-    AutoTraceSession session(rt, MinorCollecting);
+    AutoTraceSession session(rt, JS::HeapState::MinorCollecting);
     AutoStopVerifyingBarriers av(rt, false);
     AutoDisableProxyCheck disableStrictProxyChecking(rt);
     mozilla::DebugOnly<AutoEnterOOMUnsafeRegion> oomUnsafeRegion;
 
     // Move objects pointed to by roots from the nursery to the major heap.
     TenuringTracer mover(rt, this);
 
     // Mark the store buffer. This must happen first.
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -55,21 +55,17 @@ class TenuringTracer : public JSTracer
     size_t tenuredSize;
 
     // This list is threaded through the Nursery using the space from already
     // moved things. The list is used to fix up the moved things and to find
     // things held live by intra-Nursery pointers.
     gc::RelocationOverlay* head;
     gc::RelocationOverlay** tail;
 
-    // Save and restore all of the runtime state we use during MinorGC.
-    bool savedRuntimeNeedBarrier;
-
     TenuringTracer(JSRuntime* rt, Nursery* nursery);
-    ~TenuringTracer();
 
   public:
     const Nursery& nursery() const { return nursery_; }
 
     // Returns true if the pointer was updated.
     template <typename T> void traverse(T* thingp);
 
     void insertIntoFixupList(gc::RelocationOverlay* entry);
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -450,17 +450,17 @@ js::gc::GCRuntime::markRuntime(JSTracer*
         TraceRoot(trc, &rt->asyncCauseForNewActivations, "asyncCauseForNewActivations");
 
     if (rt->scriptAndCountsVector) {
         ScriptAndCountsVector& vec = *rt->scriptAndCountsVector;
         for (size_t i = 0; i < vec.length(); i++)
             TraceRoot(trc, &vec[i].script, "scriptAndCountsVector");
     }
 
-    if (!rt->isBeingDestroyed() && !trc->runtime()->isHeapMinorCollecting()) {
+    if (!rt->isBeingDestroyed() && !rt->isHeapMinorCollecting()) {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_RUNTIME_DATA);
 
         if (traceOrMark == TraceRuntime || rt->atomsCompartment()->zone()->isCollecting()) {
             MarkPermanentAtoms(trc);
             MarkAtoms(trc);
             MarkWellKnownSymbols(trc);
             jit::JitRuntime::Mark(trc);
         }
@@ -469,30 +469,30 @@ js::gc::GCRuntime::markRuntime(JSTracer*
     for (ContextIter acx(rt); !acx.done(); acx.next())
         acx->mark(trc);
 
     for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
         if (traceOrMark == MarkRuntime && !zone->isCollecting())
             continue;
 
         /* Do not discard scripts with counts while profiling. */
-        if (rt->profilingScripts && !isHeapMinorCollecting()) {
+        if (rt->profilingScripts && !rt->isHeapMinorCollecting()) {
             for (ZoneCellIterUnderGC i(zone, AllocKind::SCRIPT); !i.done(); i.next()) {
                 JSScript* script = i.get<JSScript>();
                 if (script->hasScriptCounts()) {
                     TraceRoot(trc, &script, "profilingScripts");
                     MOZ_ASSERT(script == i.get<JSScript>());
                 }
             }
         }
     }
 
     /* We can't use GCCompartmentsIter if we're called from TraceRuntime. */
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
-        if (trc->runtime()->isHeapMinorCollecting())
+        if (rt->isHeapMinorCollecting())
             c->globalWriteBarriered = false;
 
         if (traceOrMark == MarkRuntime && !c->zone()->isCollecting())
             continue;
 
         /* During a GC, these are treated as weak pointers. */
         if (traceOrMark == TraceRuntime) {
             if (c->watchpointMap)
@@ -509,17 +509,17 @@ js::gc::GCRuntime::markRuntime(JSTracer*
         if (c->objectMetadataTable)
             c->objectMetadataTable->trace(trc);
     }
 
     MarkInterpreterActivations(rt, trc);
 
     jit::MarkJitActivations(rt, trc);
 
-    if (!isHeapMinorCollecting()) {
+    if (!rt->isHeapMinorCollecting()) {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_EMBEDDING);
 
         /*
          * All JSCompartment::markRoots() does is mark the globals for
          * compartments which have been entered. Globals aren't nursery
          * allocated so there's no need to do this for minor GCs.
          */
         for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -226,17 +226,16 @@ gc::GCRuntime::startVerifyPreBarriers()
 
         node = NextNode(node);
     }
 
     verifyPreData = trc;
     incrementalState = MARK;
     marker.start();
 
-    rt->setNeedsIncrementalBarrier(true);
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
         PurgeJITCaches(zone);
         zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit);
         zone->arenas.purge();
     }
 
     return;
 
@@ -323,17 +322,16 @@ gc::GCRuntime::endVerifyPreBarriers()
     /* We need to disable barriers before tracing, which may invoke barriers. */
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
         if (!zone->needsIncrementalBarrier())
             compartmentCreated = true;
 
         zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
         PurgeJITCaches(zone);
     }
-    rt->setNeedsIncrementalBarrier(false);
 
     /*
      * We need to bump gcNumber so that the methodjit knows that jitcode has
      * been discarded.
      */
     MOZ_ASSERT(trc->number == number);
     number++;
 
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -182,17 +182,17 @@ struct Zone : public JS::shadow::Zone,
         else
             return needsIncrementalBarrier();
     }
 
     // If this returns true, all object tracing must be done with a GC marking
     // tracer.
     bool requireGCTracer() const {
         JSRuntime* rt = runtimeFromAnyThread();
-        return rt->isHeapMajorCollecting() && !rt->isHeapCompacting() && gcState_ != NoGC;
+        return rt->isHeapMajorCollecting() && !rt->gc.isHeapCompacting() && gcState_ != NoGC;
     }
 
     bool isGCMarking() {
         if (runtimeFromMainThread()->isHeapCollecting())
             return gcState_ == Mark || gcState_ == MarkGray;
         else
             return needsIncrementalBarrier();
     }
--- a/js/src/jit-test/tests/gc/bug-1165966.js
+++ b/js/src/jit-test/tests/gc/bug-1165966.js
@@ -1,6 +1,6 @@
-// |jit-test| --no-ggc; allow-unhandlable-oom
+// |jit-test| --no-ggc; allow-unhandlable-oom; --no-ion
 load(libdir + 'oomTest.js');
 var g = newGlobal();
 oomTest(function() {
     Debugger(g);
 });
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2927,17 +2927,17 @@ static const VMFunction GetIntrinsicValu
 
 void
 CodeGenerator::visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir)
 {
     pushArg(ImmGCPtr(lir->mir()->name()));
     callVM(GetIntrinsicValueInfo, lir);
 }
 
-typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, uint32_t, Value*, Value*);
+typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, uint32_t, Value*, MutableHandleValue);
 static const VMFunction InvokeFunctionInfo = FunctionInfo<InvokeFunctionFn>(InvokeFunction);
 
 void
 CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg,
                                       uint32_t argc, uint32_t unusedStack)
 {
     // Nestle %esp up to the argument vector.
     // Each path must account for framePushed_ separately, for callVM to be valid.
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -2800,16 +2800,22 @@ jit::AddKeepAliveInstructions(MIRGraph& 
                 ownerObject = ins->toSlots()->object();
                 break;
               default:
                 MOZ_CRASH("Unexpected op");
             }
 
             MOZ_ASSERT(ownerObject->type() == MIRType_Object);
 
+            if (ownerObject->isConstant()) {
+                // Constants are kept alive by other pointers, for instance
+                // ImmGCPtr in JIT code.
+                continue;
+            }
+
             for (MUseDefIterator uses(ins); uses; uses++) {
                 MInstruction* use = uses.def()->toInstruction();
 
                 if (use->isStoreElementHole()) {
                     // StoreElementHole has an explicit object operand. If GVN
                     // is disabled, we can get different unbox instructions with
                     // the same object as input, so we check for that case.
                     MOZ_ASSERT_IF(!use->toStoreElementHole()->object()->isUnbox() && !ownerObject->isUnbox(),
--- a/js/src/jit/JitSpewer.cpp
+++ b/js/src/jit/JitSpewer.cpp
@@ -312,24 +312,27 @@ GraphSpewer::endFunction()
 
     ionspewer.endFunction(this);
     graph_ = nullptr;
 }
 
 void
 GraphSpewer::dump(Fprinter& c1Out, Fprinter& jsonOut)
 {
-    if (!c1Printer_.hadOutOfMemory())
+    if (!c1Printer_.hadOutOfMemory()) {
         c1Printer_.exportInto(c1Out);
+        c1Out.flush();
+    }
     c1Printer_.clear();
 
     if (!jsonPrinter_.hadOutOfMemory())
         jsonPrinter_.exportInto(jsonOut);
     else
         jsonOut.put("{}");
+    jsonOut.flush();
     jsonPrinter_.clear();
 }
 
 void
 jit::SpewBeginFunction(MIRGenerator* mir, JSScript* function)
 {
     MIRGraph* graph = &mir->graph();
     mir->graphSpewer().init(graph, function);
--- a/js/src/jit/JitSpewer.h
+++ b/js/src/jit/JitSpewer.h
@@ -91,16 +91,17 @@ namespace jit {
 
 enum JitSpewChannel {
 #define JITSPEW_CHANNEL(name) JitSpew_##name,
     JITSPEW_CHANNEL_LIST(JITSPEW_CHANNEL)
 #undef JITSPEW_CHANNEL
     JitSpew_Terminator
 };
 
+class MIRGenerator;
 
 // The JitSpewer is only available on debug builds.
 // None of the global functions have effect on non-debug builds.
 static const int NULL_ID = -1;
 
 #ifdef DEBUG
 
 // Class made to hold the MIR and LIR graphs of an AsmJS / Ion compilation.
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -52,44 +52,32 @@ VMFunction::addToFunctions()
         initialized = true;
         functions = nullptr;
     }
     this->next = functions;
     functions = this;
 }
 
 bool
-InvokeFunction(JSContext* cx, HandleObject obj, uint32_t argc, Value* argv, Value* rval)
+InvokeFunction(JSContext* cx, HandleObject obj, uint32_t argc, Value* argv,
+               MutableHandleValue rval)
 {
     AutoArrayRooter argvRoot(cx, argc + 1, argv);
 
     // Data in the argument vector is arranged for a JIT -> JIT call.
     Value thisv = argv[0];
     Value* argvWithoutThis = argv + 1;
 
     // For constructing functions, |this| is constructed at caller side and we can just call Invoke.
     // When creating this failed / is impossible at caller site, i.e. MagicValue(JS_IS_CONSTRUCTING),
     // we use InvokeConstructor that creates it at the callee side.
-    RootedValue rv(cx);
-    if (thisv.isMagic(JS_IS_CONSTRUCTING)) {
-        if (!InvokeConstructor(cx, ObjectValue(*obj), argc, argvWithoutThis, &rv))
-            return false;
-    } else {
-        if (!Invoke(cx, thisv, ObjectValue(*obj), argc, argvWithoutThis, &rv))
-            return false;
-    }
+    if (thisv.isMagic(JS_IS_CONSTRUCTING))
+        return InvokeConstructor(cx, ObjectValue(*obj), argc, argvWithoutThis, rval);
 
-    if (obj->is<JSFunction>()) {
-        jsbytecode* pc;
-        RootedScript script(cx, cx->currentScript(&pc));
-        TypeScript::Monitor(cx, script, pc, rv.get());
-    }
-
-    *rval = rv;
-    return true;
+    return Invoke(cx, thisv, ObjectValue(*obj), argc, argvWithoutThis, rval);
 }
 
 bool
 CheckOverRecursed(JSContext* cx)
 {
     // We just failed the jitStackLimit check. There are two possible reasons:
     //  - jitStackLimit was the real stack limit and we're over-recursed
     //  - jitStackLimit was set to UINTPTR_MAX by JSRuntime::requestInterrupt
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -626,17 +626,18 @@ class AutoDetectInvalidation
     }
 
     ~AutoDetectInvalidation() {
         if (!disabled_ && ionScript_->invalidated())
             setReturnOverride();
     }
 };
 
-bool InvokeFunction(JSContext* cx, HandleObject obj0, uint32_t argc, Value* argv, Value* rval);
+bool InvokeFunction(JSContext* cx, HandleObject obj0, uint32_t argc, Value* argv,
+                    MutableHandleValue rval);
 
 bool CheckOverRecursed(JSContext* cx);
 bool CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame,
                                 uint32_t extra, uint32_t earlyCheck);
 
 bool DefVarOrConst(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain);
 bool SetConst(JSContext* cx, HandlePropertyName name, HandleObject scopeChain, HandleValue rval);
 bool MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value);
--- a/js/src/jsapi-tests/testGCMarking.cpp
+++ b/js/src/jsapi-tests/testGCMarking.cpp
@@ -13,18 +13,18 @@ class CCWTestTracer : public JS::Callbac
     }
 
     void callback(void** thingp, JS::TraceKind kind) {
         numberOfThingsTraced++;
 
         printf("*thingp         = %p\n", *thingp);
         printf("*expectedThingp = %p\n", *expectedThingp);
 
-        printf("kind         = %d\n", kind);
-        printf("expectedKind = %d\n", expectedKind);
+        printf("kind         = %d\n", static_cast<int>(kind));
+        printf("expectedKind = %d\n", static_cast<int>(expectedKind));
 
         if (*thingp != *expectedThingp || kind != expectedKind)
             okay = false;
     }
 
   public:
     bool          okay;
     size_t        numberOfThingsTraced;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1457,17 +1457,17 @@ JS_EnterCompartment(JSContext* cx, JSObj
 extern JS_PUBLIC_API(void)
 JS_LeaveCompartment(JSContext* cx, JSCompartment* oldCompartment);
 
 typedef void (*JSIterateCompartmentCallback)(JSRuntime* rt, void* data, JSCompartment* compartment);
 
 /*
  * This function calls |compartmentCallback| on every compartment. Beware that
  * there is no guarantee that the compartment will survive after the callback
- * returns.
+ * returns. Also, barriers are disabled via the TraceSession.
  */
 extern JS_PUBLIC_API(void)
 JS_IterateCompartments(JSRuntime* rt, void* data,
                        JSIterateCompartmentCallback compartmentCallback);
 
 /*
  * Initialize standard JS class constructors, prototypes, and any top-level
  * functions and constants associated with the standard classes (e.g. isNaN
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -484,17 +484,18 @@ JSCompartment::wrap(JSContext* cx, Mutab
 /*
  * This method marks pointers that cross compartment boundaries. It is called in
  * per-zone GCs (since full GCs naturally follow pointers across compartments)
  * and when compacting to update cross-compartment pointers.
  */
 void
 JSCompartment::markCrossCompartmentWrappers(JSTracer* trc)
 {
-    MOZ_ASSERT(!zone()->isCollecting() || trc->runtime()->isHeapCompacting());
+    MOZ_ASSERT(trc->runtime()->isHeapMajorCollecting());
+    MOZ_ASSERT(!zone()->isCollecting() || trc->runtime()->gc.isHeapCompacting());
 
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
         Value v = e.front().value();
         if (e.front().key().kind == CrossCompartmentKey::ObjectWrapper) {
             ProxyObject* wrapper = &v.toObject().as<ProxyObject>();
 
             /*
              * We have a cross-compartment wrapper. Its private pointer may
@@ -714,26 +715,27 @@ JSCompartment::clearObjectMetadata()
 {
     js_delete(objectMetadataTable);
     objectMetadataTable = nullptr;
 }
 
 void
 JSCompartment::setNewObjectMetadata(JSContext* cx, JSObject* obj)
 {
-    MOZ_ASSERT(this == cx->compartment());
+    assertSameCompartment(cx, this, obj);
 
     if (JSObject* metadata = objectMetadataCallback(cx, obj)) {
+        assertSameCompartment(cx, metadata);
         if (!objectMetadataTable) {
             objectMetadataTable = cx->new_<ObjectWeakMap>(cx);
             if (!objectMetadataTable)
-                CrashAtUnhandlableOOM("setObjectMetadata");
+                CrashAtUnhandlableOOM("setNewObjectMetadata");
         }
         if (!objectMetadataTable->add(cx, obj, metadata))
-            CrashAtUnhandlableOOM("setObjectMetadata");
+            CrashAtUnhandlableOOM("setNewObjectMetadata");
     }
 }
 
 static bool
 AddInnerLazyFunctionsFromScript(JSScript* script, AutoObjectVector& lazyFunctions)
 {
     if (!script->hasObjects())
         return true;
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -319,18 +319,18 @@ struct JSCompartment
 #endif
 
     /*
      * Lazily initialized script source object to use for scripts cloned
      * from the self-hosting global.
      */
     js::ReadBarrieredScriptSourceObject selfHostingScriptSource;
 
-    // Keep track of the metadata objects which can be associated with each
-    // JS object.
+    // Keep track of the metadata objects which can be associated with each JS
+    // object. Both keys and values are in this compartment.
     js::ObjectWeakMap* objectMetadataTable;
 
     // Map from array buffers to views sharing that storage.
     js::InnerViewTable innerViews;
 
     // Inline transparent typed objects do not initially have an array buffer,
     // but can have that buffer created lazily if it is accessed later. This
     // table manages references from such typed objects to their buffers.
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1063,28 +1063,28 @@ GCRuntime::pickChunk(const AutoLockGC& l
 }
 
 ArenaHeader*
 GCRuntime::allocateArena(Chunk* chunk, Zone* zone, AllocKind thingKind, const AutoLockGC& lock)
 {
     MOZ_ASSERT(chunk->hasAvailableArenas());
 
     // Fail the allocation if we are over our heap size limits.
-    if (!isHeapMinorCollecting() &&
+    if (!rt->isHeapMinorCollecting() &&
         !isHeapCompacting() &&
         usage.gcBytes() >= tunables.gcMaxBytes())
     {
         return nullptr;
     }
 
     ArenaHeader* aheader = chunk->allocateArena(rt, zone, thingKind, lock);
     zone->usage.addGCArena();
 
     // Trigger an incremental slice if needed.
-    if (!isHeapMinorCollecting() && !isHeapCompacting())
+    if (!rt->isHeapMinorCollecting() && !isHeapCompacting())
         maybeAllocTriggerZoneGC(zone, lock);
 
     return aheader;
 }
 
 void
 GCRuntime::releaseArena(ArenaHeader* aheader, const AutoLockGC& lock)
 {
@@ -1147,17 +1147,16 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
     sliceBudget(SliceBudget::Unlimited),
     incrementalAllowed(true),
     generationalDisabled(0),
     compactingEnabled(true),
     compactingDisabledCount(0),
     manipulatingDeadZones(false),
     objectsMarkedInDeadZones(0),
     poked(false),
-    heapState(Idle),
 #ifdef JS_GC_ZEAL
     zealMode(0),
     zealFrequency(0),
     nextScheduled(0),
     deterministicOnly(false),
     incrementalLimit(0),
 #endif
     validate(true),
@@ -1525,17 +1524,17 @@ GCRuntime::getParameter(JSGCParamKey key
         MOZ_ASSERT(key == JSGC_NUMBER);
         return uint32_t(number);
     }
 }
 
 void
 GCRuntime::setMarkStackLimit(size_t limit)
 {
-    MOZ_ASSERT(!isHeapBusy());
+    MOZ_ASSERT(!rt->isHeapBusy());
     AutoStopVerifyingBarriers pauseVerification(rt, false);
     marker.setMaxCapacity(limit);
 }
 
 bool
 GCRuntime::addBlackRootsTracer(JSTraceDataOp traceOp, void* data)
 {
     AssertHeapIsIdle(rt);
@@ -2122,17 +2121,17 @@ static bool ShouldRelocateZone(size_t ar
 bool
 ArenaLists::relocateArenas(ArenaHeader*& relocatedListOut, JS::gcreason::Reason reason,
                            SliceBudget& sliceBudget, gcstats::Statistics& stats)
 {
 
     // This is only called from the main thread while we are doing a GC, so
     // there is no need to lock.
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
-    MOZ_ASSERT(runtime_->isHeapCompacting());
+    MOZ_ASSERT(runtime_->gc.isHeapCompacting());
     MOZ_ASSERT(!runtime_->gc.isBackgroundSweeping());
 
     // Flush all the freeLists back into the arena headers
     purge();
     checkEmptyFreeLists();
 
     if (ShouldRelocateAllArenas(reason)) {
         for (auto i : AllAllocKinds()) {
@@ -3445,25 +3444,25 @@ GCRuntime::queueZonesForBackgroundSweep(
     AutoLockGC lock(rt);
     backgroundSweepZones.transferFrom(zones);
     helperState.maybeStartBackgroundSweep(lock);
 }
 
 void
 GCRuntime::freeUnusedLifoBlocksAfterSweeping(LifoAlloc* lifo)
 {
-    MOZ_ASSERT(isHeapBusy());
+    MOZ_ASSERT(rt->isHeapBusy());
     AutoLockGC lock(rt);
     freeLifoAlloc.transferUnusedFrom(lifo);
 }
 
 void
 GCRuntime::freeAllLifoBlocksAfterSweeping(LifoAlloc* lifo)
 {
-    MOZ_ASSERT(isHeapBusy());
+    MOZ_ASSERT(rt->isHeapBusy());
     AutoLockGC lock(rt);
     freeLifoAlloc.transferFrom(lifo);
 }
 
 void
 GCHelperState::maybeStartBackgroundSweep(const AutoLockGC& lock)
 {
     MOZ_ASSERT(CanUseExtraThreads());
@@ -4302,27 +4301,16 @@ GCRuntime::finishMarkingValidation()
 {
 #ifdef JS_GC_MARKING_VALIDATION
     js_delete(markingValidator);
     markingValidator = nullptr;
 #endif
 }
 
 static void
-AssertNeedsBarrierFlagsConsistent(JSRuntime* rt)
-{
-#ifdef JS_GC_MARKING_VALIDATION
-    bool anyNeedsBarrier = false;
-    for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
-        anyNeedsBarrier |= zone->needsIncrementalBarrier();
-    MOZ_ASSERT(rt->needsIncrementalBarrier() == anyNeedsBarrier);
-#endif
-}
-
-static void
 DropStringWrappers(JSRuntime* rt)
 {
     /*
      * String "wrappers" are dropped on GC because their presence would require
      * us to sweep the wrappers in all compartments every time we sweep a
      * compartment group.
      */
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
@@ -4475,18 +4463,16 @@ GCRuntime::getNextZoneGroup()
         MOZ_ASSERT(!isIncremental);
         for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
             MOZ_ASSERT(!zone->gcNextGraphComponent);
             MOZ_ASSERT(zone->isGCMarking());
             zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
             zone->setGCState(Zone::NoGC);
             zone->gcGrayRoots.clearAndFree();
         }
-        rt->setNeedsIncrementalBarrier(false);
-        AssertNeedsBarrierFlagsConsistent(rt);
 
         for (GCCompartmentGroupIter comp(rt); !comp.done(); comp.next())
             ResetGrayList(comp);
 
         abortSweepAfterCurrentGroup = false;
         currentZoneGroup = nullptr;
     }
 }
@@ -5514,54 +5500,54 @@ GCRuntime::finishCollection(JS::gcreason
         reason == JS::gcreason::DEBUG_GC)
     {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
         rt->gc.waitBackgroundSweepOrAllocEnd();
     }
 }
 
 /* Start a new heap session. */
-AutoTraceSession::AutoTraceSession(JSRuntime* rt, js::HeapState heapState)
+AutoTraceSession::AutoTraceSession(JSRuntime* rt, JS::HeapState heapState)
   : lock(rt),
     runtime(rt),
-    prevState(rt->gc.heapState)
+    prevState(rt->heapState_)
 {
     MOZ_ASSERT(rt->gc.isAllocAllowed());
-    MOZ_ASSERT(rt->gc.heapState == Idle);
-    MOZ_ASSERT(heapState != Idle);
-    MOZ_ASSERT_IF(heapState == MajorCollecting, rt->gc.nursery.isEmpty());
+    MOZ_ASSERT(rt->heapState_ == JS::HeapState::Idle);
+    MOZ_ASSERT(heapState != JS::HeapState::Idle);
+    MOZ_ASSERT_IF(heapState == JS::HeapState::MajorCollecting, rt->gc.nursery.isEmpty());
 
     // Threads with an exclusive context can hit refillFreeList while holding
     // the exclusive access lock. To avoid deadlocking when we try to acquire
     // this lock during GC and the other thread is waiting, make sure we hold
     // the exclusive access lock during GC sessions.
     MOZ_ASSERT(rt->currentThreadHasExclusiveAccess());
 
     if (rt->exclusiveThreadsPresent()) {
         // Lock the helper thread state when changing the heap state in the
         // presence of exclusive threads, to avoid racing with refillFreeList.
         AutoLockHelperThreadState lock;
-        rt->gc.heapState = heapState;
+        rt->heapState_ = heapState;
     } else {
-        rt->gc.heapState = heapState;
+        rt->heapState_ = heapState;
     }
 }
 
 AutoTraceSession::~AutoTraceSession()
 {
     MOZ_ASSERT(runtime->isHeapBusy());
 
     if (runtime->exclusiveThreadsPresent()) {
         AutoLockHelperThreadState lock;
-        runtime->gc.heapState = prevState;
+        runtime->heapState_ = prevState;
 
         // Notify any helper threads waiting for the trace session to end.
         HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER);
     } else {
-        runtime->gc.heapState = prevState;
+        runtime->heapState_ = prevState;
     }
 }
 
 AutoCopyFreeListToArenas::AutoCopyFreeListToArenas(JSRuntime* rt, ZoneSelector selector)
   : runtime(rt),
     selector(selector)
 {
     for (ZonesIter zone(rt, selector); !zone.done(); zone.next())
@@ -5608,18 +5594,16 @@ GCRuntime::resetIncrementalGC(const char
         for (GCCompartmentsIter c(rt); !c.done(); c.next())
             ResetGrayList(c);
 
         for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
             MOZ_ASSERT(zone->isGCMarking());
             zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
             zone->setGCState(Zone::NoGC);
         }
-        rt->setNeedsIncrementalBarrier(false);
-        AssertNeedsBarrierFlagsConsistent(rt);
 
         freeLifoAlloc.freeAll();
 
         incrementalState = NO_INCREMENTAL;
 
         MOZ_ASSERT(!marker.shouldCheckCompartments());
 
         break;
@@ -5721,35 +5705,29 @@ AutoGCSlice::AutoGCSlice(JSRuntime* rt)
          */
         if (zone->isGCMarking()) {
             MOZ_ASSERT(zone->needsIncrementalBarrier());
             zone->setNeedsIncrementalBarrier(false, Zone::DontUpdateJit);
         } else {
             MOZ_ASSERT(!zone->needsIncrementalBarrier());
         }
     }
-    rt->setNeedsIncrementalBarrier(false);
-    AssertNeedsBarrierFlagsConsistent(rt);
 }
 
 AutoGCSlice::~AutoGCSlice()
 {
     /* We can't use GCZonesIter if this is the end of the last slice. */
-    bool haveBarriers = false;
     for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) {
         if (zone->isGCMarking()) {
             zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit);
             zone->arenas.prepareForIncrementalGC(runtime);
-            haveBarriers = true;
         } else {
             zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
         }
     }
-    runtime->setNeedsIncrementalBarrier(haveBarriers);
-    AssertNeedsBarrierFlagsConsistent(runtime);
 }
 
 void
 GCRuntime::pushZealSelectedObjects()
 {
 #ifdef JS_GC_ZEAL
     /* Push selected objects onto the mark stack and clear the list. */
     for (JSObject** obj = selectedForMarking.begin(); obj != selectedForMarking.end(); obj++)
@@ -6000,17 +5978,17 @@ GCRuntime::gcCycle(bool incremental, Sli
     evictNursery(reason);
 
     /*
      * Marking can trigger many incidental post barriers, some of them for
      * objects which are not going to be live after the GC.
      */
     AutoDisableStoreBuffer adsb(this);
 
-    AutoTraceSession session(rt, MajorCollecting);
+    AutoTraceSession session(rt, JS::HeapState::MajorCollecting);
 
     majorGCTriggerReason = JS::gcreason::NO_REASON;
     interFrameGC = true;
 
     number++;
     if (!isIncrementalGCInProgress())
         incMajorGcNumber();
 
@@ -6268,17 +6246,17 @@ GCRuntime::abortGC()
     AutoStopVerifyingBarriers av(rt, false);
 
     SliceBudget unlimited;
     gcstats::AutoGCSlice agc(stats, scanZonesBeforeGC(), invocationKind,
                              unlimited, JS::gcreason::ABORT_GC);
 
     evictNursery(JS::gcreason::ABORT_GC);
     AutoDisableStoreBuffer adsb(this);
-    AutoTraceSession session(rt, MajorCollecting);
+    AutoTraceSession session(rt, JS::HeapState::MajorCollecting);
 
     number++;
     resetIncrementalGC("abort");
 }
 
 void
 GCRuntime::notifyDidPaint()
 {
@@ -6655,45 +6633,45 @@ GCRuntime::runDebugGC()
     }
 
 #endif
 }
 
 void
 GCRuntime::setValidate(bool enabled)
 {
-    MOZ_ASSERT(!isHeapMajorCollecting());
+    MOZ_ASSERT(!rt->isHeapMajorCollecting());
     validate = enabled;
 }
 
 void
 GCRuntime::setFullCompartmentChecks(bool enabled)
 {
-    MOZ_ASSERT(!isHeapMajorCollecting());
+    MOZ_ASSERT(!rt->isHeapMajorCollecting());
     fullCompartmentChecks = enabled;
 }
 
 #ifdef JS_GC_ZEAL
 bool
 GCRuntime::selectForMarking(JSObject* object)
 {
-    MOZ_ASSERT(!isHeapMajorCollecting());
+    MOZ_ASSERT(!rt->isHeapMajorCollecting());
     return selectedForMarking.append(object);
 }
 
 void
 GCRuntime::clearSelectedForMarking()
 {
     selectedForMarking.clearAndFree();
 }
 
 void
 GCRuntime::setDeterministic(bool enabled)
 {
-    MOZ_ASSERT(!isHeapMajorCollecting());
+    MOZ_ASSERT(!rt->isHeapMajorCollecting());
     deterministicOnly = enabled;
 }
 #endif
 
 #ifdef DEBUG
 
 /* Should only be called manually under gdb */
 void PreventGCDuringInteractiveDebug()
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -34,23 +34,16 @@
     D(Shape,         js::Shape,         true) \
     D(String,        JSString,          false) \
     D(Symbol,        JS::Symbol,        false)
 
 namespace js {
 
 unsigned GetCPUCount();
 
-enum HeapState {
-    Idle,             // doing nothing with the GC heap
-    Tracing,          // tracing the GC heap without collecting, e.g. IterateCompartments()
-    MajorCollecting,  // doing a GC of the major heap
-    MinorCollecting   // doing a GC of the minor heap (nursery)
-};
-
 enum ThreadType
 {
     MainThread,
     BackgroundThread
 };
 
 namespace gcstats {
 struct Statistics;
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -123,44 +123,53 @@ typedef JSConstScalarSpec<int32_t> JSCon
 typedef void
 (* JSTraceDataOp)(JSTracer* trc, void* data);
 
 namespace js {
 
 void FinishGC(JSRuntime* rt);
 
 namespace gc {
+class AutoTraceSession;
 class StoreBuffer;
 void MarkPersistentRootedChains(JSTracer*);
 void FinishPersistentRootedChains(JSRuntime*);
 }
 }
 
 namespace JS {
 
 typedef void (*OffThreadCompileCallback)(void* token, void* callbackData);
 
+enum class HeapState {
+    Idle,             // doing nothing with the GC heap
+    Tracing,          // tracing the GC heap without collecting, e.g. IterateCompartments()
+    MajorCollecting,  // doing a GC of the major heap
+    MinorCollecting   // doing a GC of the minor heap (nursery)
+};
+
 namespace shadow {
 
 struct Runtime
 {
-    /* Restrict zone access during Minor GC. */
-    bool needsIncrementalBarrier_;
+  protected:
+    // Allow inlining of heapState checks.
+    friend class js::gc::AutoTraceSession;
+    JS::HeapState heapState_;
 
-  private:
     js::gc::StoreBuffer* gcStoreBufferPtr_;
 
   public:
     Runtime()
-      : needsIncrementalBarrier_(false)
+      : heapState_(JS::HeapState::Idle)
       , gcStoreBufferPtr_(nullptr)
     {}
 
     bool needsIncrementalBarrier() const {
-        return needsIncrementalBarrier_;
+        return heapState_ == JS::HeapState::Idle;
     }
 
     js::gc::StoreBuffer* gcStoreBufferPtr() { return gcStoreBufferPtr_; }
 
     static JS::shadow::Runtime* asShadowRuntime(JSRuntime* rt) {
         return reinterpret_cast<JS::shadow::Runtime*>(rt);
     }
 
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -9,20 +9,22 @@
  */
 
 #ifndef jsutil_h
 #define jsutil_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Compiler.h"
 #include "mozilla/GuardObjects.h"
+#include "mozilla/PodOperations.h"
 
 #include <limits.h>
 
 #include "js/Utility.h"
+#include "js/Value.h"
 
 #define JS_ALWAYS_TRUE(expr)      MOZ_ALWAYS_TRUE(expr)
 #define JS_ALWAYS_FALSE(expr)     MOZ_ALWAYS_FALSE(expr)
 
 #if defined(JS_DEBUG)
 # define JS_DIAGNOSTICS_ASSERT(expr) MOZ_ASSERT(expr)
 #elif defined(JS_CRASH_DIAGNOSTICS)
 # define JS_DIAGNOSTICS_ASSERT(expr) do { if (MOZ_UNLIKELY(!(expr))) MOZ_CRASH(); } while(0)
@@ -272,31 +274,57 @@ static inline void
 ClearAllBitArrayElements(size_t* array, size_t length)
 {
     for (unsigned i = 0; i < length; ++i)
         array[i] = 0;
 }
 
 }  /* namespace js */
 
+namespace mozilla {
+
+/**
+ * Set the first |aNElem| T elements in |aDst| to |aSrc|.
+ */
+template<typename T>
+static MOZ_ALWAYS_INLINE void
+PodSet(T* aDst, T aSrc, size_t aNElem)
+{
+    for (const T* dstend = aDst + aNElem; aDst < dstend; ++aDst)
+        *aDst = aSrc;
+}
+
+} /* namespace mozilla */
+
 static inline void*
-Poison(void* ptr, int value, size_t num)
+Poison(void* ptr, uint8_t value, size_t num)
 {
-    static bool inited = false;
-    static bool poison = true;
-    if (!inited) {
-        char* env = getenv("JSGC_DISABLE_POISONING");
-        if (env)
-            poison = false;
-        inited = true;
+    static bool poison = !bool(getenv("JSGC_DISABLE_POISONING"));
+    if (poison) {
+        // Without a valid Value tag, a poisoned Value may look like a valid
+        // floating point number. To ensure that we crash more readily when
+        // observing a poised Value, we make the poison an invalid ObjectValue.
+        uintptr_t obj;
+        memset(&obj, value, sizeof(obj));
+#if defined(JS_PUNBOX64)
+        obj >>= JSVAL_TAG_SHIFT;
+#endif
+        const jsval_layout layout = OBJECT_TO_JSVAL_IMPL((JSObject*)obj);
+
+        size_t value_count = num / sizeof(jsval_layout);
+        size_t byte_count = num % sizeof(jsval_layout);
+        mozilla::PodSet((jsval_layout*)ptr, layout, value_count);
+        if (byte_count) {
+            uint8_t* bytes = static_cast<uint8_t*>(ptr);
+            uint8_t* end = bytes + num;
+            mozilla::PodSet(end - byte_count, value, byte_count);
+        }
+        return ptr;
     }
 
-    if (poison)
-        return memset(ptr, value, num);
-
     return nullptr;
 }
 
 /* Crash diagnostics */
 #if defined(DEBUG) && !defined(MOZ_ASAN)
 # define JS_CRASH_DIAGNOSTICS 1
 #endif
 #if defined(JS_CRASH_DIAGNOSTICS) || defined(JS_GC_ZEAL)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -6060,19 +6060,33 @@ MaybeOverrideOutFileFromEnv(const char* 
 
 /* Pretend we can always preserve wrappers for dummy DOM objects. */
 static bool
 DummyPreserveWrapperCallback(JSContext* cx, JSObject* obj)
 {
     return true;
 }
 
+static void
+PreInit()
+{
+#ifdef XP_WIN
+    // Disable the segfault dialog. We want to fail the tests immediately
+    // instead of hanging automation.
+    UINT prevMode = SetErrorMode(0);
+    UINT newMode = SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
+    SetErrorMode(prevMode | newMode);
+#endif
+}
+
 int
 main(int argc, char** argv, char** envp)
 {
+    PreInit();
+
     sArgc = argc;
     sArgv = argv;
 
     JSRuntime* rt;
     JSContext* cx;
     int result;
 #ifdef XP_WIN
     {
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -6878,22 +6878,24 @@ static bool
 DebuggerObject_getAllocationSite(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get allocationSite", args, obj);
 
     RootedObject metadata(cx, GetObjectMetadata(obj));
     if (!metadata)
         return null(args);
 
-    metadata = CheckedUnwrap(metadata);
-    if (!metadata || !SavedFrame::isSavedFrameAndNotProto(*metadata))
+    MOZ_ASSERT(!metadata->is<WrapperObject>());
+
+    if (!SavedFrame::isSavedFrameAndNotProto(*metadata))
         return null(args);
 
     if (!cx->compartment()->wrap(cx, &metadata))
         return false;
+
     args.rval().setObject(*metadata);
     return true;
 }
 
 static bool
 DebuggerObject_getOwnPropertyDescriptor(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "getOwnPropertyDescriptor", args, dbg, obj);
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -922,17 +922,18 @@ RegExpCompartment::sweep(JSRuntime* rt)
         for (size_t i = 0; i < ArrayLength(shared->compilationArray); i++) {
             RegExpShared::RegExpCompilation& compilation = shared->compilationArray[i];
             if (compilation.jitCode &&
                 IsAboutToBeFinalized(&compilation.jitCode))
             {
                 keep = false;
             }
         }
-        if (keep || rt->isHeapCompacting()) {
+        MOZ_ASSERT(rt->isHeapMajorCollecting());
+        if (keep || rt->gc.isHeapCompacting()) {
             shared->clearMarked();
         } else {
             js_delete(shared);
             e.removeFront();
         }
     }
 
     if (matchResultTemplateObject_ &&
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -998,21 +998,20 @@ struct JSRuntime : public JS::shadow::Ru
 #endif
 
     /* Garbage collector state, used by jsgc.c. */
     js::gc::GCRuntime   gc;
 
     /* Garbage collector state has been sucessfully initialized. */
     bool                gcInitialized;
 
-    bool isHeapBusy() { return gc.isHeapBusy(); }
-    bool isHeapMajorCollecting() { return gc.isHeapMajorCollecting(); }
-    bool isHeapMinorCollecting() { return gc.isHeapMinorCollecting(); }
-    bool isHeapCollecting() { return gc.isHeapCollecting(); }
-    bool isHeapCompacting() { return gc.isHeapCompacting(); }
+    bool isHeapBusy() const { return heapState_ != JS::HeapState::Idle; }
+    bool isHeapMajorCollecting() const { return heapState_ == JS::HeapState::MajorCollecting; }
+    bool isHeapMinorCollecting() const { return heapState_ == JS::HeapState::MinorCollecting; }
+    bool isHeapCollecting() const { return isHeapMinorCollecting() || isHeapMajorCollecting(); }
 
     int gcZeal() { return gc.zeal(); }
 
     void lockGC() {
         assertCanLock(js::GCLock);
         gc.lockGC();
     }
 
@@ -1020,20 +1019,16 @@ struct JSRuntime : public JS::shadow::Ru
         gc.unlockGC();
     }
 
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     js::jit::Simulator* simulator_;
 #endif
 
   public:
-    void setNeedsIncrementalBarrier(bool needs) {
-        needsIncrementalBarrier_ = needs;
-    }
-
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     js::jit::Simulator* simulator() const;
     uintptr_t* addressOfSimulatorStackLimit();
 #endif
 
     /* Strong references on scripts held for PCCount profiling API. */
     js::ScriptAndCountsVector* scriptAndCountsVector;
 
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -22,16 +22,17 @@
 #include "jsscript.h"
 #include "prmjtime.h"
 
 #include "gc/Marking.h"
 #include "gc/Rooting.h"
 #include "js/Vector.h"
 #include "vm/Debugger.h"
 #include "vm/StringBuffer.h"
+#include "vm/WrapperObject.h"
 
 #include "jscntxtinlines.h"
 
 #include "vm/NativeObject-inl.h"
 
 using mozilla::AddToHash;
 using mozilla::DebugOnly;
 using mozilla::HashString;
@@ -1218,16 +1219,17 @@ SavedStacksMetadataCallback(JSContext* c
 
     RootedSavedFrame frame(cx);
     if (!stacks.saveCurrentStack(cx, &frame))
         CrashAtUnhandlableOOM("SavedStacksMetadataCallback");
 
     if (!Debugger::onLogAllocationSite(cx, obj, frame, PRMJ_Now()))
         CrashAtUnhandlableOOM("SavedStacksMetadataCallback");
 
+    MOZ_ASSERT_IF(frame, !frame->is<WrapperObject>());
     return frame;
 }
 
 JS_FRIEND_API(JSPrincipals*)
 GetSavedFramePrincipals(HandleObject savedFrame)
 {
     MOZ_ASSERT(savedFrame);
     MOZ_ASSERT(savedFrame->is<SavedFrame>());
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -3235,16 +3235,20 @@ ReadSourceFromFilename(JSContext* cx, co
     rv = scriptChannel->GetURI(getter_AddRefs(actualUri));
     NS_ENSURE_SUCCESS(rv, rv);
     nsCString scheme;
     rv = actualUri->GetScheme(scheme);
     NS_ENSURE_SUCCESS(rv, rv);
     if (!scheme.EqualsLiteral("file") && !scheme.EqualsLiteral("jar"))
         return NS_OK;
 
+    // Explicitly set the content type so that we don't load the
+    // exthandler to guess it.
+    scriptChannel->SetContentType(NS_LITERAL_CSTRING("text/plain"));
+
     nsCOMPtr<nsIInputStream> scriptStream;
     rv = scriptChannel->Open(getter_AddRefs(scriptStream));
     NS_ENSURE_SUCCESS(rv, rv);
 
     uint64_t rawLen;
     rv = scriptStream->Available(&rawLen);
     NS_ENSURE_SUCCESS(rv, rv);
     if (!rawLen)
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -223,17 +223,17 @@ public:
     // Convert the given stringbuffer/length pair to a jsval
     static MOZ_ALWAYS_INLINE bool
     StringBufferToJSVal(JSContext* cx, nsStringBuffer* buf, uint32_t length,
                         JS::MutableHandleValue rval, bool* sharedBuffer)
     {
         JS::Zone* zone = js::GetContextZone(cx);
         ZoneStringCache* cache = static_cast<ZoneStringCache*>(JS_GetZoneUserData(zone));
         if (cache && buf == cache->mBuffer) {
-            MOZ_ASSERT(JS::GetTenuredGCThingZone(cache->mString) == zone);
+            MOZ_ASSERT(JS::GetStringZone(cache->mString) == zone);
             JS::MarkStringAsLive(zone, cache->mString);
             rval.setString(cache->mString);
             *sharedBuffer = false;
             return true;
         }
 
         JSString* str = JS_NewExternalString(cx,
                                              static_cast<char16_t*>(buf->Data()),
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_bug1170311.js
@@ -0,0 +1,5 @@
+const Cu = Components.utils;
+function run_test() {
+  do_check_throws_nsIException(() => Cu.getObjectPrincipal({}).equals(null), "NS_ERROR_ILLEGAL_VALUE");
+  do_check_throws_nsIException(() => Cu.getObjectPrincipal({}).subsumes(null), "NS_ERROR_ILLEGAL_VALUE");
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -53,16 +53,17 @@ support-files =
 [test_bug1034262.js]
 [test_bug1082450.js]
 [test_bug1081990.js]
 [test_bug1110546.js]
 [test_bug1131707.js]
 [test_bug1150106.js]
 [test_bug1150771.js]
 [test_bug1151385.js]
+[test_bug1170311.js]
 [test_bug_442086.js]
 [test_callFunctionWithAsyncStack.js]
 [test_file.js]
 [test_blob.js]
 [test_blob2.js]
 [test_file2.js]
 [test_import.js]
 [test_import_fail.js]
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -670,17 +670,17 @@ nsCaret::GetCaretFrameForNodeOffset(nsFr
   AdjustCaretFrameForLineEnd(&theFrame, &theFrameOffset);
   
   // Mamdouh : modification of the caret to work at rtl and ltr with Bidi
   //
   // Direction Style from visibility->mDirection
   // ------------------
   // NS_STYLE_DIRECTION_LTR : LTR or Default
   // NS_STYLE_DIRECTION_RTL
-  if (IsBidiUI())
+  if (theFrame->PresContext()->BidiEnabled())
   {
     // If there has been a reflow, take the caret Bidi level to be the level of the current frame
     if (aBidiLevel & BIDI_LEVEL_UNDEFINED)
       aBidiLevel = NS_GET_EMBEDDING_LEVEL(theFrame);
 
     int32_t start;
     int32_t end;
     nsIFrame* frameBefore;
--- a/layout/base/tests/multi-range-user-select.html
+++ b/layout/base/tests/multi-range-user-select.html
@@ -105,23 +105,21 @@ function runTest() {
       action(e, 180, 65);
       checkRangeCount(2, e);
       checkRange(0, [0,2,-2,4], e.childNodes[3]);
       checkRange(1, [5,0,6,0], e);
     } else if (test == "#prev5") {
       enableSelection('span3');
       action(e, 440, 65);
       checkRangeCount(1, e);
-      var r = sel.getRangeAt(0);
-      checkRangePoints(r, [e.childNodes[4].firstChild,10,e.childNodes[6],0], e);
+      checkRangePoints(0, [e.childNodes[4].firstChild,10,e.childNodes[6],0], e);
     } else if (test == "#prev6") {
       action(e, 140, 125);
       checkRangeCount(1, e);
-      var r = sel.getRangeAt(0);
-      checkRangePoints(r, [e.childNodes[5].firstChild,2,e.childNodes[6],0], e);
+      checkRangePoints(0, [e.childNodes[5].firstChild,2,e.childNodes[6],0], e);
     } else if (test == "#prev7") {
       if (action == accelDragSelect) {
         accelDragSelect(e, 460, 500, 125);
         checkRanges([[e.childNodes[1].firstChild,0,-1,2], [3,0,-1,4], [5,0,6,0], [6,8,6,10]], e);
       } else {
         action(e, 500, 125);
         checkRanges([[6,0,6,10]], e);
       }
@@ -154,36 +152,33 @@ function runTest() {
         checkRanges([[0,1,0,2], [0,10,-1,2], [3,0,-1,4], [5,0,e.childNodes[5].firstChild,10]], e);
       } else {
         action(e, 30);
         checkRanges([[0,1,0,10]], e);
       }
     } else if (test == "#next2") {
       action(e, 260);
       checkRangeCount(1, e);
-      var r = sel.getRangeAt(0);
-      checkRangePoints(r, [e.childNodes[0],10,e.childNodes[1].firstChild,3], e);
+      checkRangePoints(0, [e.childNodes[0],10,e.childNodes[1].firstChild,3], e);
     } else if (test == "#next3") {
       enableSelection('span2');
       action(e, 400);
       checkRangeCount(1, e);
-      var r = sel.getRangeAt(0);
-      checkRangePoints(r, [e.childNodes[0],10,e.childNodes[2].firstChild,5], e);
+      checkRangePoints(0, [e.childNodes[0],10,e.childNodes[2].firstChild,5], e);
     } else if (test == "#next4") {
       action(e, 180, 65);
       checkRangeCount(2, e);
       checkRange(0, [0,10,-1,2], e);
       checkRange(1, [-1,0,0,2], e.childNodes[3]);
     } else if (test == "#next5") {
       enableSelection('span3');
       action(e, 440, 65);
       checkRangeCount(2, e);
       checkRange(0, [0,10,-1,2], e);
-      var r = sel.getRangeAt(1);
-      checkRangePoints(r, [e.childNodes[3],0,e.childNodes[4].firstChild,10], e);
+      checkRangePoints(1, [e.childNodes[3],0,e.childNodes[4].firstChild,10], e);
     } else if (test == "#next6") {
       action(e, 140, 125);
       checkRangeCount(3, e);
       checkRange(0, [0,10,-1,2], e);
       checkRange(1, [3,0,-1,4], e);
       checkRange(2, [-1,0,0,2], e.childNodes[5]);
     } else if (test == "#next7") {
       if (action == keyRight) {
@@ -192,18 +187,17 @@ function runTest() {
       } else if (action == accelDragSelect) {
         accelDragSelect(e, 460, 500, 125);
         checkRanges([[0,10,-1,2], [3,0,-1,4], [5,0,e.childNodes[5].firstChild,10], [6,8,6,10]], e);
       } else {
         action(e, 500, 125);
         checkRangeCount(3, e);
         checkRange(0, [0,10,-1,2], e);
         checkRange(1, [3,0,-1,4], e);
-        var r = sel.getRangeAt(2);
-        checkRangePoints(r, [e.childNodes[5],0,e.childNodes[6],10], e);
+        checkRangePoints(2, [e.childNodes[5],0,e.childNodes[6],10], e);
       }
     } else if (test == "#next8") {
       if (action == accelDragSelect) {
         sel.removeAllRanges();
         var e = document.querySelector('#select');
         synthesizeMouse(e, 200, 60, {type: "mousedown", accelKey: true});
         synthesizeMouse(e, 180, 60, {type: "mousemove", accelKey: true});
         synthesizeMouse(e, 200, 80, {type: "mousemove", accelKey: true});
--- a/layout/base/tests/selection-utils.js
+++ b/layout/base/tests/selection-utils.js
@@ -119,17 +119,20 @@ function checkRangeText(text, index)
 }
 
 function checkRangeCount(n, e)
 {
   var sel = window.getSelection();
   is(sel.rangeCount, n, e.id + ": Selection range count");
 }
 
-function checkRangePoints(r, expected, e) {
+function checkRangePoints(i, expected, e) {
+  var sel = window.getSelection();
+  if (i >= sel.rangeCount) return;
+  var r = sel.getRangeAt(i);
   is(r.startContainer, expected[0], e.id + ": range.startContainer");
   is(r.startOffset, expected[1], e.id + ": range.startOffset");
   is(r.endContainer, expected[2], e.id + ": range.endContainer");
   is(r.endOffset, expected[3], e.id + ": range.endOffset");
 }
 
 function checkRange(i, expected, e) {
   var sel = window.getSelection();
--- a/layout/base/tests/test_reftests_with_caret.html
+++ b/layout/base/tests/test_reftests_with_caret.html
@@ -11,17 +11,16 @@
       border: none;
       width: 600px;
       height: 400px;
     }
   </style>
 <script type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
-SimpleTest.requestFlakyTimeout("untriaged");
 SimpleTest.requestLongerTimeout(2);
 
 var iframes = [];
 function callbackTestIframe(iframe)
 {
   iframes.push(iframe);
 
   if (iframes.length != 2)
@@ -68,17 +67,17 @@ function createIframe(url,next) {
   var currentIteration = 0;
   function iframeLoadCompleted() {
     var docEl = iframe.contentDocument.documentElement;
     if (docEl.className.indexOf("reftest-wait") >= 0) {
       if (currentIteration++ > MAX_ITERATIONS) {
         ok(false, "iframe load for " + url + " timed out");
         endTest();
       } else {
-        setTimeout(iframeLoadCompleted, 10);
+        setTimeout(iframeLoadCompleted, 0);
       }
       return;
     }
     iframe.remotePageLoaded(function() {
       if (next) {
         setTimeout(function(){createIframe(next,null);}, 0)
       }
     });
--- a/layout/generic/Selection.h
+++ b/layout/generic/Selection.h
@@ -174,16 +174,19 @@ public:
   bool ContainsNode(nsINode& aNode, bool aPartlyContained, mozilla::ErrorResult& aRv);
 
   void Modify(const nsAString& aAlter, const nsAString& aDirection,
               const nsAString& aGranularity, mozilla::ErrorResult& aRv);
 
   bool GetInterlinePosition(mozilla::ErrorResult& aRv);
   void SetInterlinePosition(bool aValue, mozilla::ErrorResult& aRv);
 
+  Nullable<int16_t> GetCaretBidiLevel(mozilla::ErrorResult& aRv) const;
+  void SetCaretBidiLevel(const Nullable<int16_t>& aCaretBidiLevel, mozilla::ErrorResult& aRv);
+
   void ToStringWithFormat(const nsAString& aFormatType,
                           uint32_t aFlags,
                           int32_t aWrapColumn,
                           nsAString& aReturn,
                           mozilla::ErrorResult& aRv);
   void AddSelectionListener(nsISelectionListener* aListener,
                             mozilla::ErrorResult& aRv);
   void RemoveSelectionListener(nsISelectionListener* aListener,
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -708,16 +708,22 @@ nsFrameSelection::ConstrainFrameAndPoint
 }
 
 void
 nsFrameSelection::SetCaretBidiLevel(nsBidiLevel aLevel)
 {
   // If the current level is undefined, we have just inserted new text.
   // In this case, we don't want to reset the keyboard language
   mCaretBidiLevel = aLevel;
+
+  nsRefPtr<nsCaret> caret;
+  if (mShell && (caret = mShell->GetCaret())) {
+    caret->SchedulePaint();
+  }
+
   return;
 }
 
 nsBidiLevel
 nsFrameSelection::GetCaretBidiLevel() const
 {
   return mCaretBidiLevel;
 }
@@ -1007,18 +1013,23 @@ nsFrameSelection::MoveCaret(nsDirection 
       theFrame->GetOffsets(frameStart, frameEnd);
     }
 
     if (context->BidiEnabled())
     {
       switch (aAmount) {
         case eSelectBeginLine:
         case eSelectEndLine:
-          // set the caret Bidi level to the paragraph embedding level
-          SetCaretBidiLevel(NS_GET_BASE_LEVEL(theFrame));
+          // In Bidi contexts, PeekOffset calculates pos.mContentOffset
+          // differently depending on whether the movement is visual or logical.
+          // For visual movement, pos.mContentOffset depends on the direction-
+          // ality of the first/last frame on the line (theFrame), and the caret
+          // directionality must correspond.
+          SetCaretBidiLevel(visualMovement ? NS_GET_EMBEDDING_LEVEL(theFrame) :
+                                             NS_GET_BASE_LEVEL(theFrame));
           break;
 
         default:
           // If the current position is not a frame boundary, it's enough just
           // to take the Bidi level of the current frame
           if ((pos.mContentOffset != frameStart &&
                pos.mContentOffset != frameEnd) ||
               eSelectLine == aAmount) {
@@ -1183,16 +1194,42 @@ Selection::GetInterlinePosition(ErrorRes
 {
   if (!mFrameSelection) {
     aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
     return false;
   }
   return mFrameSelection->GetHint() == CARET_ASSOCIATE_AFTER;
 }
 
+Nullable<int16_t>
+Selection::GetCaretBidiLevel(mozilla::ErrorResult& aRv) const
+{
+  if (!mFrameSelection) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
+    return Nullable<int16_t>();
+  }
+  nsBidiLevel caretBidiLevel = mFrameSelection->GetCaretBidiLevel();
+  return (caretBidiLevel & BIDI_LEVEL_UNDEFINED) ?
+    Nullable<int16_t>() : Nullable<int16_t>(caretBidiLevel);
+}
+
+void
+Selection::SetCaretBidiLevel(const Nullable<int16_t>& aCaretBidiLevel, mozilla::ErrorResult& aRv)
+{
+  if (!mFrameSelection) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
+    return;
+  }
+  if (aCaretBidiLevel.IsNull()) {
+    mFrameSelection->UndefineCaretBidiLevel();
+  } else {
+    mFrameSelection->SetCaretBidiLevel(aCaretBidiLevel.Value());
+  }
+}
+
 nsPrevNextBidiLevels
 nsFrameSelection::GetPrevNextBidiLevels(nsIContent *aNode,
                                         uint32_t    aContentOffset,
                                         bool        aJumpLines) const
 {
   return GetPrevNextBidiLevels(aNode, aContentOffset, mHint, aJumpLines);
 }
 
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -8990,29 +8990,16 @@ nsTextFrame::AdjustOffsetsForBidi(int32_
     int32_t prevOffset = prev->GetContentOffset();
     aStart = std::max(aStart, prevOffset);
     aEnd = std::max(aEnd, prevOffset);
     prev->ClearTextRuns();
   }
 
   mContentOffset = aStart;
   SetLength(aEnd - aStart, nullptr, 0);
-
-  /**
-   * After inserting text the caret Bidi level must be set to the level of the
-   * inserted text.This is difficult, because we cannot know what the level is
-   * until after the Bidi algorithm is applied to the whole paragraph.
-   *
-   * So we set the caret Bidi level to UNDEFINED here, and the caret code will
-   * set it correctly later
-   */
-  nsRefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
-  if (frameSelection) {
-    frameSelection->UndefineCaretBidiLevel();
-  }
 }
 
 /**
  * @return true if this text frame ends with a newline character.  It should return
  * false if it is not a text frame.
  */
 bool
 nsTextFrame::HasSignificantTerminalNewline() const
--- a/layout/generic/test/test_bug496275.html
+++ b/layout/generic/test/test_bug496275.html
@@ -140,66 +140,71 @@ function run() {
   sel.modify("move", "forward", "character");
   isAt("p3", 14, "p3", 14, "test 5");
 
   //
   // Test RTL text within a dir=LTR div.
   //
   $("ltr").focus();
   sel.collapse($("l1"), 0);
+  SpecialPowers.wrap(sel).caretBidiLevel = 1;
   isAt("l1", 0, "l1", 0, "test 6a");
   sel.modify("Move", "Left", "Character");
   isAt("l1", 1, "l1", 1, "test 6b");
   sel.modify("Extend", "Backward", "Character");
   isAt("l1", 1, "l1", 0, "test 6c");
   sel.modify("extend", "forward", "character");
   isAt("l1", 1, "l1", 1, "test 6d");
   sel.modify("Extend", "Right", "Character");
   isAt("l1", 1, "l1", 0, "test 6e");
 
   sel.collapse($("l1"), 0);
+  SpecialPowers.wrap(sel).caretBidiLevel = 1;
   sel.modify("move", "left", "character");
   sel.modify("extend", "right", "Word");
   isAt("l1", 1, "l1", 3, "test 7a");
   sel.modify("move", "left", "word");
   isAt("l1", 3, "l1", 3, "test 7b");
   sel.modify("move", "forward", "word");
   isAt("l1", 9, "l1", 9, "test 7c");
   sel.modify("extend", "backward", "word");
   isAt("l1", 9, "l1", 4, "test 7d");
   sel.modify("move", "left", "word");
   isAt("l1", 3, "l1", 3, "test 7e");
 
   sel.collapse($("l1"), 0);
+  SpecialPowers.wrap(sel).caretBidiLevel = 1;
   sel.modify("extend", "left", "lineboundary");
   isAt("l1", 0, "l1", 3, "test 8a");
   sel.modify("move", "forward", "lineboundary");
   isAt("l1", 9, "l1", 9, "test 8b");
   sel.modify("extend", "backward", "lineboundary");
   isAt("l1", 9, "l1", 0, "test 8c");
   sel.modify("move", "left", "lineboundary");
   isAt("l1", 3, "l1", 3, "test 8d");
   sel.modify("extend", "forward", "lineboundary");
   isAt("l1", 3, "l1", 9, "test 8e");
 
   // Put the cursor at the left edge of the first line so that when we go up
   // and down, where we end up doesn't depend on how the characters line up.
   sel.collapse($("l1"), 0);
+  SpecialPowers.wrap(sel).caretBidiLevel = 1;
   sel.modify("move", "left", "lineboundary");
   isAt("l1", 3, "l1", 3, "test 9a");
   sel.modify("move", "forward", "Line");
   isAt("l2", 0, "l2", 0, "test 9b");
   sel.modify("extend", "backward", "Line");
   // Apparently going up from the beginning of the line takes us to offset 3 in
   // the line above.  This is a little weird, but it's consistent with how the
   // keyboard works.
   isAt("l2", 0, "l1", 3, "test 9c");
 
   // Same test as above, now with absolute directions.
   sel.collapse($("l1"), 0);
+  SpecialPowers.wrap(sel).caretBidiLevel = 1;
   sel.modify("move", "left", "lineboundary");
   isAt("l1", 3, "l1", 3, "test 10a");
   sel.modify("move", "right", "line");
   isAt("l2", 0, "l2", 0, "test 10b");
   sel.modify("extend", "left", "line");
   isAt("l2", 0, "l1", 3, "test 10c");
 
   //
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -34,17 +34,17 @@ fuzzy-if(winWidget,102,580) fuzzy-if(d2d
 == rotate3d-2a.html rotatey-1-ref.html
 != backface-visibility-1a.html about:blank
 == backface-visibility-1b.html about:blank
 == backface-visibility-1c.html about:blank
 fuzzy-if(winWidget&&!layersGPUAccelerated,1,251) == backface-visibility-2.html backface-visibility-2-ref.html
 == backface-visibility-3.html backface-visibility-3-ref.html
 != perspective-origin-1a.html rotatex-perspective-1a.html
 random-if(Android&&AndroidVersion==17) == perspective-origin-1b.html perspective-origin-1a.html
-random-if(Android&&!browserIsRemote) == perspective-origin-2a.html perspective-origin-2-ref.html # bug 732568
+fuzzy(3,99) random-if(Android&&!browserIsRemote) == perspective-origin-2a.html perspective-origin-2-ref.html # subpixel AA, bug 732568
 fuzzy-if(winWidget&&!layersGPUAccelerated,1,61) == perspective-origin-3a.html perspective-origin-3-ref.html
 == perspective-origin-4a.html perspective-origin-4-ref.html
 != sorting-1a.html sorting-1-ref.html
 # Parallel planes, different z depth
 == sorting-2a.html sorting-2-ref.html
 # Parallel planes, same z depth (shouldn't be sorted!)
 == sorting-2b.html sorting-2-ref.html
 == sorting-3a.html green-rect.html
@@ -52,14 +52,14 @@ fuzzy-if(winWidget&&!layersGPUAccelerate
 == rotatex-transformorigin-1a.html rotatex-transformorigin-1-ref.html
 fuzzy-if((gtk2Widget&&layersOMTC)||(winWidget&&!layersGPUAccelerated),1,86) == overflow-hidden-1a.html overflow-hidden-1-ref.html
 == transform-style-flat-1a.html transform-style-flat-1-ref.html
 pref(layout.css.will-change.enabled,true) == willchange-containing-block.html?willchange willchange-containing-block.html?ref
 pref(layout.css.will-change.enabled,true) != willchange-containing-block.html?willchange willchange-containing-block.html?noblock
 fuzzy-if(winWidget&&!layersGPUAccelerated,1,606) == scroll-perspective-1.html scroll-perspective-1-ref.html
 # Bugs
 fails-if(!layersGPUAccelerated) == 1035611-1.html 1035611-1-ref.html # Bug 1072898 for !layersGPUAccelerated failures
-== animate-cube-radians.html animate-cube-radians-ref.html
-fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated,16,6) fuzzy-if(Mulet,16,9) == animate-cube-radians-zoom.html animate-cube-radians-zoom-ref.html
+fuzzy(3,99) == animate-cube-radians.html animate-cube-radians-ref.html # subpixel AA
+fuzzy(3,99) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated,16,6) fuzzy-if(Mulet,16,9) == animate-cube-radians-zoom.html animate-cube-radians-zoom-ref.html
 != animate-cube-radians-ref.html animate-cube-radians-zoom-ref.html
-== animate-cube-degrees.html animate-cube-degrees-ref.html
+fuzzy(3,99) == animate-cube-degrees.html animate-cube-degrees-ref.html # subpixel AA
 == animate-cube-degrees-zoom.html animate-cube-degrees-zoom-ref.html
 != animate-cube-degrees-ref.html animate-cube-degrees-zoom-ref.html
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-003.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-003.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'top', 'height' and 'bottom' are 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-003-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr' and 'top', 'height' and 'bottom' are 'auto', then the height becomes shrink-to-fit and then solve for 'bottom'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'top', 'height' and 'bottom' are 'auto', then set 'top' to the static position, then the height is based on the content and then solve for 'bottom'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-2col-3row-320x320.png");
       color: transparent;
@@ -39,76 +39,76 @@
       color: green;
       height: auto;
       position: absolute;
       top: auto;
     }
 
 /*
 "
-If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
 "
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
 
 "
+If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
+
 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
-      0px : top: auto
+    160px : top: auto: set to static position
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
   (solve) : bottom: auto
     =====================
     320px : height of containing block
 
 gives us:
 
-      0px : top: auto
+    160px : top: auto: set to static position
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
   (solve) : bottom: auto
     =====================
     320px : height of containing block
 
-And so computed bottom value must be 240px;
+And so computed bottom value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-005.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-005.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'left', 'width' and 'right' are 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vrl-004-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr' and 'left', 'width' and 'right' are 'auto', then the width becomes shrink-to-fit and then solve for 'right'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'left', 'width' and 'right' are 'auto', then set 'left' to the static position, the width becomes shrink-to-fit and then solve for 'right'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-3col-2row-320x320.png");
       color: transparent;
@@ -40,69 +40,67 @@
       -webkit-writing-mode: vertical-lr;
       writing-mode: tb-lr; /* IE11 */
       writing-mode: vertical-lr;
     }
 
 /*
 "
 If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
-"
 
-"
 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
-      0px : left: auto
+    160px : left: auto: set to static position
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
-    (shrink-to-fit) : width: auto
+  (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
   (solve) : right: auto
     =====================
     320px : width of containing block
 
 gives us:
 
-      0px : left: auto
+    160px : left: auto: set to static position
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
      80px : (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
   (solve) : right: auto
     =====================
     320px : width of containing block
 
-And so computed right value must be 240px;
+And so computed right value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-007.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-007.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'top', 'height' and 'bottom' are 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-007-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr' and 'top', 'height' and 'bottom' are 'auto', then the height becomes shrink-to-fit and then solve for 'bottom'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'top', 'height' and 'bottom' are 'auto', then set 'top' to the static position, then the height is based on the content and then solve for 'bottom'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   html
     {
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
@@ -44,76 +44,76 @@
       color: green;
       height: auto;
       position: absolute;
       top: auto;
     }
 
 /*
 "
-If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
 "
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
 
 "
+If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
+
 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
-      0px : top: auto
+    160px : top: auto: set to static position
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
   (solve) : bottom: auto
     =====================
     320px : height of containing block
 
 gives us:
 
-      0px : top: auto
+    160px : top: auto: set to static position
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
   (solve) : bottom: auto
     =====================
     320px : height of containing block
 
-And so computed bottom value must be 240px;
+And so computed bottom value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-009.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-009.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: rtl' and 'top', 'height' and 'bottom' are 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-009-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'rtl' and 'top', 'height' and 'bottom' are 'auto', then the height becomes shrink-to-fit and then solve for 'top'." />
+  <meta name="assert" content="When 'direction' is 'rtl' and 'top', 'height' and 'bottom' are 'auto', then set 'bottom' to the static position, the height is based on the content and then solve for 'top'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-2col-2row-320x320.png");
       color: transparent;
@@ -39,76 +39,76 @@
       color: green;
       height: auto;
       position: absolute;
       top: auto;
     }
 
 /*
 "
-If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
 "
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
 
 "
-3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
+If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
+
+1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-      0px : bottom: auto
+    160px : bottom: auto: set to static position
     =====================
     320px : height of containing block
 
 gives us:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-      0px : bottom: auto
+    160px : bottom: auto: set to static position
     =====================
     320px : height of containing block
 
-And so computed top value must be 240px;
+And so computed top value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-011.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-011.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: rtl' and 'left', 'width' and 'right' are 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-009-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'rtl' and 'left', 'width' and 'right' are 'auto', then the width becomes shrink-to-fit and then solve for 'left'." />
+  <meta name="assert" content="When 'direction' is 'rtl' and 'left', 'width' and 'right' are 'auto', then set 'right' to the static position, the width becomes shrink-to-fit and then solve for 'left'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-2col-2row-320x320.png");
       color: transparent;
@@ -40,69 +40,67 @@
       -webkit-writing-mode: vertical-lr;
       writing-mode: tb-lr; /* IE11 */
       writing-mode: vertical-lr;
     }
 
 /*
 "
 If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
-"
 
-"
 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
   (solve) : left: auto
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
-    (shrink-to-fit) : width: auto
+  (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
-    160px : right: auto
+    160px : right: auto: set to static position
     =====================
     320px : width of containing block
 
 gives us:
 
   (solve) : left: auto
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
      80px : (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
-    160px : right: auto
+    160px : right: auto: set to static position
     =====================
     320px : width of containing block
 
-And so computed left value must be 80px;
+And so computed left value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-013.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-013.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: rtl' and 'top', 'height' and 'bottom' are 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-013-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'rtl' and 'top', 'height' and 'bottom' are 'auto', then the height becomes shrink-to-fit and then solve for 'top'." />
+  <meta name="assert" content="When 'direction' is 'rtl' and 'top', 'height' and 'bottom' are 'auto', then set 'bottom' to the static position, the height is based on the content and then solve for 'top'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   html
     {
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
@@ -43,76 +43,76 @@
       color: green;
       height: auto;
       position: absolute;
       top: auto;
     }
 
 /*
 "
-If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
 "
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
 
 "
-3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
+If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0. Then, if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position and apply rule number three below; otherwise, set 'right' to the static position and apply rule number one below.
+
+1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-      0px : bottom: auto
+    160px : bottom: auto: set to static position
     =====================
     320px : height of containing block
 
 gives us:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-      0px : bottom: auto
+    160px : bottom: auto: set to static position
     =====================
     320px : height of containing block
 
-And so computed top value must be 240px;
+And so computed top value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-015.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-015.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'top', 'height' are 'auto' and bottom is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-009-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr'  and 'top', 'height' are 'auto' and bottom is not 'auto', then the height becomes shrink-to-fit and then solve for 'top'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'top', 'height' are 'auto' and bottom is not 'auto', then the height is based on the content and then solve for 'top'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-2col-2row-320x320.png");
       color: transparent;
@@ -39,75 +39,74 @@
       color: green;
       height: auto;
       position: absolute;
       top: auto;
     }
 
 /*
 "
-set 'auto' values for 'margin-left' and 'margin-right' to 0, and pick the one of the following six rules that applies.
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
 
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
 "
 
-
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
     160px : bottom
     =====================
     320px : height of containing block
 
 gives us:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
     160px : bottom
     =====================
     320px : height of containing block
 
-And so computed bottom value must be 80px;
+And so computed top value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-017.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-017.xht
@@ -50,21 +50,21 @@ 1. 'left' and 'width' are 'auto' and 'ri
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
   (solve) : left: auto
   +
       0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
-    (shrink-to-fit) : width: auto
+  (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
       0px : margin-right
   +
     160px : right
@@ -72,33 +72,33 @@ So:
     320px : width of containing block
 
 gives us:
 
   (solve) : left: auto
   +
       0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
      80px : (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
       0px : margin-right
   +
     160px : right
     =====================
     320px : width of containing block
 
-And so computed left value must be 80px;
+And so computed left value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-019.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-019.xht
@@ -1,23 +1,23 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 
  <head>
 
-  <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'top' and 'height' are 'auto and 'bottom' is not 'auto'</title>
+  <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'top' and 'height' are 'auto' and 'bottom' is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-013-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr' and 'top' and 'height' are 'auto and 'bottom' is not 'auto', then the height becomes shrink-to-fit and then solve for 'top'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then the height is based on the content and then solve for 'top'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   html
     {
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
@@ -29,89 +29,88 @@
     {
       background: red url("support/bg-red-2col-2row-320x320.png");
       color: transparent;
       direction: ltr;
       font: 80px/1 Ahem;
       height: 320px;
       position: relative;
       width: 320px;
-
     }
 
   div#containing-block > span
     {
       background-color: red;
       bottom: 2em;
       color: green;
       height: auto;
       position: absolute;
       top: auto;
     }
 
 /*
 "
-set 'auto' values for 'margin-left' and 'margin-right' to 0, and pick the one of the following six rules that applies.
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
 
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
     160px : bottom
     =====================
     320px : height of containing block
 
 gives us:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
     160px : bottom
     =====================
     320px : height of containing block
 
-And so computed top value must be 80px;
+And so computed top value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-021.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-021.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: rtl' and 'top' and 'height' are 'auto and 'bottom' is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-009-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'rtl' and 'top' and 'height' are 'auto and 'bottom' is not 'auto', then the height becomes shrink-to-fit and then solve for 'top'." />
+  <meta name="assert" content="When 'direction' is 'rtl' and 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then the height is based on the content and then solve for 'top'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-2col-2row-320x320.png");
       color: transparent;
@@ -39,74 +39,74 @@
       color: green;
       height: auto;
       position: absolute;
       top: auto;
     }
 
 /*
 "
-set 'auto' values for 'margin-left' and 'margin-right' to 0, and pick the one of the following six rules that applies.
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
 
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
     160px : bottom
     =====================
     320px : height of containing block
 
 gives us:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
     160px : bottom
     =====================
     320px : height of containing block
 
-And so computed top value must be 80px;
+And so computed top value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-023.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-023.xht
@@ -29,78 +29,76 @@
     }
 
   div#containing-block > span
     {
       background-color: red;
       color: green;
       left: auto;
       position: absolute;
-      right: auto;
+      right: 2em;
       width: auto;
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
       writing-mode: tb-lr; /* IE11 */
       writing-mode: vertical-lr;
     }
 
 /*
 "
-set 'auto' values for 'margin-left' and 'margin-right' to 0, and pick the one of the following six rules that applies.
-
 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
   (solve) : left: auto
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
-    (shrink-to-fit) : width: auto
+  (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
      160px : right
     =====================
     320px : width of containing block
 
 gives us:
 
   (solve) : left: auto
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
      80px : (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
      160px : right
     =====================
     320px : width of containing block
 
-And so computed left value must be 80px;
+And so computed left value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-025.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-025.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: rtl' and 'top' and 'height' are 'auto' and 'bottom' is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-013-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'rtl' and 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then the height becomes shrink-to-fit and then solve for 'top'." />
+  <meta name="assert" content="When 'direction' is 'rtl' and 'top', 'height' are 'auto' and bottom is not 'auto', then the height is based on the content and then solve for 'top'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   html
     {
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
@@ -43,74 +43,74 @@
       color: green;
       height: auto;
       position: absolute;
       top: auto;
     }
 
 /*
 "
-set 'auto' values for 'margin-left' and 'margin-right' to 0, and pick the one of the following six rules that applies.
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
 
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
     160px : bottom
     =====================
     320px : height of containing block
 
 gives us:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
     160px : bottom
     =====================
     320px : height of containing block
 
-And so computed top value must be 80px;
+And so computed top value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-027.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-027.xht
@@ -1,23 +1,23 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 
  <head>
 
-  <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'top' and 'bottom are 'auto' and 'height' is not 'auto'</title>
+  <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'top' and 'bottom' are 'auto' and 'height' is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
-  <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
+  <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height" title="10.6.4 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-003-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr' and 'top' and 'bottom are 'auto' and 'height' is not 'auto', then set 'top' to static position and solve for 'bottom'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to static position and solve for 'bottom'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-2col-3row-320x320.png");
       color: transparent;
@@ -39,72 +39,52 @@
       color: green;
       height: 1em;
       position: absolute;
       top: auto;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position. Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr').
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
-    160px : top: auto
+    160px : top: auto: set to static position
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
      80px : height
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-    (solve): bottom: auto
+   (solve) : bottom: auto
     =====================
     320px : height of containing block
 
-gives us:
-
-    160px : top: auto
-  +
-      0px : margin-top: auto
-  +
-      0px : border-top-width
-  +
-      0px : padding-top
-  +
-     80px : height
-  +
-      0px : padding-bottom
-  +
-      0px : border-bottom-width
-  +
-      0px : margin-bottom: auto
-  +
-    (solve): bottom: auto
-    =====================
-    320px : height of containing block
-
-And so computed bottom value must be 80px;
+And so computed bottom value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-029.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-029.xht
@@ -46,59 +46,59 @@
 "
 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position. Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr').
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
-    160px : left: auto
+    160px : left: auto: set to static position
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
      80px : width
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
-    (solve): right: auto
+  (solve) : right: auto
     =====================
     320px : width of containing block
 
 gives us:
 
-    160px : left: auto
+    160px : left: auto: set to static position
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
      80px : width
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
-    (solve): right: auto
+  (solve) : right: auto
     =====================
     320px : width of containing block
 
-And so computed right value must be 80px;
+And so computed right value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-031.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-031.xht
@@ -1,23 +1,23 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 
  <head>
 
-  <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'top' and 'bottom are 'auto' and 'height' is not 'auto'</title>
+  <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'top' and 'bottom' are 'auto' and 'height' is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-007-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr' and 'top' and 'bottom are 'auto' and 'height' is not 'auto', then set 'top' to static position and solve for 'bottom'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to static position and solve for 'bottom'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   html
     {
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
@@ -44,72 +44,52 @@
       color: green;
       height: 1em;
       position: absolute;
       top: auto;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position. Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr').
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
-    160px : top: auto
+    160px : top: auto: set to static position
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
      80px : height
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-    (solve): bottom: auto
+  (solve) : bottom: auto
     =====================
     320px : height of containing block
 
-gives us:
-
-    160px : top: auto
-  +
-      0px : margin-top: auto
-  +
-      0px : border-top-width
-  +
-      0px : padding-top
-  +
-     80px : height
-  +
-      0px : padding-bottom
-  +
-      0px : border-bottom-width
-  +
-      0px : margin-bottom: auto
-  +
-    (solve): bottom: auto
-    =====================
-    320px : height of containing block
-
-And so computed bottom value must be 80px;
+And so computed bottom value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-033.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-033.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: rtl' and 'top' and 'bottom' are 'auto and 'height' is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-009-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'rtl' and 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'bottom' to static position and solve for 'top'." />
+  <meta name="assert" content="When 'direction' is 'rtl' and 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to static position and solve for 'bottom'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-2col-2row-320x320.png");
       color: transparent;
@@ -39,72 +39,52 @@
       color: green;
       height: 1em;
       position: absolute;
       top: auto;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position. Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr').
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
      80px : height
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-    160px : bottom: auto
+    160px : bottom: auto: set to static position
     =====================
     320px : height of containing block
 
-gives us:
-
-  (solve) : top: auto
-  +
-      0px : margin-top: auto
-  +
-      0px : border-top-width
-  +
-      0px : padding-top
-  +
-     80px : height
-  +
-      0px : padding-bottom
-  +
-      0px : border-bottom-width
-  +
-      0px : margin-bottom: auto
-  +
-    160px : bottom: auto
-    =====================
-    320px : height of containing block
-
-And so computed top value must be 80px;
+And so computed top value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-035.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-035.xht
@@ -48,57 +48,35 @@ 2. 'left' and 'right' are 'auto' and 'wi
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
   (solve) : left: auto
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
      80px : width
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
     160px : right: auto
     =====================
     320px : width of containing block
 
-gives us:
-
-  (solve) : left: auto
-  +
-      0px : margin-left: auto
-  +
-      0px : border-top-width
-  +
-      0px : padding-top
-  +
-     80px : width
-  +
-      0px : padding-right
-  +
-      0px : border-right-width
-  +
-      0px : margin-right: auto
-  +
-    160px : right: auto
-    =====================
-    320px : width of containing block
-
-And so computed left value must be 80px;
+And so computed left value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-037.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-037.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: rtl' and 'top' and 'bottom' are 'auto' and 'height' is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-013-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'rtl' and 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'bottom' to static position and then solve for 'top'." />
+  <meta name="assert" content="When 'direction' is 'rtl' and 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to static position and solve for 'bottom'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   html
     {
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
@@ -43,72 +43,52 @@
       color: green;
       height: 1em;
       position: absolute;
       top: auto;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of the element establishing the static-position containing block is 'ltr' set 'left' to the static position, otherwise set 'right' to the static position. Then solve for 'left' (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr').
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
      80px : height
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-    160px : bottom
+    160px : bottom: auto: set to static position
     =====================
     320px : height of containing block
 
-gives us:
-
-  (solve) : top: auto
-  +
-      0px : margin-top: auto
-  +
-      0px : border-top-width
-  +
-      0px : padding-top
-  +
-     80px : height
-  +
-      0px : padding-bottom
-  +
-      0px : border-bottom-width
-  +
-      0px : margin-bottom: auto
-  +
-    160px : bottom
-    =====================
-    320px : height of containing block
-
-And so computed top value must be 80px;
+And so computed top value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-039.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-039.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'height' and 'bottom' are 'auto' and 'top' is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-009-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr' and 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height becomes shrink-to-fit and then solve for 'bottom'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height is based on the content and then solve for 'bottom'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-2col-2row-320x320.png");
       color: transparent;
@@ -38,74 +38,75 @@
       bottom: auto;
       color: green;
       height: auto;
       position: absolute;
       top: 1em;
     }
 
 /*
+"
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
 
 "
 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
      80px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-   (solve): bottom: auto
+  (solve) : bottom: auto
     =====================
     320px : height of containing block
 
 gives us:
 
      80px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-   (solve): bottom: auto
+  (solve) : bottom: auto
     =====================
     320px : height of containing block
 
-And so computed bottom value must be 160px;
+And so computed bottom value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-041.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-041.xht
@@ -49,57 +49,57 @@ 3. 'width' and 'right' are 'auto' and 'l
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
      80px : left
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
-    (shrink-to-fit) : width: auto
+  (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
-   (solve): right: auto
+  (solve) : right: auto
     =====================
     320px : width of containing block
 
 gives us:
 
      80px : left
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
       0px : border-top-width
   +
       0px : padding-top
   +
      80px : (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
-   (solve): right: auto
+  (solve) : right: auto
     =====================
     320px : width of containing block
 
-And so computed right value must be 160px;
+And so computed right value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-043.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-043.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'height' and 'bottom' are 'auto' and 'top' is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-013-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr' and 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height becomes shrink-to-fit and then solve for 'bottom'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height is based on the content and then solve for 'bottom'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   html
     {
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
@@ -42,74 +42,75 @@
       bottom: auto;
       color: green;
       height: auto;
       position: absolute;
       top: 1em;
     }
 
 /*
+"
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
 
 "
 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
      80px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-   (solve): bottom: auto
+  (solve) : bottom: auto
     =====================
     320px : height of containing block
 
 gives us:
 
      80px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-    (solve): bottom: auto
+   (solve) : bottom: auto
     =====================
     320px : height of containing block
 
-And so computed bottom value must be 160px;
+And so computed bottom value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-045.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-045.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: rtl' and 'height' and 'bottom' are 'auto' and 'top' is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-009-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'rtl' and 'top', 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height becomes shrink-to-fit and then solve for 'bottom'." />
+  <meta name="assert" content="When 'direction' is 'rtl' and 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height is based on the content and then solve for 'bottom'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-2col-2row-320x320.png");
       color: transparent;
@@ -38,74 +38,75 @@
       bottom: auto;
       color: green;
       height: auto;
       position: absolute;
       top: 1em;
     }
 
 /*
+"
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
 
 "
 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
      80px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-   (solve): bottom: auto
+  (solve) : bottom: auto
     =====================
     320px : height of containing block
 
 gives us:
 
      80px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
-   (solve): bottom: auto
+  (solve) : bottom: auto
     =====================
     320px : height of containing block
 
-And so computed bottom value must be 160px;
+And so computed bottom value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-047.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-047.xht
@@ -38,68 +38,67 @@
       width: auto;
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
       writing-mode: tb-lr; /* IE11 */
       writing-mode: vertical-lr;
     }
 
 /*
-
 "
 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
      80px : left
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
-    (shrink-to-fit) : width: auto
+  (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
-   (solve): right: auto
+  (solve) : right: auto
     =====================
     320px : width of containing block
 
 gives us:
 
      80px : left
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
      80px : (shrink-to-fit) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
-   (solve): right: auto
+  (solve) : right: auto
     =====================
     320px : width of containing block
 
-And so computed right value must be 160px;
+And so computed right value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-049.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-049.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: rtl' and 'height' and 'bottom' are 'auto' and 'top' is not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-013-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'rtl' and 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height becomes shrink-to-fit and then solve for 'bottom'." />
+  <meta name="assert" content="When 'direction' is 'rtl' and 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height is based on the content and then solve for 'bottom'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   html
     {
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
@@ -42,74 +42,75 @@
       bottom: auto;
       color: green;
       height: auto;
       position: absolute;
       top: 1em;
     }
 
 /*
+"
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
 
 "
 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
-      80px: top
+     80px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-    (shrink-to-fit) : height: auto
+  (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
   (solve) : bottom: auto
     =====================
     320px : height of containing block
 
 gives us:
 
-      80px: top
+     80px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : (shrink-to-fit) : height: auto
+     80px : (based on the content) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
   (solve) : bottom: auto
     =====================
     320px : height of containing block
 
-And so computed bottom value must be 160px;
+And so computed bottom value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-051.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-051.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'top' is 'auto' and 'height' and 'bottom' are not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-003-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr' and 'top' is 'auto' and 'height' and 'bottom' are not 'auto', then  solve for 'top'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'top' is 'auto' and 'height' and 'bottom' are not 'auto', then solve for 'top'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-2col-3row-320x320.png");
       color: transparent;
@@ -38,52 +38,53 @@
       bottom: 1em;
       color: green;
       height: 1em;
       position: absolute;
       top: auto;
     }
 
 /*
+"
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
 
 "
 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : height: auto
+     80px : height
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
      80px : bottom
     =====================
     320px : height of containing block
 
-And so computed top value must be 160px;
+And so computed top value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-053.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-053.xht
@@ -48,35 +48,35 @@ 4. 'left' is 'auto', 'width' and 'right'
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
   (solve) : left: auto
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
-     80px : width: auto
+     80px : width
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
      80px : right
     =====================
     320px : width of containing block
 
-And so computed left value must be 160px;
+And so computed left value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-055.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-055.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'top' is 'auto' and 'height' and 'bottom' are not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-007-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr' and 'top' is 'auto' and 'height' and 'bottom' are not 'auto', then then solve for 'top'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'top' is 'auto' and 'height' and 'bottom' are not 'auto', then solve for 'top'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   html
     {
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
@@ -43,50 +43,52 @@
       color: green;
       height: 1em;
       position: absolute;
       top: auto;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : height: auto
+     80px : height
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
      80px : bottom
     =====================
     320px : height of containing block
 
-And so computed top value must be 160px;
+And so computed top value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-057.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-057.xht
@@ -39,50 +39,52 @@
       color: green;
       height: 1em;
       position: absolute;
       top: auto;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
-     80px : height: auto
+     80px : height
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
      80px : bottom
     =====================
     320px : height of containing block
 
-And so computed top value must be 160px;
+And so computed top value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-059.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-059.xht
@@ -48,35 +48,35 @@ 4.'left' is 'auto', 'width' and 'right' 
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
   (solve) : left: auto
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
      80px : width
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
      80px : right
     =====================
     320px : width of containing block
 
-And so computed left value must be 160px;
+And so computed left value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-061.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-061.xht
@@ -43,52 +43,55 @@
       color: green;
       height: 1em;
       position: absolute;
       top: auto;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
   (solve) : top: auto
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
      80px : height
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
      80px : bottom
     =====================
     320px : height of containing block
 
-And so computed top value must be 160px;
+And so computed top value must be 160px .
 */
 
+
   ]]></style>
 
  </head>
 
  <body>
 
   <p><img src="support/pass-cdts-abs-pos-non-replaced.png" width="246" height="36" alt="Image download support must be enabled" /></p>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-063.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-063.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: ltr' and 'height' is 'auto' and 'top' and 'bottom' are not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-003-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'ltr' and 'height' is 'auto' and 'top' and 'bottom' are not 'auto', then then solve for 'height'." />
+  <meta name="assert" content="When 'direction' is 'ltr' and 'height' is 'auto' and 'top' and 'bottom' are not 'auto', then solve for 'height'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   div#containing-block
     {
       background: red url("support/bg-red-2col-3row-320x320.png");
       color: transparent;
@@ -29,66 +29,68 @@
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
       writing-mode: tb-lr; /* IE11 */
       writing-mode: vertical-lr;
     }
 
   div#containing-block > span
     {
-      background-color: red;
+      background-color: green;
       bottom: 1em;
-      color: green;
       height: auto;
       position: absolute;
       top: 2em;
+      width: 1em;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
     160px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
   (solve) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
      80px : bottom
     =====================
     320px : height of containing block
 
-And so computed height value must be 80px;
+And so computed height value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
   <p><img src="support/pass-cdts-abs-pos-non-replaced.png" width="246" height="36" alt="Image download support must be enabled" /></p>
 
-  <div id="containing-block">1 2 34<span>X</span></div>
+  <div id="containing-block">1 2 34<span></span></div>
 
  </body>
 </html>
\ No newline at end of file
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-065.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-065.xht
@@ -25,18 +25,18 @@
       font: 80px/1 Ahem;
       height: 320px;
       position: relative;
       width: 320px;
     }
 
   div#containing-block > span
     {
-      background-color: red;
-      color: green;
+      background-color: green;
+      height: 1em;
       left: 2em;
       position: absolute;
       right: 1em;
       width: auto;
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
       writing-mode: tb-lr; /* IE11 */
       writing-mode: vertical-lr;
@@ -48,41 +48,41 @@ 5. 'width' is 'auto', 'left' and 'right'
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
     160px : left: auto
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
   (solve) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
      80px : right: auto
     =====================
     320px : width of containing block
 
-And so computed width value must be 80px;
+And so computed width value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
   <p><img src="support/pass-cdts-abs-pos-non-replaced.png" width="246" height="36" alt="Image download support must be enabled" /></p>
 
-  <div id="containing-block">1 2 34<span>X</span></div>
+  <div id="containing-block">1 2 34<span></span></div>
 
  </body>
 </html>
\ No newline at end of file
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-067.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-067.xht
@@ -33,66 +33,68 @@
       font: 80px/1 Ahem;
       height: 320px;
       position: relative;
       width: 320px;
     }
 
   div#containing-block > span
     {
-      background-color: red;
+      background-color: green;
       bottom: 1em;
-      color: green;
       height: auto;
       position: absolute;
       top: 2em;
+      width: 1em;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
     160px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
   (solve) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
      80px : bottom
     =====================
     320px : height of containing block
 
-And so computed height value must be 80px;
+And so computed height value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
   <p><img src="support/pass-cdts-abs-pos-non-replaced.png" width="246" height="36" alt="Image download support must be enabled" /></p>
 
-  <div id="containing-block">1 2 34<span>X</span></div>
+  <div id="containing-block">1 2 34<span></span></div>
 
  </body>
 </html>
\ No newline at end of file
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-069.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-069.xht
@@ -29,66 +29,68 @@
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
       writing-mode: tb-lr; /* IE11 */
       writing-mode: vertical-lr;
     }
 
   div#containing-block > span
     {
-      background-color: red;
+      background-color: green;
       bottom: 1em;
-      color: green;
       height: auto;
       position: absolute;
       top: 2em;
+      width: 1em;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
     160px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
   (solve) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
      80px : bottom
     =====================
     320px : height of containing block
 
-And so computed height value must be 80px;
+And so computed height value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
   <p><img src="support/pass-cdts-abs-pos-non-replaced.png" width="246" height="36" alt="Image download support must be enabled" /></p>
 
-  <div id="containing-block">1 2 34<span>X</span></div>
+  <div id="containing-block">1 2 34<span></span></div>
 
  </body>
 </html>
\ No newline at end of file
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-071.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-071.xht
@@ -25,18 +25,18 @@
       font: 80px/1 Ahem;
       height: 320px;
       position: relative;
       width: 320px;
     }
 
   div#containing-block > span
     {
-      background-color: red;
-      color: green;
+      background-color: green;
+      height: 1em;
       left: 2em;
       position: absolute;
       right: 1em;
       width: auto;
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
       writing-mode: tb-lr; /* IE11 */
       writing-mode: vertical-lr;
@@ -48,41 +48,41 @@ 5. 'width' is 'auto', 'left' and 'right'
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
     160px : left
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
   (solve) : width: auto
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
      80px : right
     =====================
     320px : width of containing block
 
-And so computed width value must be 80px;
+And so computed width value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
   <p><img src="support/pass-cdts-abs-pos-non-replaced.png" width="246" height="36" alt="Image download support must be enabled" /></p>
 
-  <div id="containing-block">1 2 34<span>X</span></div>
+  <div id="containing-block">1 2 34<span></span></div>
 
  </body>
 </html>
\ No newline at end of file
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-073.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-073.xht
@@ -7,17 +7,17 @@
   <title>CSS Writing Modes Test: absolutely positioned non-replaced element - 'direction: rtl' and 'height' is 'auto' and 'top' and 'bottom' are not 'auto'</title>
 
   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements" />
   <link rel="match" href="s71-abs-pos-non-replaced-vlr-007-ref.xht" />
 
   <meta name="flags" content="ahem image" />
-  <meta name="assert" content="When 'direction' is 'rtl' and 'height' is 'auto' and 'top' and 'bottom' are not 'auto', then then solve for 'height'." />
+  <meta name="assert" content="When 'direction' is 'rtl' and 'height' is 'auto' and 'top' and 'bottom' are not 'auto', then solve for 'height'." />
 
   <link type="text/css" rel="stylesheet" href="support/ahem.css" />
 
   <style type="text/css"><![CDATA[
   html
     {
       -ah-writing-mode: vertical-lr;
       -webkit-writing-mode: vertical-lr;
@@ -33,66 +33,68 @@
       font: 80px/1 Ahem;
       height: 320px;
       position: relative;
       width: 320px;
     }
 
   div#containing-block > span
     {
-      background-color: red;
+      background-color: green;
       bottom: 1em;
-      color: green;
       height: auto;
       position: absolute;
       top: 2em;
+      width: 1em;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
     160px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
   (solve) : height: auto
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
      80px : bottom
     =====================
     320px : height of containing block
 
-And so computed height value must be 80px;
+And so computed height value must be 80px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
   <p><img src="support/pass-cdts-abs-pos-non-replaced.png" width="246" height="36" alt="Image download support must be enabled" /></p>
 
-  <div id="containing-block">1 2 34<span>X</span></div>
+  <div id="containing-block">1 2 34<span></span></div>
 
  </body>
 </html>
\ No newline at end of file
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-075.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-075.xht
@@ -39,50 +39,52 @@
       color: green;
       height: 1em;
       position: absolute;
       top: 1em;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve for 'right'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
      80px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
      80px : height
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
   (solve) : bottom: auto
     =====================
     320px : height of containing block
 
-And so computed bottom value must be 160px;
+And so computed bottom value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-077.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-077.xht
@@ -48,35 +48,35 @@ 6. 'right' is 'auto', 'left' and 'width'
 "
 
 'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
 
 So:
 
      80px : left
   +
-      0px : margin-left: auto
+      0px : margin-left
   +
-      0px : border-top-width
+      0px : border-left-width
   +
-      0px : padding-top
+      0px : padding-left
   +
      80px : width
   +
       0px : padding-right
   +
       0px : border-right-width
   +
-      0px : margin-right: auto
+      0px : margin-right
   +
   (solve) : right: auto
     =====================
     320px : width of containing block
 
-And so computed right value must be 160px;
+And so computed right value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-079.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-079.xht
@@ -43,50 +43,52 @@
       color: green;
       height: 1em;
       position: absolute;
       top: 1em;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve for 'right'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-
-"
-Layout rules that refer to the *-left and *-right box properties (border, margin, padding) use *-top and *-bottom instead, and vice versa. Which side of the box the property applies to doesn't change: only which values are inputs to which layout calculations changes.
-"
-7.1 Principles of Layout in Vertical Writing Modes
-http://www.w3.org/TR/css-writing-modes-3/#logical-direction-layout
+'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block
 
 So:
 
      80px : top
   +
-      0px : margin-top: auto
+      0px : margin-top
   +
       0px : border-top-width
   +
       0px : padding-top
   +
      80px : height
   +
       0px : padding-bottom
   +
       0px : border-bottom-width
   +
-      0px : margin-bottom: auto
+      0px : margin-bottom
   +
   (solve) : bottom: auto
     =====================
     320px : height of containing block
 
-And so computed bottom value must be 160px;
+And so computed bottom value must be 160px .
 */
 
   ]]></style>
 
  </head>
 
  <body>
 
--- a/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-081.xht
+++ b/layout/reftests/writing-mode/abspos/s71-abs-pos-non-replaced-vlr-081.xht
@@ -39,50 +39,52 @@
       color: green;
       height: 1em;
       position: absolute;
       top: 1em;
     }
 
 /*
 "
+Layout calculation rules (such as those in CSS2.1, Section 10.3) that apply to the horizontal dimension in horizontal writing modes instead apply to the vertical dimension in vertical writing modes.
+"
+7.1 Principles of Layout in Vertical Writing Modes
+http://www.w3.org/TR/css-writing-modes-3/#vertical-layout
+
+So here, *-top and *-bottom properties are input into the §10.3.7 algorithms where *-top properties refer to *-left properties in the layout rules and where *-bottom properties refer to *-right properties in the layout rules.
+
+"
 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve for 'right'
 "
 
-'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block
-