merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 24 Jun 2015 16:01:47 +0200
changeset 250093 4cdc1a95a672aaae593448b89b1caee33a159ab7
parent 250000 3ae7fd12f53fa7955ab952273870f205a82de527 (current diff)
parent 250092 d0114c0ca3a182e9af020513b7e21b6135ad01d3 (diff)
child 250094 7b0df70e27ea18748e2841506cbe9e23cae18b2f
child 250097 14f96e9b415aa5002bfb4fd41462038be2ecfbf2
child 250106 5e376b895220eeb611705a7dbce4f4fe53d1aa78
child 250138 d12f46ccb758b83e304ecc5e68d59eace4d0303f
push id28943
push usercbook@mozilla.com
push dateWed, 24 Jun 2015 14:02:00 +0000
treeherdermozilla-central@4cdc1a95a672 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone41.0a1
first release with
nightly linux32
4cdc1a95a672 / 41.0a1 / 20150624080416 / files
nightly linux64
4cdc1a95a672 / 41.0a1 / 20150624080416 / files
nightly mac
4cdc1a95a672 / 41.0a1 / 20150624080416 / files
nightly win32
4cdc1a95a672 / 41.0a1 / 20150624080416 / files
nightly win64
4cdc1a95a672 / 41.0a1 / 20150624080416 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
embedding/tests/winEmbed/SMALL.ICO
embedding/tests/winEmbed/WebBrowserChrome.cpp
embedding/tests/winEmbed/WebBrowserChrome.h
embedding/tests/winEmbed/WindowCreator.cpp
embedding/tests/winEmbed/WindowCreator.h
embedding/tests/winEmbed/moz.build
embedding/tests/winEmbed/resource.h
embedding/tests/winEmbed/winEmbed.ICO
embedding/tests/winEmbed/winEmbed.cpp
embedding/tests/winEmbed/winEmbed.h
embedding/tests/winEmbed/winEmbed.rc
embedding/tests/winEmbed/winembed.dsp
layout/base/nsIPercentHeightObserver.h
profile/dirserviceprovider/ProfileUnlockerWin.cpp
profile/dirserviceprovider/ProfileUnlockerWin.h
profile/dirserviceprovider/moz.build
profile/dirserviceprovider/nsProfileDirServiceProvider.cpp
profile/dirserviceprovider/nsProfileDirServiceProvider.h
profile/dirserviceprovider/nsProfileLock.cpp
profile/dirserviceprovider/nsProfileLock.h
profile/dirserviceprovider/nsProfileStringTypes.h
profile/moz.build
profile/notifications.txt
profile/nsIProfileUnlocker.idl
testing/web-platform/meta/IndexedDB/idbcursor_update_index5.htm.ini
testing/web-platform/meta/IndexedDB/idbcursor_update_objectstore6.htm.ini
testing/web-platform/meta/IndexedDB/idbfactory_open12.htm.ini
testing/web-platform/meta/IndexedDB/idbfactory_open2.htm.ini
testing/web-platform/meta/IndexedDB/idbindex_get7.htm.ini
testing/web-platform/meta/IndexedDB/idbindex_getKey7.htm.ini
testing/web-platform/meta/IndexedDB/idbindex_openCursor2.htm.ini
testing/web-platform/meta/IndexedDB/idbindex_openKeyCursor3.htm.ini
testing/web-platform/meta/IndexedDB/idbobjectstore_get.htm.ini
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -678,17 +678,17 @@ getRoleCB(AtkObject *aAtkObj)
 
 #undef ROLE
 
   if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1))
     aAtkObj->role = ATK_ROLE_LIST;
   else if (aAtkObj->role == ATK_ROLE_TABLE_ROW && !IsAtkVersionAtLeast(2, 1))
     aAtkObj->role = ATK_ROLE_LIST_ITEM;
   else if (aAtkObj->role == ATK_ROLE_MATH && !IsAtkVersionAtLeast(2, 12))
-    aAtkObj->role = ATK_ROLE_PANEL;
+    aAtkObj->role = ATK_ROLE_SECTION;
   else if (aAtkObj->role == ATK_ROLE_STATIC && !IsAtkVersionAtLeast(2, 16))
     aAtkObj->role = ATK_ROLE_TEXT;
   else if ((aAtkObj->role == ATK_ROLE_MATH_FRACTION ||
             aAtkObj->role == ATK_ROLE_MATH_ROOT) && !IsAtkVersionAtLeast(2, 16))
     aAtkObj->role = ATK_ROLE_SECTION;
 
   return aAtkObj->role;
 }
--- a/accessible/base/RoleMap.h
+++ b/accessible/base/RoleMap.h
@@ -1062,281 +1062,281 @@ ROLE(SWITCH,
      NSAccessibilityCheckBoxRole,
      ROLE_SYSTEM_CHECKBUTTON,
      IA2_ROLE_TOGGLE_BUTTON,
      eNameFromSubtreeRule)
 
 ROLE(MATHML_MATH,
      "math",
      ATK_ROLE_MATH,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      ROLE_SYSTEM_EQUATION,
      ROLE_SYSTEM_EQUATION,
      eNoNameRule)
 
 ROLE(MATHML_IDENTIFIER,
      "mathml identifier",
      ATK_ROLE_STATIC,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNameFromSubtreeRule)
 
 ROLE(MATHML_NUMBER,
      "mathml number",
      ATK_ROLE_STATIC,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNameFromSubtreeRule)
 
 ROLE(MATHML_OPERATOR,
      "mathml operator",
      ATK_ROLE_STATIC,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNameFromSubtreeRule)
 
 ROLE(MATHML_TEXT,
      "mathml text",
      ATK_ROLE_STATIC,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNameFromSubtreeRule)
 
 ROLE(MATHML_STRING_LITERAL,
      "mathml string literal",
      ATK_ROLE_STATIC,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNameFromSubtreeRule)
 
 ROLE(MATHML_GLYPH,
      "mathml glyph",
      ATK_ROLE_IMAGE,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNameFromSubtreeRule)
 
 ROLE(MATHML_ROW,
      "mathml row",
-     ATK_ROLE_PANEL,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_FRACTION,
      "mathml fraction",
      ATK_ROLE_MATH_FRACTION,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_SQUARE_ROOT,
      "mathml square root",
      ATK_ROLE_MATH_ROOT,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_ROOT,
      "mathml root",
      ATK_ROLE_MATH_ROOT,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_FENCED,
      "mathml fenced",
-     ATK_ROLE_PANEL,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_ENCLOSED,
      "mathml enclosed",
-     ATK_ROLE_PANEL,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_STYLE,
      "mathml style",
-     ATK_ROLE_PANEL,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_SUB,
      "mathml sub",
-     ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_SUP,
      "mathml sup",
-     ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_SUB_SUP,
      "mathml sub sup",
-     ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_UNDER,
      "mathml under",
-     ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_OVER,
      "mathml over",
-     ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_UNDER_OVER,
      "mathml under over",
-     ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_MULTISCRIPTS,
      "mathml multiscripts",
-     ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_TABLE,
      "mathml table",
      ATK_ROLE_TABLE,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_LABELED_ROW,
      "mathml labeled row",
      ATK_ROLE_TABLE_ROW,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_TABLE_ROW,
      "mathml table row",
      ATK_ROLE_TABLE_ROW,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_CELL,
      "mathml cell",
      ATK_ROLE_TABLE_CELL,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_ACTION,
      "mathml action",
-     ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_ERROR,
      "mathml error",
-     ATK_ROLE_PANEL,
-     NSAccessibilityUnknownRole,
+     ATK_ROLE_SECTION,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_STACK,
      "mathml stack",
      ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_LONG_DIVISION,
      "mathml long division",
      ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_STACK_GROUP,
      "mathml stack group",
      ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_STACK_ROW,
      "mathml stack row",
      ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_STACK_CARRIES,
      "mathml stack carries",
      ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_STACK_CARRY,
      "mathml stack carry",
      ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(MATHML_STACK_LINE,
      "mathml stack line",
      ATK_ROLE_UNKNOWN,
-     NSAccessibilityUnknownRole,
+     NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
      eNoNameRule)
 
 ROLE(RADIO_GROUP,
      "grouping",
      ATK_ROLE_PANEL,
      NSAccessibilityRadioGroupRole,
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -498,16 +498,76 @@ GetClosestInterestingAccessible(id anObj
       return @"AXDefinitionList"; // 10.6+ NSAccessibilityDefinitionListSubrole;
 
     case roles::TERM:
       return @"AXTerm";
 
     case roles::DEFINITION:
       return @"AXDefinition";
 
+    case roles::MATHML_MATH:
+      return @"AXDocumentMath";
+
+    case roles::MATHML_FRACTION:
+      return @"AXMathFraction";
+
+    case roles::MATHML_FENCED:
+      // XXX This should be AXMathFence, but doing so without implementing the
+      // whole fence interface seems to make VoiceOver crash, so we present it
+      // as a row for now.
+      return @"AXMathRow";
+
+    case roles::MATHML_SUB:
+    case roles::MATHML_SUP:
+    case roles::MATHML_SUB_SUP:
+      return @"AXMathSubscriptSuperscript";
+
+    case roles::MATHML_ROW:
+      return @"AXMathRow";
+
+    case roles::MATHML_UNDER:
+    case roles::MATHML_OVER:
+    case roles::MATHML_UNDER_OVER:
+      return @"AXMathUnderOver";
+
+    case roles::MATHML_SQUARE_ROOT:
+      return @"AXMathSquareRoot";
+
+    case roles::MATHML_ROOT:
+      return @"AXMathRoot";
+
+    case roles::MATHML_TEXT:
+      return @"AXMathText";
+
+    case roles::MATHML_NUMBER:
+      return @"AXMathNumber";
+
+    case roles::MATHML_IDENTIFIER:
+      return @"AXMathIdentifier";
+
+    case roles::MATHML_TABLE:
+      return @"AXMathTable";
+
+    case roles::MATHML_TABLE_ROW:
+      return @"AXMathTableRow";
+
+    case roles::MATHML_CELL:
+      return @"AXMathTableCell";
+
+    // XXX: NSAccessibility also uses subroles AXMathSeparatorOperator and
+    // AXMathFenceOperator. We should use the NS_MATHML_OPERATOR_FENCE and
+    // NS_MATHML_OPERATOR_SEPARATOR bits of nsOperatorFlags, but currently they
+    // are only available from the MathML layout code. Hence we just fallback
+    // to subrole AXMathOperator for now.
+    case roles::MATHML_OPERATOR:
+      return @"AXMathOperator";
+
+    case roles::MATHML_MULTISCRIPTS:
+      return @"AXMathMultiscript";
+
     case roles::SWITCH:
       return @"AXSwitch";
 
     default:
       break;
   }
 
   return nil;
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -300,17 +300,16 @@
 @RESPATH@/components/parentalcontrols.xpt
 #ifdef MOZ_WEBRTC
 @RESPATH@/components/peerconnection.xpt
 #endif
 @RESPATH@/components/places.xpt
 @RESPATH@/components/plugin.xpt
 @RESPATH@/components/pref.xpt
 @RESPATH@/components/prefetch.xpt
-@RESPATH@/components/profile.xpt
 #ifdef MOZ_ENABLE_PROFILER_SPS
 @RESPATH@/components/profiler.xpt
 #endif
 @RESPATH@/components/proxyObject.xpt
 @RESPATH@/components/rdf.xpt
 @RESPATH@/components/satchel.xpt
 @RESPATH@/components/saxparser.xpt
 @RESPATH@/components/sessionstore.xpt
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -470,16 +470,17 @@ skip-if = e10s # Bug 940206 - nsIWebCont
 [browser_addCertException.js]
 skip-if = e10s # Bug 1100687 - test directly manipulates content (content.document.getElementById)
 [browser_bug1045809.js]
 [browser_e10s_switchbrowser.js]
 [browser_e10s_about_process.js]
 [browser_e10s_chrome_process.js]
 [browser_e10s_javascript.js]
 [browser_blockHPKP.js]
+tags = psm
 skip-if = e10s # bug 1100687 - test directly manipulates content (content.document.getElementById)
 [browser_mcb_redirect.js]
 [browser_windowactivation.js]
 [browser_contextmenu_childprocess.js]
 [browser_bug963945.js]
 [browser_readerMode.js]
 support-files =
   readerModeArticle.html
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -301,17 +301,16 @@
 @RESPATH@/components/parentalcontrols.xpt
 #ifdef MOZ_WEBRTC
 @RESPATH@/components/peerconnection.xpt
 #endif
 @RESPATH@/components/places.xpt
 @RESPATH@/components/plugin.xpt
 @RESPATH@/components/pref.xpt
 @RESPATH@/components/prefetch.xpt
-@RESPATH@/components/profile.xpt
 #ifdef MOZ_ENABLE_PROFILER_SPS
 @RESPATH@/components/profiler.xpt
 #endif
 @RESPATH@/components/rdf.xpt
 @RESPATH@/components/satchel.xpt
 @RESPATH@/components/saxparser.xpt
 @RESPATH@/browser/components/sessionstore.xpt
 @RESPATH@/components/services-crypto-component.xpt
--- a/dom/base/Attr.h
+++ b/dom/base/Attr.h
@@ -93,16 +93,18 @@ public:
   bool Specified() const;
 
   // XPCOM GetNamespaceURI() is OK
   // XPCOM GetPrefix() is OK
   // XPCOM GetLocalName() is OK
 
   Element* GetOwnerElement(ErrorResult& aRv);
 
+  bool IsNSAware() const { return mNsAware; }
+
 protected:
   virtual Element* GetNameSpaceElement() override
   {
     return GetElement();
   }
 
   static bool sInitialized;
 
--- a/dom/base/nsDOMAttributeMap.cpp
+++ b/dom/base/nsDOMAttributeMap.cpp
@@ -10,16 +10,17 @@
 
 #include "nsDOMAttributeMap.h"
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/Attr.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/NamedNodeMapBinding.h"
 #include "mozilla/dom/NodeInfoInlines.h"
+#include "mozilla/Telemetry.h"
 #include "nsAttrName.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsIContentInlines.h"
 #include "nsIDocument.h"
 #include "nsNameSpaceManager.h"
 #include "nsNodeInfoManager.h"
 #include "nsUnicharUtils.h"
@@ -266,16 +267,31 @@ nsDOMAttributeMap::SetNamedItemNS(nsIDOM
 
 already_AddRefed<Attr>
 nsDOMAttributeMap::SetNamedItemInternal(Attr& aAttr,
                                         bool aWithNS,
                                         ErrorResult& aError)
 {
   NS_ENSURE_TRUE(mContent, nullptr);
 
+  if (!aAttr.IsNSAware() &&
+      !mContent->IsHTMLElement() &&
+      aAttr.OwnerDoc()->IsHTMLDocument()) {
+    // Check whether we have a non-lowercase name, and if so log some telemetry.
+    // We check whether the attr's document is HTML _before_ the adopt we do
+    // below, because we're trying to figure out whether we could lowercase the
+    // attr name at creation time.  We restrict this to the !IsNSAware() case,
+    // because we only care about Attr nodes created via createAttribute.
+    nsIAtom* nameAtom = aAttr.NodeInfo()->NameAtom();
+    if (nsContentUtils::StringContainsASCIIUpper(nsDependentAtomString(nameAtom))) {
+        Telemetry::Accumulate(Telemetry::NONLOWERCASE_NONHTML_ATTR_NODE_SET,
+                              true);
+      }
+  }
+
   // XXX should check same-origin between mContent and aAttr however
   // nsContentUtils::CheckSameOrigin can't deal with attributenodes yet
 
   // Check that attribute is not owned by somebody else
   nsDOMAttributeMap* owner = aAttr.GetMap();
   if (owner) {
     if (owner != this) {
       aError.Throw(NS_ERROR_DOM_INUSE_ATTRIBUTE_ERR);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7586,28 +7586,16 @@ nsGlobalWindow::ClearInterval(int32_t aH
 {
   ErrorResult rv;
   ClearInterval(aHandle, rv);
 
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
-nsGlobalWindow::SetTimeout(int32_t *_retval)
-{
-  return SetTimeoutOrInterval(false, _retval);
-}
-
-NS_IMETHODIMP
-nsGlobalWindow::SetInterval(int32_t *_retval)
-{
-  return SetTimeoutOrInterval(true, _retval);
-}
-
-NS_IMETHODIMP
 nsGlobalWindow::SetResizable(bool aResizable)
 {
   // nop
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -11940,60 +11928,16 @@ nsGlobalWindow::SetTimeoutOrInterval(nsI
 
   timeout->mPublicId = ++mTimeoutPublicIdCounter;
   *aReturn = timeout->mPublicId;
 
   return NS_OK;
 
 }
 
-nsresult
-nsGlobalWindow::SetTimeoutOrInterval(bool aIsInterval, int32_t *aReturn)
-{
-  // This needs to forward to the inner window, but since the current
-  // inner may not be the inner in the calling scope, we need to treat
-  // this specially here as we don't want timeouts registered in a
-  // dying inner window to get registered and run on the current inner
-  // window. To get this right, we need to forward this call to the
-  // inner window that's calling window.setTimeout().
-
-  if (IsOuterWindow()) {
-    nsGlobalWindow* callerInner = CallerInnerWindow();
-    NS_ENSURE_TRUE(callerInner || nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
-
-    // If the caller and the callee share the same outer window,
-    // forward to the callee inner. Else, we forward to the current
-    // inner (e.g. someone is calling setTimeout() on a reference to
-    // some other window).
-
-    if (callerInner &&
-        callerInner->GetOuterWindow() == this &&
-        callerInner->IsInnerWindow()) {
-      return callerInner->SetTimeoutOrInterval(aIsInterval, aReturn);
-    }
-
-    FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
-                     NS_ERROR_NOT_INITIALIZED);
-  }
-
-  int32_t interval = 0;
-  bool isInterval = aIsInterval;
-  nsCOMPtr<nsIScriptTimeoutHandler> handler;
-  nsresult rv = NS_CreateJSTimeoutHandler(this,
-                                          &isInterval,
-                                          &interval,
-                                          getter_AddRefs(handler));
-  if (!handler) {
-    *aReturn = 0;
-    return rv;
-  }
-
-  return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
-}
-
 int32_t
 nsGlobalWindow::SetTimeoutOrInterval(Function& aFunction, int32_t aTimeout,
                                      const Sequence<JS::Value>& aArguments,
                                      bool aIsInterval, ErrorResult& aError)
 {
   nsGlobalWindow* inner = InnerForSetTimeoutOrInterval(aError);
   if (!inner) {
     return -1;
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -124,22 +124,16 @@ namespace indexedDB {
 class IDBFactory;
 } // namespace indexedDB
 } // namespace dom
 namespace gfx {
 class VRHMDInfo;
 } // namespace gfx
 } // namespace mozilla
 
-extern nsresult
-NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,
-                          bool *aIsInterval,
-                          int32_t *aInterval,
-                          nsIScriptTimeoutHandler **aRet);
-
 extern already_AddRefed<nsIScriptTimeoutHandler>
 NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,
                           mozilla::dom::Function& aFunction,
                           const mozilla::dom::Sequence<JS::Value>& aArguments,
                           mozilla::ErrorResult& aError);
 
 extern already_AddRefed<nsIScriptTimeoutHandler>
 NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
@@ -1330,17 +1324,16 @@ public:
   nsresult ClearTimeoutOrInterval(int32_t aTimerID) override
   {
     mozilla::ErrorResult rv;
     ClearTimeoutOrInterval(aTimerID, rv);
     return rv.StealNSResult();
   }
 
   // JS specific timeout functions (JS args grabbed from context).
-  nsresult SetTimeoutOrInterval(bool aIsInterval, int32_t* aReturn);
   nsresult ResetTimersForNonBackgroundWindow();
 
   // The timeout implementation functions.
   void RunTimeout(nsTimeout *aTimeout);
   void RunTimeout() { RunTimeout(nullptr); }
   // Return true if |aTimeout| was cleared while its handler ran.
   bool RunTimeoutHandler(nsTimeout* aTimeout, nsIScriptContext* aScx);
   // Return true if |aTimeout| needs to be reinserted into the timeout list.
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -53,19 +53,16 @@ public:
     *aLineNo = mLineNo;
   }
 
   virtual const nsTArray<JS::Value>& GetArgs() override
   {
     return mArgs;
   }
 
-  nsresult Init(nsGlobalWindow *aWindow, bool *aIsInterval,
-                int32_t *aInterval, bool* aAllowEval);
-
   void ReleaseJSObjects();
 
 private:
   ~nsJSScriptTimeoutHandler();
 
   // filename, line number and JS language version string of the
   // caller of setTimeout()
   nsCString mFileName;
@@ -243,171 +240,23 @@ nsJSScriptTimeoutHandler::ReleaseJSObjec
 {
   if (mFunction) {
     mFunction = nullptr;
     mArgs.Clear();
     mozilla::DropJSObjects(this);
   }
 }
 
-nsresult
-nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, bool *aIsInterval,
-                               int32_t *aInterval, bool *aAllowEval)
-{
-  if (!aWindow->GetContextInternal() || !aWindow->FastGetGlobalJSObject()) {
-    // This window was already closed, or never properly initialized,
-    // don't let a timer be scheduled on such a window.
-
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-
-  nsAXPCNativeCallContext *ncc = nullptr;
-  nsresult rv = nsContentUtils::XPConnect()->
-    GetCurrentNativeCallContext(&ncc);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!ncc)
-    return NS_ERROR_NOT_AVAILABLE;
-
-  JSContext *cx = nullptr;
-
-  rv = ncc->GetJSContext(&cx);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  uint32_t argc;
-  JS::Value *argv = nullptr;
-
-  ncc->GetArgc(&argc);
-  ncc->GetArgvPtr(&argv);
-
-  JS::Rooted<JSFlatString*> expr(cx);
-  JS::Rooted<JSObject*> funobj(cx);
-
-  if (argc < 1) {
-    ::JS_ReportError(cx, "Function %s requires at least 2 parameter",
-                     *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
-    return NS_ERROR_DOM_TYPE_ERR;
-  }
-
-  int32_t interval = 0;
-  if (argc > 1) {
-    JS::Rooted<JS::Value> arg(cx, argv[1]);
-
-    if (!JS::ToInt32(cx, arg, &interval)) {
-      ::JS_ReportError(cx,
-                       "Second argument to %s must be a millisecond interval",
-                       aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
-      return NS_ERROR_DOM_TYPE_ERR;
-    }
-  }
-
-  if (argc == 1) {
-    // If no interval was specified, treat this like a timeout, to avoid
-    // setting an interval of 0 milliseconds.
-    *aIsInterval = false;
-  }
-
-  JS::Rooted<JS::Value> arg(cx, argv[0]);
-  switch (::JS_TypeOfValue(cx, arg)) {
-  case JSTYPE_FUNCTION:
-    funobj = &arg.toObject();
-    break;
-
-  case JSTYPE_STRING:
-  case JSTYPE_OBJECT:
-    {
-      JSString *str = JS::ToString(cx, arg);
-      if (!str)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-      expr = ::JS_FlattenString(cx, str);
-      if (!expr)
-          return NS_ERROR_OUT_OF_MEMORY;
-
-      argv[0] = JS::StringValue(str);
-    }
-    break;
-
-  default:
-    ::JS_ReportError(cx, "useless %s call (missing quotes around argument?)",
-                     *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
-
-    // Return an error that nsGlobalWindow can recognize and turn into NS_OK.
-    return NS_ERROR_DOM_TYPE_ERR;
-  }
-
-  if (expr) {
-    // if CSP is enabled, and setTimeout/setInterval was called with a string,
-    // disable the registration and log an error
-    ErrorResult error;
-    *aAllowEval = CheckCSPForEval(cx, aWindow, error);
-    if (error.Failed() || !*aAllowEval) {
-      return error.StealNSResult();
-    }
-
-    MOZ_ASSERT(mExpr.IsEmpty());
-    AssignJSFlatString(mExpr, expr);
-
-    // Get the calling location.
-    nsJSUtils::GetCallingLocation(cx, mFileName, &mLineNo);
-  } else if (funobj) {
-    *aAllowEval = true;
-
-    mozilla::HoldJSObjects(this);
-
-    mFunction = new Function(funobj, GetIncumbentGlobal());
-
-    // Create our arg array.  argc is the number of arguments passed
-    // to setTimeout or setInterval; the first two are our callback
-    // and the delay, so only arguments after that need to go in our
-    // array.
-    // std::max(argc - 2, 0) wouldn't work right because argc is unsigned.
-    uint32_t argCount = std::max(argc, 2u) - 2;
-
-    FallibleTArray<JS::Heap<JS::Value> > args;
-    if (!args.SetCapacity(argCount, fallible)) {
-      // No need to drop here, since we already have a non-null mFunction
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    for (uint32_t idx = 0; idx < argCount; ++idx) {
-      *args.AppendElement(fallible) = argv[idx + 2];
-    }
-    args.SwapElements(mArgs);
-  } else {
-    NS_WARNING("No func and no expr - why are we here?");
-  }
-  *aInterval = interval;
-  return NS_OK;
-}
-
 const char16_t *
 nsJSScriptTimeoutHandler::GetHandlerText()
 {
   NS_ASSERTION(!mFunction, "No expression, so no handler text!");
   return mExpr.get();
 }
 
-nsresult NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,
-                                   bool *aIsInterval,
-                                   int32_t *aInterval,
-                                   nsIScriptTimeoutHandler **aRet)
-{
-  *aRet = nullptr;
-  nsRefPtr<nsJSScriptTimeoutHandler> handler = new nsJSScriptTimeoutHandler();
-  bool allowEval;
-  nsresult rv = handler->Init(aWindow, aIsInterval, aInterval, &allowEval);
-  if (NS_FAILED(rv) || !allowEval) {
-    return rv;
-  }
-
-  handler.forget(aRet);
-
-  return NS_OK;
-}
-
 already_AddRefed<nsIScriptTimeoutHandler>
 NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow, Function& aFunction,
                           const Sequence<JS::Value>& aArguments,
                           ErrorResult& aError)
 {
   FallibleTArray<JS::Heap<JS::Value> > args;
   if (!args.AppendElements(aArguments, fallible)) {
     aError.Throw(NS_ERROR_OUT_OF_MEMORY);
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -673,38 +673,45 @@ nsXMLHttpRequest::AppendToResponseText(c
 {
   NS_ENSURE_STATE(mDecoder);
 
   int32_t destBufferLen;
   nsresult rv = mDecoder->GetMaxLength(aSrcBuffer, aSrcBufferLen,
                                        &destBufferLen);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (!mResponseText.SetCapacity(mResponseText.Length() + destBufferLen, fallible)) {
+  uint32_t size = mResponseText.Length() + destBufferLen;
+  if (size < (uint32_t)destBufferLen) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  if (!mResponseText.SetCapacity(size, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   char16_t* destBuffer = mResponseText.BeginWriting() + mResponseText.Length();
 
-  int32_t totalChars = mResponseText.Length();
+  CheckedInt32 totalChars = mResponseText.Length();
 
   // This code here is basically a copy of a similar thing in
   // nsScanner::Append(const char* aBuffer, uint32_t aLen).
   int32_t srclen = (int32_t)aSrcBufferLen;
   int32_t destlen = (int32_t)destBufferLen;
   rv = mDecoder->Convert(aSrcBuffer,
                          &srclen,
                          destBuffer,
                          &destlen);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   totalChars += destlen;
-
-  mResponseText.SetLength(totalChars);
-
+  if (!totalChars.isValid()) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  mResponseText.SetLength(totalChars.value());
   return NS_OK;
 }
 
 /* readonly attribute AString responseText; */
 NS_IMETHODIMP
 nsXMLHttpRequest::GetResponseText(nsAString& aResponseText)
 {
   ErrorResult rv;
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -751,16 +751,21 @@ IDBFactory::OpenInternal(nsIPrincipal* a
     MOZ_ASSERT(scriptOwner);
 
     request = IDBOpenDBRequest::CreateForWindow(this, mWindow, scriptOwner);
   } else {
     autoJS.Init(mOwningObject.get());
     JS::Rooted<JSObject*> scriptOwner(autoJS.cx(), mOwningObject);
 
     request = IDBOpenDBRequest::CreateForJS(this, scriptOwner);
+    if (!request) {
+      MOZ_ASSERT(!NS_IsMainThread());
+      aRv.ThrowUncatchableException();
+      return nullptr;
+    }
   }
 
   MOZ_ASSERT(request);
 
   if (aDeleting) {
     IDB_LOG_MARK("IndexedDB %s: Child  Request[%llu]: "
                    "indexedDB.deleteDatabase(\"%s\")",
                  "IndexedDB %s: C R[%llu]: IDBFactory.deleteDatabase()",
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -437,35 +437,56 @@ IDBRequest::PreHandleEvent(EventChainPre
   aVisitor.mParentTarget = mTransaction;
   return NS_OK;
 }
 
 class IDBOpenDBRequest::WorkerFeature final
   : public mozilla::dom::workers::WorkerFeature
 {
   WorkerPrivate* mWorkerPrivate;
+#ifdef DEBUG
+  // This is only here so that assertions work in the destructor even if
+  // NoteAddFeatureFailed was called.
+  WorkerPrivate* mWorkerPrivateDEBUG;
+#endif
 
 public:
   explicit
   WorkerFeature(WorkerPrivate* aWorkerPrivate)
     : mWorkerPrivate(aWorkerPrivate)
+#ifdef DEBUG
+    , mWorkerPrivateDEBUG(aWorkerPrivate)
+#endif
   {
     MOZ_ASSERT(aWorkerPrivate);
     aWorkerPrivate->AssertIsOnWorkerThread();
 
     MOZ_COUNT_CTOR(IDBOpenDBRequest::WorkerFeature);
   }
 
   ~WorkerFeature()
   {
-    mWorkerPrivate->AssertIsOnWorkerThread();
+#ifdef DEBUG
+    mWorkerPrivateDEBUG->AssertIsOnWorkerThread();
+#endif
 
     MOZ_COUNT_DTOR(IDBOpenDBRequest::WorkerFeature);
 
-    mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this);
+    if (mWorkerPrivate) {
+      mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this);
+    }
+  }
+
+  void
+  NoteAddFeatureFailed()
+  {
+    MOZ_ASSERT(mWorkerPrivate);
+    mWorkerPrivate->AssertIsOnWorkerThread();
+
+    mWorkerPrivate = nullptr;
   }
 
 private:
   virtual bool
   Notify(JSContext* aCx, Status aStatus) override;
 };
 
 IDBOpenDBRequest::IDBOpenDBRequest(IDBFactory* aFactory, nsPIDOMWindow* aOwner)
@@ -522,16 +543,17 @@ IDBOpenDBRequest::CreateForJS(IDBFactory
 
     workerPrivate->AssertIsOnWorkerThread();
 
     JSContext* cx = workerPrivate->GetJSContext();
     MOZ_ASSERT(cx);
 
     nsAutoPtr<WorkerFeature> feature(new WorkerFeature(workerPrivate));
     if (NS_WARN_IF(!workerPrivate->AddFeature(cx, feature))) {
+      feature->NoteAddFeatureFailed();
       return nullptr;
     }
 
     request->mWorkerFeature = Move(feature);
   }
 
   return request.forget();
 }
--- a/dom/interfaces/base/nsIDOMJSWindow.idl
+++ b/dom/interfaces/base/nsIDOMJSWindow.idl
@@ -1,30 +1,21 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
-[scriptable, uuid(4237c376-d637-4b6e-9f8a-1da57e867834)]
+[scriptable, uuid(e0f739e3-47e2-4007-af30-181939e97a51)]
 interface nsIDOMJSWindow : nsISupports
 {
   void                      dump(in DOMString str);
 
   /**
-   * These methods take typeless arguments and optional arguments, the
-   * first argument is either a function or a string, the second
-   * argument must be a number (ms) and the rest of the arguments (2
-   * ... n) are passed to the callback function
-   */
-  long                      setTimeout();
-  long                      setInterval();
-
-  /**
    * These methods take one optional argument that's the timer ID to
    * clear. Often in existing code these methods are passed undefined,
    * which is a nop so we need to support that as well.
    */
   void                      clearTimeout([optional] in long handle);
   void                      clearInterval([optional] in long handle);
 
   /**
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -99,23 +99,22 @@ void InitPreferredSampleRate()
     // Query failed, use a sensible default.
     sPreferredSampleRate = 44100;
   }
 }
 
 cubeb* GetCubebContextUnlocked()
 {
   sMutex.AssertCurrentThreadOwns();
-  if (!sCubebContext) {
-    MOZ_ASSERT(NS_IsMainThread());
-    if (cubeb_init(&sCubebContext, "CubebUtils") != CUBEB_OK) {
-      NS_WARNING("cubeb_init failed");
-    }
+  if (sCubebContext ||
+      cubeb_init(&sCubebContext, "CubebUtils") == CUBEB_OK) {
+    return sCubebContext;
   }
-  return sCubebContext;
+  NS_WARNING("cubeb_init failed");
+  return nullptr;
 }
 
 uint32_t GetCubebLatency()
 {
   StaticMutexAutoLock lock(sMutex);
   return sCubebLatency;
 }
 
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaDecoder.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MathAlgorithms.h"
 #include <limits>
 #include "nsIObserver.h"
 #include "nsTArray.h"
-#include "CubebUtils.h"
 #include "VideoUtils.h"
 #include "MediaDecoderStateMachine.h"
 #include "ImageContainer.h"
 #include "MediaResource.h"
 #include "nsError.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
 #include "nsIMemoryReporter.h"
@@ -397,21 +396,16 @@ MediaDecoder::MediaDecoder() :
 }
 
 bool MediaDecoder::Init(MediaDecoderOwner* aOwner)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mOwner = aOwner;
   mVideoFrameContainer = aOwner->GetVideoFrameContainer();
   MediaShutdownManager::Instance().Register(this);
-  // We don't use the cubeb context yet, but need to ensure it is created on
-  // the main thread.
-  if (!CubebUtils::GetCubebContext()) {
-    NS_WARNING("Audio backend initialization failed.");
-  }
   return true;
 }
 
 void MediaDecoder::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mShuttingDown)
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -281,16 +281,21 @@ public:
 
   nsRefPtr<MediaByteBuffer> mCodecSpecificConfig;
   nsRefPtr<MediaByteBuffer> mExtraData;
 
 };
 
 class EncryptionInfo {
 public:
+  EncryptionInfo()
+    : mEncrypted(false)
+  {
+  }
+
   struct InitData {
     template<typename AInitDatas>
     InitData(const nsAString& aType, AInitDatas&& aInitData)
       : mType(aType)
       , mInitData(Forward<AInitDatas>(aInitData))
     {
     }
 
@@ -300,32 +305,36 @@ public:
     // Encryption data.
     nsTArray<uint8_t> mInitData;
   };
   typedef nsTArray<InitData> InitDatas;
 
   // True if the stream has encryption metadata
   bool IsEncrypted() const
   {
-    return !mInitDatas.IsEmpty();
+    return mEncrypted;
   }
 
   template<typename AInitDatas>
   void AddInitData(const nsAString& aType, AInitDatas&& aInitData)
   {
     mInitDatas.AppendElement(InitData(aType, Forward<AInitDatas>(aInitData)));
+    mEncrypted = true;
   }
 
   void AddInitData(const EncryptionInfo& aInfo)
   {
     mInitDatas.AppendElements(aInfo.mInitDatas);
+    mEncrypted = !!mInitDatas.Length();
   }
 
   // One 'InitData' per encrypted buffer.
   InitDatas mInitDatas;
+private:
+  bool mEncrypted;
 };
 
 class MediaInfo {
 public:
   bool HasVideo() const
   {
     return mVideo.IsValid();
   }
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -26,16 +26,17 @@
 #endif
 #include "GMPContentParent.h"
 
 #include "mozilla/dom/CrashReporterParent.h"
 using mozilla::dom::CrashReporterParent;
 using mozilla::ipc::GeckoChildProcessHost;
 
 #ifdef MOZ_CRASHREPORTER
+#include "nsPrintfCString.h"
 using CrashReporter::AnnotationTable;
 using CrashReporter::GetIDFromMinidump;
 #endif
 
 #include "mozilla/Telemetry.h"
 
 namespace mozilla {
 
@@ -191,16 +192,21 @@ GMPParent::LoadProcess()
   return NS_OK;
 }
 
 void
 AbortWaitingForGMPAsyncShutdown(nsITimer* aTimer, void* aClosure)
 {
   NS_WARNING("Timed out waiting for GMP async shutdown!");
   GMPParent* parent = reinterpret_cast<GMPParent*>(aClosure);
+#if defined(MOZ_CRASHREPORTER)
+  CrashReporter::AnnotateCrashReport(
+    nsPrintfCString("AsyncPluginShutdown-%s@%p", parent->GetDisplayName().get(), parent),
+    NS_LITERAL_CSTRING("Timed out waiting for async shutdown"));
+#endif
   nsRefPtr<GeckoMediaPluginServiceParent> service =
     GeckoMediaPluginServiceParent::GetSingleton();
   if (service) {
     service->AsyncShutdownComplete(parent);
   }
 }
 
 nsresult
@@ -234,18 +240,30 @@ GMPParent::EnsureAsyncShutdownTimeoutSet
     nsITimer::TYPE_ONE_SHOT);
 }
 
 bool
 GMPParent::RecvPGMPContentChildDestroyed()
 {
   --mGMPContentChildCount;
   if (!IsUsed()) {
+#if defined(MOZ_CRASHREPORTER)
+    CrashReporter::AnnotateCrashReport(
+      nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
+      NS_LITERAL_CSTRING("Content children destroyed"));
+#endif
     CloseIfUnused();
   }
+#if defined(MOZ_CRASHREPORTER)
+  else {
+    CrashReporter::AnnotateCrashReport(
+      nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
+      nsPrintfCString("Content child destroyed, remaining: %u", mGMPContentChildCount));
+  }
+#endif
   return true;
 }
 
 void
 GMPParent::CloseIfUnused()
 {
   MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
   LOGD("%s: mAsyncShutdownRequired=%d", __FUNCTION__, mAsyncShutdownRequired);
@@ -257,19 +275,29 @@ GMPParent::CloseIfUnused()
     // Ensure all timers are killed.
     for (uint32_t i = mTimers.Length(); i > 0; i--) {
       mTimers[i - 1]->Shutdown();
     }
 
     if (mAsyncShutdownRequired) {
       if (!mAsyncShutdownInProgress) {
         LOGD("%s: sending async shutdown notification", __FUNCTION__);
+#if defined(MOZ_CRASHREPORTER)
+      CrashReporter::AnnotateCrashReport(
+        nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
+        NS_LITERAL_CSTRING("Sent BeginAsyncShutdown"));
+#endif
         mAsyncShutdownInProgress = true;
         if (!SendBeginAsyncShutdown() ||
             NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
+#if defined(MOZ_CRASHREPORTER)
+          CrashReporter::AnnotateCrashReport(
+            nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
+            NS_LITERAL_CSTRING("Could not send BeginAsyncShutdown - Aborting"));
+#endif
           AbortAsyncShutdown();
         }
       }
     } else {
       // Any async shutdown must be complete. Shutdown GMPStorage.
       for (size_t i = mStorage.Length(); i > 0; i--) {
         mStorage[i - 1]->Shutdown();
       }
@@ -308,16 +336,21 @@ GMPParent::CloseActive(bool aDieWhenUnlo
 
   if (aDieWhenUnloaded) {
     mDeleteProcessOnlyOnUnload = true; // don't allow this to go back...
   }
   if (mState == GMPStateLoaded) {
     mState = GMPStateUnloading;
   }
   if (mState != GMPStateNotLoaded && IsUsed()) {
+#if defined(MOZ_CRASHREPORTER)
+    CrashReporter::AnnotateCrashReport(
+      nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
+      nsPrintfCString("Sent CloseActive, content children to close: %u", mGMPContentChildCount));
+#endif
     unused << SendCloseActive();
   }
 }
 
 void
 GMPParent::MarkForDeletion()
 {
   mDeleteProcessOnlyOnUnload = true;
@@ -563,16 +596,21 @@ GMPParent::ActorDestroy(ActorDestroyReas
   mState = GMPStateClosing;
   mAbnormalShutdownInProgress = true;
   CloseActive(false);
 
   // Normal Shutdown() will delete the process on unwind.
   if (AbnormalShutdown == aWhy) {
     nsRefPtr<GMPParent> self(this);
     if (mAsyncShutdownRequired) {
+#if defined(MOZ_CRASHREPORTER)
+      CrashReporter::AnnotateCrashReport(
+        nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
+        NS_LITERAL_CSTRING("Actor destroyed"));
+#endif
       mService->AsyncShutdownComplete(this);
       mAsyncShutdownRequired = false;
     }
     // Must not call Close() again in DeleteProcess(), as we'll recurse
     // infinitely if we do.
     MOZ_ASSERT(mState == GMPStateClosing);
     DeleteProcess();
     // Note: final destruction will be Dispatched to ourself
@@ -865,16 +903,21 @@ GMPParent::RecvAsyncShutdownRequired()
 }
 
 bool
 GMPParent::RecvAsyncShutdownComplete()
 {
   LOGD("%s", __FUNCTION__);
 
   MOZ_ASSERT(mAsyncShutdownRequired);
+#if defined(MOZ_CRASHREPORTER)
+  CrashReporter::AnnotateCrashReport(
+    nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
+    NS_LITERAL_CSTRING("Received AsyncShutdownComplete"));
+#endif
   AbortAsyncShutdown();
   return true;
 }
 
 class RunCreateContentParentCallbacks : public nsRunnable
 {
 public:
   explicit RunCreateContentParentCallbacks(GMPContentParent* aGMPContentParent)
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -311,17 +311,17 @@ SourceBuffer::SourceBuffer(MediaSource* 
   , mActive(false)
   , mUpdateID(0)
   , mReportedOffset(0)
   , mType(aType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aMediaSource);
   mEvictionThreshold = Preferences::GetUint("media.mediasource.eviction_threshold",
-                                            75 * (1 << 20));
+                                            100 * (1 << 20));
   mContentManager =
     SourceBufferContentManager::CreateManager(this,
                                               aMediaSource->GetDecoder(),
                                               aType);
   MSE_DEBUG("Create mContentManager=%p",
             mContentManager.get());
   if (aType.LowerCaseEqualsLiteral("audio/mpeg") ||
       aType.LowerCaseEqualsLiteral("audio/aac")) {
@@ -576,30 +576,29 @@ SourceBuffer::PrepareAppend(const uint8_
     // We notify that we've evicted from the time range 0 through to
     // the current start point.
     mMediaSource->NotifyEvicted(0.0, newBufferStartTime.ToSeconds());
   }
 
   // See if we have enough free space to append our new data.
   // As we can only evict once we have playable data, we must give a chance
   // to the DASH player to provide a complete media segment.
-  if (aLength > mEvictionThreshold ||
+  if (aLength > mEvictionThreshold || evicted == Result::BUFFER_FULL ||
       ((!mIsUsingFormatReader &&
         mContentManager->GetSize() > mEvictionThreshold - aLength) &&
        evicted != Result::CANT_EVICT)) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
   }
 
   nsRefPtr<MediaByteBuffer> data = new MediaByteBuffer();
   if (!data->AppendElements(aData, aLength, fallible)) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
   }
-  // TODO: Test buffer full flag.
   return data.forget();
 }
 
 double
 SourceBuffer::GetBufferedStart()
 {
   MOZ_ASSERT(NS_IsMainThread());
   ErrorResult dummy;
--- a/dom/media/mediasource/SourceBufferContentManager.h
+++ b/dom/media/mediasource/SourceBufferContentManager.h
@@ -52,16 +52,17 @@ public:
   // http://w3c.github.io/media-source/#sourcebuffer-coded-frame-removal
   virtual nsRefPtr<RangeRemovalPromise> RangeRemoval(TimeUnit aStart, TimeUnit aEnd) = 0;
 
   enum class EvictDataResult : int8_t
   {
     NO_DATA_EVICTED,
     DATA_EVICTED,
     CANT_EVICT,
+    BUFFER_FULL,
   };
 
   // Evicts data up to aPlaybackTime. aThreshold is used to
   // bound the data being evicted. It will not evict more than aThreshold
   // bytes. aBufferStartTime contains the new start time of the data after the
   // eviction.
   virtual EvictDataResult
   EvictData(TimeUnit aPlaybackTime, uint32_t aThreshold, TimeUnit* aBufferStartTime) = 0;
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -34,32 +34,63 @@ AppendStateToStr(TrackBuffersManager::Ap
       return "PARSING_MEDIA_SEGMENT";
     default:
       return "IMPOSSIBLE";
   }
 }
 
 static Atomic<uint32_t> sStreamSourceID(0u);
 
+#ifdef MOZ_EME
+class DispatchKeyNeededEvent : public nsRunnable {
+public:
+  DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder,
+                         nsTArray<uint8_t>& aInitData,
+                         const nsString& aInitDataType)
+    : mDecoder(aDecoder)
+    , mInitData(aInitData)
+    , mInitDataType(aInitDataType)
+  {
+  }
+  NS_IMETHOD Run() {
+    // Note: Null check the owner, as the decoder could have been shutdown
+    // since this event was dispatched.
+    MediaDecoderOwner* owner = mDecoder->GetOwner();
+    if (owner) {
+      owner->DispatchEncrypted(mInitData, mInitDataType);
+    }
+    mDecoder = nullptr;
+    return NS_OK;
+  }
+private:
+  nsRefPtr<AbstractMediaDecoder> mDecoder;
+  nsTArray<uint8_t> mInitData;
+  nsString mInitDataType;
+};
+#endif // MOZ_EME
+
 TrackBuffersManager::TrackBuffersManager(dom::SourceBuffer* aParent, MediaSourceDecoder* aParentDecoder, const nsACString& aType)
   : mInputBuffer(new MediaByteBuffer)
   , mAppendState(AppendState::WAITING_FOR_SEGMENT)
   , mBufferFull(false)
   , mFirstInitializationSegmentReceived(false)
   , mActiveTrack(false)
   , mType(aType)
   , mParser(ContainerParser::CreateForMIMEType(aType))
   , mProcessedInput(0)
   , mAppendRunning(false)
   , mTaskQueue(aParentDecoder->GetDemuxer()->GetTaskQueue())
   , mParent(new nsMainThreadPtrHolder<dom::SourceBuffer>(aParent, false /* strict */))
   , mParentDecoder(new nsMainThreadPtrHolder<MediaSourceDecoder>(aParentDecoder, false /* strict */))
   , mMediaSourceDemuxer(mParentDecoder->GetDemuxer())
   , mMediaSourceDuration(mTaskQueue, Maybe<double>(), "TrackBuffersManager::mMediaSourceDuration (Mirror)")
   , mAbort(false)
+  , mEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold",
+                                            100 * (1 << 20)))
+  , mEvictionOccurred(false)
   , mMonitor("TrackBuffersManager")
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread");
   nsRefPtr<TrackBuffersManager> self = this;
   nsCOMPtr<nsIRunnable> task =
     NS_NewRunnableFunction([self] () {
       self->mMediaSourceDuration.Connect(self->mParentDecoder->CanonicalExplicitDuration());
     });
@@ -171,16 +202,21 @@ TrackBuffersManager::EvictData(TimeUnit 
   int64_t toEvict = GetSize() - aThreshold;
   if (toEvict <= 0) {
     return EvictDataResult::NO_DATA_EVICTED;
   }
   if (toEvict <= 512*1024) {
     // Don't bother evicting less than 512KB.
     return EvictDataResult::CANT_EVICT;
   }
+
+  if (mBufferFull && mEvictionOccurred) {
+    return EvictDataResult::BUFFER_FULL;
+  }
+
   MSE_DEBUG("Reaching our size limit, schedule eviction of %lld bytes", toEvict);
 
   nsCOMPtr<nsIRunnable> task =
     NS_NewRunnableMethodWithArgs<TimeUnit, uint32_t>(
       this, &TrackBuffersManager::DoEvictData,
       aPlaybackTime, toEvict);
   GetTaskQueue()->Dispatch(task.forget());
 
@@ -340,22 +376,22 @@ TrackBuffersManager::CompleteResetParser
 }
 
 void
 TrackBuffersManager::DoEvictData(const TimeUnit& aPlaybackTime,
                                  uint32_t aSizeToEvict)
 {
   MOZ_ASSERT(OnTaskQueue());
 
-  // Remove any data we've already played, up to 5s behind.
-  TimeUnit lowerLimit = aPlaybackTime - TimeUnit::FromSeconds(5);
-  TimeUnit to;
   // Video is what takes the most space, only evict there if we have video.
   const auto& track = HasVideo() ? mVideoTracks : mAudioTracks;
   const auto& buffer = track.mBuffers.LastElement();
+  // Remove any data we've already played, or before the next sample to be
+  // demuxed whichever is lowest.
+  TimeUnit lowerLimit = std::min(track.mNextSampleTime, aPlaybackTime);
   uint32_t lastKeyFrameIndex = 0;
   int64_t toEvict = aSizeToEvict;
   uint32_t partialEvict = 0;
   for (uint32_t i = 0; i < buffer.Length(); i++) {
     const auto& frame = buffer[i];
     if (frame->mKeyframe) {
       lastKeyFrameIndex = i;
       toEvict -= partialEvict;
@@ -364,46 +400,59 @@ TrackBuffersManager::DoEvictData(const T
       }
       partialEvict = 0;
     }
     if (frame->mTime >= lowerLimit.ToMicroseconds()) {
       break;
     }
     partialEvict += sizeof(*frame) + frame->mSize;
   }
+
+  int64_t finalSize = mSizeSourceBuffer - aSizeToEvict;
+
   if (lastKeyFrameIndex > 0) {
+    MSE_DEBUG("Step1. Evicting %u bytes prior currentTime",
+              aSizeToEvict - toEvict);
     CodedFrameRemoval(
       TimeInterval(TimeUnit::FromMicroseconds(0),
-                   TimeUnit::FromMicroseconds(buffer[lastKeyFrameIndex-1]->mTime)));
+                   TimeUnit::FromMicroseconds(buffer[lastKeyFrameIndex]->mTime - 1)));
   }
-  if (toEvict <= 0) {
+
+  if (mSizeSourceBuffer <= finalSize) {
     return;
   }
 
-  // Still some to remove. Remove data starting from the end, up to 5s ahead
-  // of our playtime.
-  TimeUnit upperLimit = aPlaybackTime + TimeUnit::FromSeconds(5);
+  toEvict = mSizeSourceBuffer - finalSize;
+
+  // Still some to remove. Remove data starting from the end, up to 30s ahead
+  // of the later of the playback time or the next sample to be demuxed.
+  // 30s is a value chosen as it appears to work with YouTube.
+  TimeUnit upperLimit =
+    std::max(aPlaybackTime, track.mNextSampleTime) + TimeUnit::FromSeconds(30);
+  lastKeyFrameIndex = buffer.Length();
   for (int32_t i = buffer.Length() - 1; i >= 0; i--) {
     const auto& frame = buffer[i];
     if (frame->mKeyframe) {
       lastKeyFrameIndex = i;
       toEvict -= partialEvict;
       if (toEvict < 0) {
         break;
       }
       partialEvict = 0;
     }
     if (frame->mTime <= upperLimit.ToMicroseconds()) {
       break;
     }
     partialEvict += sizeof(*frame) + frame->mSize;
   }
-  if (lastKeyFrameIndex + 1 < buffer.Length()) {
+  if (lastKeyFrameIndex < buffer.Length()) {
+    MSE_DEBUG("Step2. Evicting %u bytes from trailing data",
+              mSizeSourceBuffer - finalSize);
     CodedFrameRemoval(
-      TimeInterval(TimeUnit::FromMicroseconds(buffer[lastKeyFrameIndex+1]->mTime),
+      TimeInterval(TimeUnit::FromMicroseconds(buffer[lastKeyFrameIndex]->GetEndTime() + 1),
                    TimeUnit::FromInfinity()));
   }
 }
 
 nsRefPtr<TrackBuffersManager::RangeRemovalPromise>
 TrackBuffersManager::CodedFrameRemovalWithPromise(TimeInterval aInterval)
 {
   MOZ_ASSERT(OnTaskQueue());
@@ -554,19 +603,17 @@ TrackBuffersManager::CodedFrameRemoval(T
 
     // 5. If this object is in activeSourceBuffers, the current playback position
     // is greater than or equal to start and less than the remove end timestamp,
     // and HTMLMediaElement.readyState is greater than HAVE_METADATA, then set the
     // HTMLMediaElement.readyState attribute to HAVE_METADATA and stall playback.
     // This will be done by the MDSM during playback.
     // TODO properly, so it works even if paused.
   }
-  // 4. If buffer full flag equals true and this object is ready to accept more bytes, then set the buffer full flag to false.
-  // TODO.
-  mBufferFull = false;
+
   {
     MonitorAutoLock mon(mMonitor);
     mVideoBufferedRanges = mVideoTracks.mBufferedRanges;
     mAudioBufferedRanges = mAudioTracks.mBufferedRanges;
   }
 
   if (HasVideo()) {
     MSE_DEBUG("after video ranges=%s",
@@ -575,16 +622,22 @@ TrackBuffersManager::CodedFrameRemoval(T
   if (HasAudio()) {
     MSE_DEBUG("after audio ranges=%s",
               DumpTimeRanges(mAudioTracks.mBufferedRanges).get());
   }
 
   // Update our reported total size.
   mSizeSourceBuffer = mVideoTracks.mSizeBuffer + mAudioTracks.mSizeBuffer;
 
+  // 4. If buffer full flag equals true and this object is ready to accept more bytes, then set the buffer full flag to false.
+  if (mBufferFull && mSizeSourceBuffer < mEvictionThreshold) {
+    mBufferFull = false;
+  }
+  mEvictionOccurred = true;
+
   // Tell our demuxer that data was removed.
   mMediaSourceDemuxer->NotifyTimeRangesChanged();
 
   return dataRemoved;
 }
 
 nsRefPtr<TrackBuffersManager::AppendPromise>
 TrackBuffersManager::InitSegmentParserLoop()
@@ -948,27 +1001,29 @@ TrackBuffersManager::OnDemuxerInitDone(n
 
     // 6. Set first initialization segment received flag to true.
     mFirstInitializationSegmentReceived = true;
   } else {
     mAudioTracks.mLastInfo = new SharedTrackInfo(info.mAudio, streamID);
     mVideoTracks.mLastInfo = new SharedTrackInfo(info.mVideo, streamID);
   }
 
-  // TODO CHECK ENCRYPTION
   UniquePtr<EncryptionInfo> crypto = mInputDemuxer->GetCrypto();
   if (crypto && crypto->IsEncrypted()) {
 #ifdef MOZ_EME
     // Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
     for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
-//      NS_DispatchToMainThread(
-//        new DispatchKeyNeededEvent(mParentDecoder, crypto->mInitDatas[i].mInitData, NS_LITERAL_STRING("cenc")));
+      NS_DispatchToMainThread(
+        new DispatchKeyNeededEvent(mParentDecoder, crypto->mInitDatas[i].mInitData, NS_LITERAL_STRING("cenc")));
     }
 #endif // MOZ_EME
     info.mCrypto = *crypto;
+    // We clear our crypto init data array, so the MediaFormatReader will
+    // not emit an encrypted event for the same init data again.
+    info.mCrypto.mInitDatas.Clear();
     mEncrypted = true;
   }
 
   {
     MonitorAutoLock mon(mMonitor);
     mInfo = info;
   }
 
@@ -1175,18 +1230,20 @@ TrackBuffersManager::CompleteCodedFrameP
     }
   }
 
   // Update our reported total size.
   mSizeSourceBuffer = mVideoTracks.mSizeBuffer + mAudioTracks.mSizeBuffer;
 
   // Return to step 6.4 of Segment Parser Loop algorithm
   // 4. If this SourceBuffer is full and cannot accept more media data, then set the buffer full flag to true.
-  // TODO
-  mBufferFull = false;
+  if (mSizeSourceBuffer >= mEvictionThreshold) {
+    mBufferFull = true;
+    mEvictionOccurred = false;
+  }
 
   // 5. If the input buffer does not contain a complete media segment, then jump to the need more data step below.
   if (mParser->MediaSegmentRange().IsNull()) {
     ResolveProcessing(true, __func__);
     return;
   }
 
   // 6. Remove the media segment bytes from the beginning of the input buffer.
@@ -1355,88 +1412,94 @@ TrackBuffersManager::ProcessFrame(MediaR
   //      Remove all coded frames from track buffer that have a presentation timestamp greater than or equal to highest end timestamp and less than frame end timestamp
 
   // There is an ambiguity on how to remove frames, which was lodged with:
   // https://www.w3.org/Bugs/Public/show_bug.cgi?id=28710, implementing as per
   // bug description.
   Maybe<uint32_t> firstRemovedIndex;
   TimeInterval removedInterval;
   TrackBuffer& data = trackBuffer.mBuffers.LastElement();
-  if (trackBuffer.mBufferedRanges.ContainsStrict(presentationTimestamp)) {
+  bool removeCodedFrames =
+    trackBuffer.mHighestEndTimestamp.isSome()
+      ? trackBuffer.mHighestEndTimestamp.ref() <= presentationTimestamp
+      : true;
+  if (removeCodedFrames) {
     TimeUnit lowerBound =
       trackBuffer.mHighestEndTimestamp.valueOr(presentationTimestamp);
-    for (uint32_t i = 0; i < data.Length();) {
-      MediaRawData* sample = data[i].get();
-      if (sample->mTime >= lowerBound.ToMicroseconds() &&
-          sample->mTime < frameEndTimestamp.ToMicroseconds()) {
-        if (firstRemovedIndex.isNothing()) {
-          removedInterval =
-            TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
-                         TimeUnit::FromMicroseconds(sample->GetEndTime()));
-          firstRemovedIndex = Some(i);
+    if (trackBuffer.mBufferedRanges.ContainsStrict(lowerBound)) {
+      for (uint32_t i = 0; i < data.Length();) {
+        MediaRawData* sample = data[i].get();
+        if (sample->mTime >= lowerBound.ToMicroseconds() &&
+            sample->mTime < frameEndTimestamp.ToMicroseconds()) {
+          if (firstRemovedIndex.isNothing()) {
+            removedInterval =
+              TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
+                           TimeUnit::FromMicroseconds(sample->GetEndTime()));
+            firstRemovedIndex = Some(i);
+          } else {
+            removedInterval = removedInterval.Span(
+              TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
+                           TimeUnit::FromMicroseconds(sample->GetEndTime())));
+          }
+          trackBuffer.mSizeBuffer -= sizeof(*sample) + sample->mSize;
+          MSE_DEBUGV("Overlapping frame:%u ([%f, %f))",
+                    i,
+                    TimeUnit::FromMicroseconds(sample->mTime).ToSeconds(),
+                    TimeUnit::FromMicroseconds(sample->GetEndTime()).ToSeconds());
+          data.RemoveElementAt(i);
+
+          if (trackBuffer.mNextGetSampleIndex.isSome()) {
+            if (trackBuffer.mNextGetSampleIndex.ref() == i) {
+              MSE_DEBUG("Next sample to be played got evicted");
+              trackBuffer.mNextGetSampleIndex.reset();
+            } else if (trackBuffer.mNextGetSampleIndex.ref() > i) {
+              trackBuffer.mNextGetSampleIndex.ref()--;
+            }
+          }
         } else {
-          removedInterval = removedInterval.Span(
-            TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
-                         TimeUnit::FromMicroseconds(sample->GetEndTime())));
+          i++;
         }
-        trackBuffer.mSizeBuffer -= sizeof(*sample) + sample->mSize;
-        MSE_DEBUGV("Overlapping frame:%u ([%f, %f))",
-                  i,
-                  TimeUnit::FromMicroseconds(sample->mTime).ToSeconds(),
-                  TimeUnit::FromMicroseconds(sample->GetEndTime()).ToSeconds());
-        data.RemoveElementAt(i);
-
-        if (trackBuffer.mNextGetSampleIndex.isSome()) {
-          if (trackBuffer.mNextGetSampleIndex.ref() == i) {
-            MSE_DEBUG("Next sample to be played got evicted");
-            trackBuffer.mNextGetSampleIndex.reset();
-          } else if (trackBuffer.mNextGetSampleIndex.ref() > i) {
-            trackBuffer.mNextGetSampleIndex.ref()--;
-          }
-        }
-      } else {
-        i++;
       }
     }
-  }
-  // 15. Remove decoding dependencies of the coded frames removed in the previous step:
-  // Remove all coded frames between the coded frames removed in the previous step and the next random access point after those removed frames.
-  if (firstRemovedIndex.isSome()) {
-    uint32_t start = firstRemovedIndex.ref();
-    uint32_t end = start;
-    for (;end < data.Length(); end++) {
-      MediaRawData* sample = data[end].get();
-      if (sample->mKeyframe) {
-        break;
+    // 15. Remove decoding dependencies of the coded frames removed in the previous step:
+    // Remove all coded frames between the coded frames removed in the previous step and the next random access point after those removed frames.
+    if (firstRemovedIndex.isSome()) {
+      uint32_t start = firstRemovedIndex.ref();
+      uint32_t end = start;
+      for (;end < data.Length(); end++) {
+        MediaRawData* sample = data[end].get();
+        if (sample->mKeyframe) {
+          break;
+        }
+        removedInterval = removedInterval.Span(
+          TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
+                       TimeUnit::FromMicroseconds(sample->GetEndTime())));
+        trackBuffer.mSizeBuffer -= sizeof(*sample) + sample->mSize;
       }
-      removedInterval = removedInterval.Span(
-        TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
-                     TimeUnit::FromMicroseconds(sample->GetEndTime())));
-      trackBuffer.mSizeBuffer -= sizeof(*sample) + sample->mSize;
-    }
-    data.RemoveElementsAt(start, end - start);
+      data.RemoveElementsAt(start, end - start);
 
-    MSE_DEBUG("Removing undecodable frames from:%u (frames:%u) ([%f, %f))",
-              start, end - start,
-              removedInterval.mStart.ToSeconds(), removedInterval.mEnd.ToSeconds());
+      MSE_DEBUG("Removing undecodable frames from:%u (frames:%u) ([%f, %f))",
+                start, end - start,
+                removedInterval.mStart.ToSeconds(), removedInterval.mEnd.ToSeconds());
 
-    if (trackBuffer.mNextGetSampleIndex.isSome()) {
-      if (trackBuffer.mNextGetSampleIndex.ref() >= start &&
-          trackBuffer.mNextGetSampleIndex.ref() < end) {
-        MSE_DEBUG("Next sample to be played got evicted");
-        trackBuffer.mNextGetSampleIndex.reset();
-      } else if (trackBuffer.mNextGetSampleIndex.ref() >= end) {
-        trackBuffer.mNextGetSampleIndex.ref() -= end - start;
+      if (trackBuffer.mNextGetSampleIndex.isSome()) {
+        if (trackBuffer.mNextGetSampleIndex.ref() >= start &&
+            trackBuffer.mNextGetSampleIndex.ref() < end) {
+          MSE_DEBUG("Next sample to be played got evicted");
+          trackBuffer.mNextGetSampleIndex.reset();
+        } else if (trackBuffer.mNextGetSampleIndex.ref() >= end) {
+          trackBuffer.mNextGetSampleIndex.ref() -= end - start;
+        }
       }
+
+      // Update our buffered range to exclude the range just removed.
+      trackBuffer.mBufferedRanges -= removedInterval;
+      MOZ_ASSERT(trackBuffer.mNextInsertionIndex.isNothing() ||
+                 trackBuffer.mNextInsertionIndex.ref() <= start);
     }
-
-    // Update our buffered range to exclude the range just removed.
-    trackBuffer.mBufferedRanges -= removedInterval;
-    MOZ_ASSERT(trackBuffer.mNextInsertionIndex.isNothing() ||
-               trackBuffer.mNextInsertionIndex.ref() <= start);
   }
 
   // 16. Add the coded frame with the presentation timestamp, decode timestamp, and frame duration to the track buffer.
   aSample->mTime = presentationTimestamp.ToMicroseconds();
   aSample->mTimecode = decodeTimestamp.ToMicroseconds();
   aSample->mTrackInfo = trackBuffer.mLastInfo;
 
   if (data.IsEmpty()) {
@@ -1559,21 +1622,21 @@ TrackBuffersManager::GetTracksList()
   return tracks;
 }
 
 void
 TrackBuffersManager::RestoreCachedVariables()
 {
   MOZ_ASSERT(OnTaskQueue());
   if (mTimestampOffset != mLastTimestampOffset) {
+    nsRefPtr<TrackBuffersManager> self = this;
     nsCOMPtr<nsIRunnable> task =
-      NS_NewRunnableMethodWithArg<TimeUnit>(
-        mParent.get(),
-        static_cast<void (dom::SourceBuffer::*)(const TimeUnit&)>(&dom::SourceBuffer::SetTimestampOffset), /* beauty uh? :) */
-        mTimestampOffset);
+      NS_NewRunnableFunction([self] {
+        self->mParent->SetTimestampOffset(self->mTimestampOffset);
+      });
     AbstractThread::MainThread()->Dispatch(task.forget());
   }
 }
 
 void
 TrackBuffersManager::SetAppendState(TrackBuffersManager::AppendState aAppendState)
 {
   MSE_DEBUG("AppendState changed from %s to %s",
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -305,16 +305,18 @@ private:
 
   // Set to true if abort was called.
   Atomic<bool> mAbort;
   // Set to true if mediasource state changed to ended.
   Atomic<bool> mEnded;
 
   // Global size of this source buffer content.
   Atomic<int64_t> mSizeSourceBuffer;
+  uint32_t mEvictionThreshold;
+  Atomic<bool> mEvictionOccurred;
 
   // Monitor to protect following objects accessed across multipple threads.
   mutable Monitor mMonitor;
   // Stable audio and video track time ranges.
   TimeIntervals mVideoBufferedRanges;
   TimeIntervals mAudioBufferedRanges;
   // MediaInfo of the first init segment read.
   MediaInfo mInfo;
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -105,21 +105,16 @@ AudioContext::AudioContext(nsPIDOMWindow
   // bound to the window.
   mDestination = new AudioDestinationNode(this, aIsOffline, aChannel,
                                           aNumberOfChannels, aLength, aSampleRate);
   // We skip calling SetIsOnlyNodeForContext and the creation of the
   // audioChannelAgent during mDestination's constructor, because we can only
   // call them after mDestination has been set up.
   mDestination->CreateAudioChannelAgent();
   mDestination->SetIsOnlyNodeForContext(true);
-  // We don't use the cubeb context yet, but need to ensure it is created on
-  // the main thread.
-  if (!aIsOffline && !CubebUtils::GetCubebContext()) {
-    NS_WARNING("Audio backend initialization failed.");
-  }
 }
 
 AudioContext::~AudioContext()
 {
   nsPIDOMWindow* window = GetOwner();
   if (window) {
     window->RemoveAudioContext(this);
   }
--- a/dom/storage/DOMStorageCache.cpp
+++ b/dom/storage/DOMStorageCache.cpp
@@ -766,18 +766,21 @@ DOMStorageCache::StartDatabase()
 
     nsresult rv = db->Init();
     if (NS_FAILED(rv)) {
       return nullptr;
     }
 
     sDatabase = db.forget();
   } else {
+    // Use DOMLocalStorageManager::Ensure in case we're called from
+    // DOMSessionStorageManager's initializer and we haven't yet initialized the
+    // local storage manager.
     nsRefPtr<DOMStorageDBChild> db = new DOMStorageDBChild(
-        DOMLocalStorageManager::Self());
+        DOMLocalStorageManager::Ensure());
 
     nsresult rv = db->Init();
     if (NS_FAILED(rv)) {
       return nullptr;
     }
 
     db.forget(&sDatabase);
   }
--- a/dom/storage/DOMStorageManager.cpp
+++ b/dom/storage/DOMStorageManager.cpp
@@ -623,16 +623,31 @@ DOMLocalStorageManager::DOMLocalStorageM
   }
 }
 
 DOMLocalStorageManager::~DOMLocalStorageManager()
 {
   sSelf = nullptr;
 }
 
+DOMLocalStorageManager*
+DOMLocalStorageManager::Ensure()
+{
+  if (sSelf) {
+    return sSelf;
+  }
+
+  // Cause sSelf to be populated.
+  nsCOMPtr<nsIDOMStorageManager> initializer =
+    do_GetService("@mozilla.org/dom/localStorage-manager;1");
+  MOZ_ASSERT(sSelf, "Didn't initialize?");
+
+  return sSelf;
+}
+
 // DOMSessionStorageManager
 
 DOMSessionStorageManager::DOMSessionStorageManager()
   : DOMStorageManager(SessionStorage)
 {
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     // Do this only on the child process.  The thread IPC bridge
     // is also used to communicate chrome observer notifications.
--- a/dom/storage/DOMStorageManager.h
+++ b/dom/storage/DOMStorageManager.h
@@ -121,16 +121,19 @@ class DOMLocalStorageManager final : pub
 {
 public:
   DOMLocalStorageManager();
   virtual ~DOMLocalStorageManager();
 
   // Global getter of localStorage manager service
   static DOMLocalStorageManager* Self() { return sSelf; }
 
+  // Like Self, but creates an instance if we're not yet initialized.
+  static DOMLocalStorageManager* Ensure();
+
 private:
   static DOMLocalStorageManager* sSelf;
 };
 
 class DOMSessionStorageManager final : public DOMStorageManager
 {
 public:
   DOMSessionStorageManager();
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -374,51 +374,49 @@ NS_INTERFACE_MAP_BEGIN(ServiceWorkerMana
   NS_INTERFACE_MAP_ENTRY(nsIServiceWorkerManager)
   NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIServiceWorkerManager)
 NS_INTERFACE_MAP_END
 
 ServiceWorkerManager::ServiceWorkerManager()
   : mActor(nullptr)
+  , mShuttingDown(false)
 {
   // Register this component to PBackground.
   MOZ_ALWAYS_TRUE(BackgroundChild::GetOrCreateForCurrentThread(this));
 }
 
 ServiceWorkerManager::~ServiceWorkerManager()
 {
   // The map will assert if it is not empty when destroyed.
   mRegistrationInfos.Clear();
-
-  if (mActor) {
-    mActor->ManagerShuttingDown();
-
-    nsRefPtr<TeardownRunnable> runnable = new TeardownRunnable(mActor);
-    nsresult rv = NS_DispatchToMainThread(runnable);
-    unused << NS_WARN_IF(NS_FAILED(rv));
-  }
+  MOZ_ASSERT(!mActor);
 }
 
 void
 ServiceWorkerManager::Init()
 {
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    DebugOnly<nsresult> rv;
+    rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false /* ownsWeak */);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+  }
+
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     nsRefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
     MOZ_ASSERT(swr);
 
     nsTArray<ServiceWorkerRegistrationData> data;
     swr->GetRegistrations(data);
     LoadRegistrations(data);
 
-    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       DebugOnly<nsresult> rv;
-      rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false /* ownsWeak */);
-      MOZ_ASSERT(NS_SUCCEEDED(rv));
       rv = obs->AddObserver(this, PURGE_SESSION_HISTORY, false /* ownsWeak */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
       rv = obs->AddObserver(this, PURGE_DOMAIN_DATA, false /* ownsWeak */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
       rv = obs->AddObserver(this, WEBAPPS_CLEAR_DATA, false /* ownsWeak */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
@@ -867,16 +865,17 @@ class ServiceWorkerRegisterJob final : p
   friend class ContinueInstallTask;
 
   nsCString mScope;
   nsCString mScriptSpec;
   nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
   nsRefPtr<ServiceWorkerUpdateFinishCallback> mCallback;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsRefPtr<ServiceWorkerInfo> mUpdateAndInstallInfo;
+  nsCOMPtr<nsILoadGroup> mLoadGroup;
 
   ~ServiceWorkerRegisterJob()
   { }
 
   enum
   {
     REGISTER_JOB = 0,
     UPDATE_JOB = 1,
@@ -887,25 +886,29 @@ class ServiceWorkerRegisterJob final : p
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // [[Register]]
   ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue,
                            const nsCString& aScope,
                            const nsCString& aScriptSpec,
                            ServiceWorkerUpdateFinishCallback* aCallback,
-                           nsIPrincipal* aPrincipal)
+                           nsIPrincipal* aPrincipal,
+                           nsILoadGroup* aLoadGroup)
     : ServiceWorkerJob(aQueue)
     , mScope(aScope)
     , mScriptSpec(aScriptSpec)
     , mCallback(aCallback)
     , mPrincipal(aPrincipal)
+    , mLoadGroup(aLoadGroup)
     , mJobType(REGISTER_JOB)
     , mCanceled(false)
-  { }
+  {
+    MOZ_ASSERT(mLoadGroup);
+  }
 
   // [[Update]]
   ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue,
                            ServiceWorkerRegistrationInfo* aRegistration,
                            ServiceWorkerUpdateFinishCallback* aCallback)
     : ServiceWorkerJob(aQueue)
     , mRegistration(aRegistration)
     , mCallback(aCallback)
@@ -1225,17 +1228,17 @@ private:
     // byte-for-byte match with the script resource of newestWorker...
     if (workerInfo && workerInfo->ScriptSpec().Equals(mRegistration->mScriptSpec)) {
       cacheName = workerInfo->CacheName();
     }
 
     nsresult rv =
       serviceWorkerScriptCache::Compare(mRegistration->mPrincipal, cacheName,
                                         NS_ConvertUTF8toUTF16(mRegistration->mScriptSpec),
-                                        this);
+                                        this, mLoadGroup);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return Fail(rv);
     }
   }
 
   void
   Succeed()
   {
@@ -1529,18 +1532,30 @@ ServiceWorkerManager::Register(nsIDOMWin
   }
 
   ServiceWorkerJobQueue* queue = GetOrCreateJobQueue(originSuffix, cleanedScope);
   MOZ_ASSERT(queue);
 
   nsRefPtr<ServiceWorkerResolveWindowPromiseOnUpdateCallback> cb =
     new ServiceWorkerResolveWindowPromiseOnUpdateCallback(window, promise);
 
+  nsCOMPtr<nsILoadGroup> docLoadGroup = doc->GetDocumentLoadGroup();
+  nsRefPtr<WorkerLoadInfo::InterfaceRequestor> ir =
+    new WorkerLoadInfo::InterfaceRequestor(documentPrincipal, docLoadGroup);
+  ir->MaybeAddTabChild(docLoadGroup);
+
+  // Create a load group that is separate from, yet related to, the document's load group.
+  // This allows checks for interfaces like nsILoadContext to yield the values used by the
+  // the document, yet will not cancel the update job if the document's load group is cancelled.
+  nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
+  rv = loadGroup->SetNotificationCallbacks(ir);
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
+
   nsRefPtr<ServiceWorkerRegisterJob> job =
-    new ServiceWorkerRegisterJob(queue, cleanedScope, spec, cb, documentPrincipal);
+    new ServiceWorkerRegisterJob(queue, cleanedScope, spec, cb, documentPrincipal, loadGroup);
   queue->Append(job);
 
   AssertIsOnMainThread();
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_REGISTRATIONS, 1);
 
   promise.forget(aPromise);
   return NS_OK;
 }
@@ -1548,29 +1563,33 @@ ServiceWorkerManager::Register(nsIDOMWin
 void
 ServiceWorkerManager::AppendPendingOperation(ServiceWorkerJobQueue* aQueue,
                                              ServiceWorkerJob* aJob)
 {
   MOZ_ASSERT(!mActor);
   MOZ_ASSERT(aQueue);
   MOZ_ASSERT(aJob);
 
-  PendingOperation* opt = mPendingOperations.AppendElement();
-  opt->mQueue = aQueue;
-  opt->mJob = aJob;
+  if (!mShuttingDown) {
+    PendingOperation* opt = mPendingOperations.AppendElement();
+    opt->mQueue = aQueue;
+    opt->mJob = aJob;
+  }
 }
 
 void
 ServiceWorkerManager::AppendPendingOperation(nsIRunnable* aRunnable)
 {
   MOZ_ASSERT(!mActor);
   MOZ_ASSERT(aRunnable);
 
-  PendingOperation* opt = mPendingOperations.AppendElement();
-  opt->mRunnable = aRunnable;
+  if (!mShuttingDown) {
+    PendingOperation* opt = mPendingOperations.AppendElement();
+    opt->mRunnable = aRunnable;
+  }
 }
 
 /*
  * Used to handle ExtendableEvent::waitUntil() and proceed with
  * installation/activation.
  */
 class LifecycleEventPromiseHandler final : public PromiseNativeHandler
 {
@@ -2378,18 +2397,20 @@ private:
     PrincipalInfo principalInfo;
     if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(mPrincipal,
                                                       &principalInfo)))) {
       return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
     }
 
     nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
 
-    MOZ_ASSERT(swm->mActor);
-    swm->mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(mScope));
+    // Could it be that we are shutting down.
+    if (swm->mActor) {
+      swm->mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(mScope));
+    }
 
     nsAutoCString scopeKey;
     nsresult rv = swm->PrincipalToScopeKey(mPrincipal, scopeKey);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
     }
 
     // "Let registration be the result of running [[Get Registration]]
@@ -2730,20 +2751,25 @@ ServiceWorkerManager::ActorCreated(mozil
   mPendingOperations.Clear();
 }
 
 void
 ServiceWorkerManager::StoreRegistration(
                                    nsIPrincipal* aPrincipal,
                                    ServiceWorkerRegistrationInfo* aRegistration)
 {
-  MOZ_ASSERT(mActor);
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aRegistration);
 
+  if (mShuttingDown) {
+    return;
+  }
+
+  MOZ_ASSERT(mActor);
+
   ServiceWorkerRegistrationData data;
   nsresult rv = PopulateRegistrationData(aPrincipal, aRegistration, data);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   PrincipalInfo principalInfo;
   if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
@@ -4059,16 +4085,20 @@ ServiceWorkerManager::MaybeRemoveRegistr
 }
 
 void
 ServiceWorkerManager::RemoveRegistrationInternal(ServiceWorkerRegistrationInfo* aRegistration)
 {
   MOZ_ASSERT(aRegistration);
   MOZ_ASSERT(!aRegistration->IsControllingDocuments());
 
+  if (mShuttingDown) {
+    return;
+  }
+
   // All callers should be either from a job in which case the actor is
   // available, or from MaybeStopControlling(), in which case, this will only be
   // called if a valid registration is found. If a valid registration exists,
   // it means the actor is available since the original map of registrations is
   // populated by it, and any new registrations wait until the actor is
   // available before proceeding (See ServiceWorkerRegisterJob::Start).
   MOZ_ASSERT(mActor);
 
@@ -4492,31 +4522,32 @@ ServiceWorkerManager::UpdateAllRegistrat
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ServiceWorkerManager::Observe(nsISupports* aSubject,
                               const char* aTopic,
                               const char16_t* aData)
 {
-  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
-
   if (strcmp(aTopic, PURGE_SESSION_HISTORY) == 0) {
+    MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
     RemoveAll();
     PropagateRemoveAll();
     return NS_OK;
   }
 
   if (strcmp(aTopic, PURGE_DOMAIN_DATA) == 0) {
+    MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
     nsAutoString domain(aData);
     RemoveAndPropagate(NS_ConvertUTF16toUTF8(domain));
     return NS_OK;
   }
 
   if (strcmp(aTopic, WEBAPPS_CLEAR_DATA) == 0) {
+    MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
     nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
       do_QueryInterface(aSubject);
     if (NS_WARN_IF(!params)) {
       return NS_OK;
     }
 
     uint32_t appId;
     nsresult rv = params->GetAppId(&appId);
@@ -4536,28 +4567,45 @@ ServiceWorkerManager::Observe(nsISupport
 
     nsCOMPtr<nsIPrincipal> principal;
     app->GetPrincipal(getter_AddRefs(principal));
     if (NS_WARN_IF(!principal)) {
       return NS_OK;
     }
 
     RemoveAllRegistrations(principal);
-  } else if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
+    return NS_OK;
+  }
+
+  if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
+    mShuttingDown = true;
+
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
-      obs->RemoveObserver(this, PURGE_SESSION_HISTORY);
-      obs->RemoveObserver(this, PURGE_DOMAIN_DATA);
-      obs->RemoveObserver(this, WEBAPPS_CLEAR_DATA);
+
+      if (XRE_GetProcessType() == GeckoProcessType_Default) {
+        obs->RemoveObserver(this, PURGE_SESSION_HISTORY);
+        obs->RemoveObserver(this, PURGE_DOMAIN_DATA);
+        obs->RemoveObserver(this, WEBAPPS_CLEAR_DATA);
+      }
     }
-  } else {
-    MOZ_CRASH("Received message we aren't supposed to be registered for!");
-  }
-
+
+    if (mActor) {
+      mActor->ManagerShuttingDown();
+
+      nsRefPtr<TeardownRunnable> runnable = new TeardownRunnable(mActor);
+      nsresult rv = NS_DispatchToMainThread(runnable);
+      unused << NS_WARN_IF(NS_FAILED(rv));
+      mActor = nullptr;
+    }
+    return NS_OK;
+  }
+
+  MOZ_CRASH("Received message we aren't supposed to be registered for!");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ServiceWorkerManager::PropagateSoftUpdate(JS::Handle<JS::Value> aOriginAttributes,
                                           const nsAString& aScope,
                                           JSContext* aCx)
 {
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -547,15 +547,17 @@ private:
   // Removes all service worker registrations for a given principal.
   void
   RemoveAllRegistrations(nsIPrincipal* aPrincipal);
 
   nsRefPtr<ServiceWorkerManagerChild> mActor;
 
   struct PendingOperation;
   nsTArray<PendingOperation> mPendingOperations;
+
+  bool mShuttingDown;
 };
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_workers_serviceworkermanager_h
--- a/dom/workers/ServiceWorkerScriptCache.cpp
+++ b/dom/workers/ServiceWorkerScriptCache.cpp
@@ -72,31 +72,32 @@ public:
   explicit CompareNetwork(CompareManager* aManager)
     : mManager(aManager)
   {
     MOZ_ASSERT(aManager);
     AssertIsOnMainThread();
   }
 
   nsresult
-  Initialize(nsIPrincipal* aPrincipal, const nsAString& aURL)
+  Initialize(nsIPrincipal* aPrincipal, const nsAString& aURL, nsILoadGroup* aLoadGroup)
   {
     MOZ_ASSERT(aPrincipal);
     AssertIsOnMainThread();
 
     nsCOMPtr<nsIURI> uri;
     nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, nullptr);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     rv = NS_NewChannel(getter_AddRefs(mChannel),
                        uri, aPrincipal,
                        nsILoadInfo::SEC_NORMAL,
-                       nsIContentPolicy::TYPE_SCRIPT); // FIXME(nsm): TYPE_SERVICEWORKER
+                       nsIContentPolicy::TYPE_SCRIPT, // FIXME(nsm): TYPE_SERVICEWORKER
+                       aLoadGroup);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsLoadFlags flags;
     rv = mChannel->GetLoadFlags(&flags);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
@@ -275,34 +276,34 @@ public:
     , mCacheFinished(false)
     , mInCache(false)
   {
     AssertIsOnMainThread();
   }
 
   nsresult
   Initialize(nsIPrincipal* aPrincipal, const nsAString& aURL,
-             const nsAString& aCacheName)
+             const nsAString& aCacheName, nsILoadGroup* aLoadGroup)
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(aPrincipal);
 
     mURL = aURL;
 
     // Always create a CacheStorage since we want to write the network entry to
     // the cache even if there isn't an existing one.
     ErrorResult result;
     mCacheStorage = CreateCacheStorage(aPrincipal, result, getter_AddRefs(mSandbox));
     if (NS_WARN_IF(result.Failed())) {
       MOZ_ASSERT(!result.IsErrorWithMessage());
       return result.StealNSResult();
     }
 
     mCN = new CompareNetwork(this);
-    nsresult rv = mCN->Initialize(aPrincipal, aURL);
+    nsresult rv = mCN->Initialize(aPrincipal, aURL, aLoadGroup);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     if (!aCacheName.IsEmpty()) {
       mCC = new CompareCache(this);
       rv = mCC->Initialize(aPrincipal, aURL, aCacheName);
       if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -931,26 +932,27 @@ GenerateCacheName(nsAString& aName)
   id.ToProvidedString(chars);
   aName.AssignASCII(chars, NSID_LENGTH);
 
   return NS_OK;
 }
 
 nsresult
 Compare(nsIPrincipal* aPrincipal, const nsAString& aCacheName,
-        const nsAString& aURL, CompareCallback* aCallback)
+        const nsAString& aURL, CompareCallback* aCallback,
+        nsILoadGroup* aLoadGroup)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(!aURL.IsEmpty());
   MOZ_ASSERT(aCallback);
 
   nsRefPtr<CompareManager> cm = new CompareManager(aCallback);
 
-  nsresult rv = cm->Initialize(aPrincipal, aURL, aCacheName);
+  nsresult rv = cm->Initialize(aPrincipal, aURL, aCacheName, aLoadGroup);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 } // serviceWorkerScriptCache namespace
--- a/dom/workers/ServiceWorkerScriptCache.h
+++ b/dom/workers/ServiceWorkerScriptCache.h
@@ -39,17 +39,17 @@ public:
                    const nsACString& aMaxScope) = 0;
 
   NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0;
   NS_IMETHOD_(MozExternalRefCountType) Release() = 0;
 };
 
 nsresult
 Compare(nsIPrincipal* aPrincipal, const nsAString& aCacheName,
-        const nsAString& aURL, CompareCallback* aCallback);
+        const nsAString& aURL, CompareCallback* aCallback, nsILoadGroup* aLoadGroup);
 
 } // serviceWorkerScriptCache namespace
 
 } // workers namespace
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_workers_ServiceWorkerScriptCache_h
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -5957,21 +5957,23 @@ WorkerPrivate::AddFeature(JSContext* aCx
     MutexAutoLock lock(mMutex);
 
     if (mStatus >= Canceling) {
       return false;
     }
   }
 
   MOZ_ASSERT(!mFeatures.Contains(aFeature), "Already know about this one!");
+
+  if (mFeatures.IsEmpty() && !ModifyBusyCountFromWorker(aCx, true)) {
+    return false;
+  }
+
   mFeatures.AppendElement(aFeature);
-
-  return mFeatures.Length() == 1 ?
-         ModifyBusyCountFromWorker(aCx, true) :
-         true;
+  return true;
 }
 
 void
 WorkerPrivate::RemoveFeature(JSContext* aCx, WorkerFeature* aFeature)
 {
   AssertIsOnWorkerThread();
 
   MOZ_ASSERT(mFeatures.Contains(aFeature), "Didn't know about this one!");
--- a/editor/libeditor/moz.build
+++ b/editor/libeditor/moz.build
@@ -65,9 +65,11 @@ LOCAL_INCLUDES += [
     '/editor/txmgr',
     '/extensions/spellcheck/src',
     '/layout/generic',
     '/layout/style',
     '/layout/tables',
     '/layout/xul',
 ]
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 FINAL_LIBRARY = 'xul'
--- a/editor/libeditor/nsEditorEventListener.cpp
+++ b/editor/libeditor/nsEditorEventListener.cpp
@@ -54,16 +54,18 @@
 #include "nsServiceManagerUtils.h"      // for do_GetService
 #include "nsString.h"                   // for nsAutoString
 #include "nsQueryObject.h"              // for do_QueryObject
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
 #include "nsContentUtils.h"             // for nsContentUtils, etc
 #include "nsIBidiKeyboard.h"            // for nsIBidiKeyboard
 #endif
 
+#include "mozilla/dom/TabParent.h"
+
 class nsPresContext;
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static void
 DoCommandCallback(Command aCommand, void* aData)
 {
@@ -980,16 +982,24 @@ nsEditorEventListener::CanDrop(nsIDOMDra
   nsresult rv = sourceNode->GetOwnerDocument(getter_AddRefs(sourceDoc));
   NS_ENSURE_SUCCESS(rv, false);
 
   // If the source and the dest are not same document, allow to drop it always.
   if (domdoc != sourceDoc) {
     return true;
   }
 
+  // If the source node is a remote browser, treat this as coming from a
+  // different document and allow the drop.
+  nsCOMPtr<nsIContent> sourceContent = do_QueryInterface(sourceNode);
+  TabParent* tp = TabParent::GetFrom(sourceContent);
+  if (tp) {
+    return true;
+  }
+
   nsRefPtr<Selection> selection = mEditor->GetSelection();
   if (!selection) {
     return false;
   }
 
   // If selection is collapsed, allow to drop it always.
   if (selection->Collapsed()) {
     return true;
deleted file mode 100644
index ec288075e2874b7f8371930b7fdc8c4071fce40c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/embedding/tests/winEmbed/WebBrowserChrome.cpp
+++ /dev/null
@@ -1,591 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: Mozilla-sample-code 1.0
- *
- * Copyright (c) 2002 Netscape Communications Corporation and
- * other contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this Mozilla sample software and associated documentation files
- * (the "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do so, subject to the
- * following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
-
-// Local includes
-#include "resource.h"
-#include "winEmbed.h"
-#include "WebBrowserChrome.h"
-
-// OS headers
-#include <stdio.h>
-
-// Frozen APIs
-
-#include "nsStringAPI.h"
-#include "nsIComponentManager.h"
-#include "nsIDOMWindow.h"
-#include "nsIInterfaceRequestor.h"
-#include "nsIRequest.h"
-#include "nsIURI.h"
-#include "nsIWebProgress.h"
-#include "nsCWebBrowser.h"
-
-// Glue APIs (not frozen, but safe to use because they are statically linked)
-#include "nsComponentManagerUtils.h"
-
-// NON-FROZEN APIS!
-#include "nsIWebNavigation.h"
-
-WebBrowserChrome::WebBrowserChrome()
-{
-    mNativeWindow = nullptr;
-    mSizeSet = false;
-}
-
-WebBrowserChrome::~WebBrowserChrome()
-{
-    WebBrowserChromeUI::Destroyed(this);
-}
-
-nsresult WebBrowserChrome::CreateBrowser(int32_t aX, int32_t aY,
-                                         int32_t aCX, int32_t aCY,
-                                         nsIWebBrowser **aBrowser)
-{
-    NS_ENSURE_ARG_POINTER(aBrowser);
-    *aBrowser = nullptr;
-
-    mWebBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
-    
-    if (!mWebBrowser)
-        return NS_ERROR_FAILURE;
-
-    (void)mWebBrowser->SetContainerWindow(static_cast<nsIWebBrowserChrome*>(this));
-
-    nsCOMPtr<nsIBaseWindow> browserBaseWindow = do_QueryInterface(mWebBrowser);
-
-    mNativeWindow = WebBrowserChromeUI::CreateNativeWindow(static_cast<nsIWebBrowserChrome*>(this));
-
-    if (!mNativeWindow)
-        return NS_ERROR_FAILURE;
-
-    browserBaseWindow->InitWindow( mNativeWindow,
-                             nullptr, 
-                             aX, aY, aCX, aCY);
-    browserBaseWindow->Create();
-
-    nsCOMPtr<nsIWebProgressListener> listener(static_cast<nsIWebProgressListener*>(this));
-    nsCOMPtr<nsIWeakReference> thisListener(do_GetWeakReference(listener));
-    (void)mWebBrowser->AddWebBrowserListener(thisListener, 
-        NS_GET_IID(nsIWebProgressListener));
-
-    // The window has been created. Now register for history notifications
-    mWebBrowser->AddWebBrowserListener(thisListener, NS_GET_IID(nsISHistoryListener));
-
-    if (mWebBrowser)
-    {
-      *aBrowser = mWebBrowser;
-      NS_ADDREF(*aBrowser);
-      return NS_OK;
-    }
-    return NS_ERROR_FAILURE;
-}
-
-//*****************************************************************************
-// WebBrowserChrome::nsISupports
-//*****************************************************************************   
-
-NS_IMPL_ADDREF(WebBrowserChrome)
-NS_IMPL_RELEASE(WebBrowserChrome)
-
-NS_INTERFACE_MAP_BEGIN(WebBrowserChrome)
-   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
-   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
-   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
-   NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
-   NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) // optional
-   NS_INTERFACE_MAP_ENTRY(nsISHistoryListener)
-   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-   NS_INTERFACE_MAP_ENTRY(nsIObserver)
-   NS_INTERFACE_MAP_ENTRY(nsIContextMenuListener)
-   NS_INTERFACE_MAP_ENTRY(nsITooltipListener)
-NS_INTERFACE_MAP_END
-
-//*****************************************************************************
-// WebBrowserChrome::nsIInterfaceRequestor
-//*****************************************************************************   
-
-NS_IMETHODIMP WebBrowserChrome::GetInterface(const nsIID &aIID, void** aInstancePtr)
-{
-    NS_ENSURE_ARG_POINTER(aInstancePtr);
-
-    *aInstancePtr = 0;
-    if (aIID.Equals(NS_GET_IID(nsIDOMWindow)))
-    {
-        if (mWebBrowser)
-        {
-            return mWebBrowser->GetContentDOMWindow((nsIDOMWindow **) aInstancePtr);
-        }
-        return NS_ERROR_NOT_INITIALIZED;
-    }
-    return QueryInterface(aIID, aInstancePtr);
-}
-
-//*****************************************************************************
-// WebBrowserChrome::nsIWebBrowserChrome
-//*****************************************************************************   
-
-NS_IMETHODIMP WebBrowserChrome::SetStatus(uint32_t aType, const char16_t* aStatus)
-{
-    WebBrowserChromeUI::UpdateStatusBarText(this, aStatus);
-    return NS_OK;
-}
-
-NS_IMETHODIMP WebBrowserChrome::GetWebBrowser(nsIWebBrowser** aWebBrowser)
-{
-    NS_ENSURE_ARG_POINTER(aWebBrowser);
-    *aWebBrowser = mWebBrowser;
-    NS_IF_ADDREF(*aWebBrowser);
-    return NS_OK;
-}
-
-NS_IMETHODIMP WebBrowserChrome::SetWebBrowser(nsIWebBrowser* aWebBrowser)
-{
-    mWebBrowser = aWebBrowser;
-    return NS_OK;
-}
-
-NS_IMETHODIMP WebBrowserChrome::GetChromeFlags(uint32_t* aChromeMask)
-{
-    *aChromeMask = mChromeFlags;
-    return NS_OK;
-}
-
-NS_IMETHODIMP WebBrowserChrome::SetChromeFlags(uint32_t aChromeMask)
-{
-    mChromeFlags = aChromeMask;
-    return NS_OK;
-}
-
-NS_IMETHODIMP WebBrowserChrome::DestroyBrowserWindow(void)
-{
-    WebBrowserChromeUI::Destroy(this);
-    return NS_OK;
-}
-
-
-// IN: The desired browser client area dimensions.
-NS_IMETHODIMP WebBrowserChrome::SizeBrowserTo(int32_t aWidth, int32_t aHeight)
-{
-  /* This isn't exactly correct: we're setting the whole window to
-     the size requested for the browser. At time of writing, though,
-     it's fine and useful for winEmbed's purposes. */
-  WebBrowserChromeUI::SizeTo(this, aWidth, aHeight);
-  mSizeSet = true;
-  return NS_OK;
-}
-
-
-NS_IMETHODIMP WebBrowserChrome::ShowAsModal(void)
-{
-  if (mDependentParent)
-    AppCallbacks::EnableChromeWindow(mDependentParent, false);
-
-  mContinueModalLoop = true;
-  AppCallbacks::RunEventLoop(mContinueModalLoop);
-
-  if (mDependentParent)
-    AppCallbacks::EnableChromeWindow(mDependentParent, true);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP WebBrowserChrome::IsWindowModal(bool *_retval)
-{
-    *_retval = false;
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP WebBrowserChrome::ExitModalEventLoop(nsresult aStatus)
-{
-  mContinueModalLoop = false;
-  return NS_OK;
-}
-
-//*****************************************************************************
-// WebBrowserChrome::nsIWebBrowserChromeFocus
-//*****************************************************************************
-
-NS_IMETHODIMP WebBrowserChrome::FocusNextElement()
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP WebBrowserChrome::FocusPrevElement()
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-//*****************************************************************************
-// WebBrowserChrome::nsIWebProgressListener
-//*****************************************************************************   
-
-NS_IMETHODIMP WebBrowserChrome::OnProgressChange(nsIWebProgress *progress, nsIRequest *request,
-                                                  int32_t curSelfProgress, int32_t maxSelfProgress,
-                                                  int32_t curTotalProgress, int32_t maxTotalProgress)
-{
-    WebBrowserChromeUI::UpdateProgress(this, curTotalProgress, maxTotalProgress);
-    return NS_OK;
-}
-
-NS_IMETHODIMP WebBrowserChrome::OnStateChange(nsIWebProgress *progress, nsIRequest *request,
-                                               uint32_t progressStateFlags, nsresult status)
-{
-    if ((progressStateFlags & STATE_START) && (progressStateFlags & STATE_IS_DOCUMENT))
-    {
-        WebBrowserChromeUI::UpdateBusyState(this, true);
-    }
-
-    if ((progressStateFlags & STATE_STOP) && (progressStateFlags & STATE_IS_DOCUMENT))
-    {
-        WebBrowserChromeUI::UpdateBusyState(this, false);
-        WebBrowserChromeUI::UpdateProgress(this, 0, 100);
-        WebBrowserChromeUI::UpdateStatusBarText(this, nullptr);
-        ContentFinishedLoading();
-    }
-
-    return NS_OK;
-}
-
-
-NS_IMETHODIMP WebBrowserChrome::OnLocationChange(nsIWebProgress* aWebProgress,
-                                                 nsIRequest* aRequest,
-                                                 nsIURI *location,
-                                                 uint32_t aFlags)
-{
-  bool isSubFrameLoad = false; // Is this a subframe load
-  if (aWebProgress) {
-    nsCOMPtr<nsIDOMWindow>  domWindow;
-    nsCOMPtr<nsIDOMWindow>  topDomWindow;
-    aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
-    if (domWindow) { // Get root domWindow
-      domWindow->GetTop(getter_AddRefs(topDomWindow));
-    }
-    if (domWindow != topDomWindow)
-      isSubFrameLoad = true;
-  }
-  if (!isSubFrameLoad)
-    WebBrowserChromeUI::UpdateCurrentURI(this);
-  return NS_OK;
-}
-
-NS_IMETHODIMP 
-WebBrowserChrome::OnStatusChange(nsIWebProgress* aWebProgress,
-                                 nsIRequest* aRequest,
-                                 nsresult aStatus,
-                                 const char16_t* aMessage)
-{
-    WebBrowserChromeUI::UpdateStatusBarText(this, aMessage);
-    return NS_OK;
-}
-
-
-
-NS_IMETHODIMP 
-WebBrowserChrome::OnSecurityChange(nsIWebProgress *aWebProgress, 
-                                    nsIRequest *aRequest, 
-                                    uint32_t state)
-{
-    return NS_OK;
-}
-
-//*****************************************************************************
-// WebBrowserChrome::nsISHistoryListener
-//*****************************************************************************   
-
-NS_IMETHODIMP
-WebBrowserChrome::OnHistoryNewEntry(nsIURI * aNewURI)
-{
-    return SendHistoryStatusMessage(aNewURI, "add");
-}
-
-NS_IMETHODIMP
-WebBrowserChrome::OnHistoryGoBack(nsIURI * aBackURI, bool * aContinue)
-{
-    // For now, let the operation continue
-    *aContinue = true;
-    return SendHistoryStatusMessage(aBackURI, "back");
-}
-
-
-NS_IMETHODIMP
-WebBrowserChrome::OnHistoryGoForward(nsIURI * aForwardURI, bool * aContinue)
-{
-    // For now, let the operation continue
-    *aContinue = true;
-    return SendHistoryStatusMessage(aForwardURI, "forward");
-}
-
-
-NS_IMETHODIMP
-WebBrowserChrome::OnHistoryGotoIndex(int32_t aIndex, nsIURI * aGotoURI, bool * aContinue)
-{
-    // For now, let the operation continue
-    *aContinue = true;
-    return SendHistoryStatusMessage(aGotoURI, "goto", aIndex);
-}
-
-NS_IMETHODIMP
-WebBrowserChrome::OnHistoryReload(nsIURI * aURI, uint32_t aReloadFlags, bool * aContinue)
-{
-    // For now, let the operation continue
-    *aContinue = true;
-    return SendHistoryStatusMessage(aURI, "reload", 0 /* no info to pass here */, aReloadFlags);
-}
-
-NS_IMETHODIMP
-WebBrowserChrome::OnHistoryPurge(int32_t aNumEntries, bool *aContinue)
-{
-    // For now let the operation continue
-    *aContinue = false;
-    return SendHistoryStatusMessage(nullptr, "purge", aNumEntries);
-}
-
-NS_IMETHODIMP
-WebBrowserChrome::OnHistoryReplaceEntry(int32_t aIndex)
-{
-    return SendHistoryStatusMessage(nullptr, "replace", aIndex);
-}
-
-static void
-AppendIntToCString(int32_t info1, nsCString& aResult)
-{
-  char intstr[10];
-  _snprintf(intstr, sizeof(intstr) - 1, "%i", info1);
-  intstr[sizeof(intstr) - 1] = '\0';
-  aResult.Append(intstr);
-}
-
-nsresult
-WebBrowserChrome::SendHistoryStatusMessage(nsIURI * aURI, char * operation, int32_t info1, uint32_t aReloadFlags)
-{
-    nsCString uriSpec;
-    if (aURI)
-    {
-        aURI->GetSpec(uriSpec);
-    }
-
-    nsCString status;
-
-    if(!(strcmp(operation, "back")))
-    {
-        status.AssignLiteral("Going back to url: ");
-        status.Append(uriSpec);
-    }
-    else if (!(strcmp(operation, "forward")))
-    {
-        // Going forward. XXX Get string from a resource file
-        status.AssignLiteral("Going forward to url: ");
-        status.Append(uriSpec);
-    }
-    else if (!(strcmp(operation, "reload")))
-    {
-        // Reloading. XXX Get string from a resource file
-        if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY && 
-            aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE)
-        {
-            status.AssignLiteral("Reloading url, (bypassing proxy and cache): ");
-        }
-        else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY)
-        {
-            status.AssignLiteral("Reloading url, (bypassing proxy): ");
-        }
-        else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE)
-        {
-            status.AssignLiteral("Reloading url, (bypassing cache): ");
-        }
-        else
-        {
-            status.AssignLiteral("Reloading url, (normal): ");
-        }
-        status.Append(uriSpec);
-    }
-    else if (!(strcmp(operation, "add")))
-    {
-        status.Assign(uriSpec);
-        status.AppendLiteral(" added to session History");
-    }
-    else if (!(strcmp(operation, "goto")))
-    {
-        status.AssignLiteral("Going to HistoryIndex: ");
-
-	AppendIntToCString(info1, status);
-
-        status.AppendLiteral(" Url: ");
-        status.Append(uriSpec);
-    }
-    else if (!(strcmp(operation, "purge")))
-    {
-        AppendIntToCString(info1, status);
-        status.AppendLiteral(" purged from Session History");
-    }
-    else if (!(strcmp(operation, "replace")))
-    {
-        status.AssignLiteral("Replacing HistoryIndex: ");
-        AppendIntToCString(info1, status);
-    }
-
-    nsString wstatus;
-    NS_CStringToUTF16(status, NS_CSTRING_ENCODING_UTF8, wstatus);
-    WebBrowserChromeUI::UpdateStatusBarText(this, wstatus.get());
-
-    return NS_OK;
-}
-
-void WebBrowserChrome::ContentFinishedLoading()
-{
-  // if it was a chrome window and no one has already specified a size,
-  // size to content
-  if (mWebBrowser && !mSizeSet &&
-     (mChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)) {
-    nsCOMPtr<nsIDOMWindow> contentWin;
-    mWebBrowser->GetContentDOMWindow(getter_AddRefs(contentWin));
-    if (contentWin)
-        contentWin->SizeToContent();
-    WebBrowserChromeUI::ShowWindow(this, true);
-  }
-}
-
-
-//*****************************************************************************
-// WebBrowserChrome::nsIEmbeddingSiteWindow
-//*****************************************************************************   
-
-NS_IMETHODIMP WebBrowserChrome::SetDimensions(uint32_t aFlags, int32_t x, int32_t y, int32_t cx, int32_t cy)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP WebBrowserChrome::GetDimensions(uint32_t aFlags, int32_t *x, int32_t *y, int32_t *cx, int32_t *cy)
-{
-    if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION)
-    {
-        *x = 0;
-        *y = 0;
-    }
-    if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER ||
-        aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER)
-    {
-        *cx = 0;
-        *cy = 0;
-    }
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* void setFocus (); */
-NS_IMETHODIMP WebBrowserChrome::SetFocus()
-{
-    WebBrowserChromeUI::SetFocus(this);
-    return NS_OK;
-}
-
-/* void blur (); */
-NS_IMETHODIMP WebBrowserChrome::Blur()
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* attribute wstring title; */
-NS_IMETHODIMP WebBrowserChrome::GetTitle(char16_t * *aTitle)
-{
-   NS_ENSURE_ARG_POINTER(aTitle);
-
-   *aTitle = nullptr;
-   
-   return NS_ERROR_NOT_IMPLEMENTED;
-}
-NS_IMETHODIMP WebBrowserChrome::SetTitle(const char16_t * aTitle)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* attribute boolean visibility; */
-NS_IMETHODIMP WebBrowserChrome::GetVisibility(bool * aVisibility)
-{
-    NS_ENSURE_ARG_POINTER(aVisibility);
-    *aVisibility = true;
-    return NS_OK;
-}
-NS_IMETHODIMP WebBrowserChrome::SetVisibility(bool aVisibility)
-{
-    return NS_OK;
-}
-
-/* attribute nativeSiteWindow siteWindow */
-NS_IMETHODIMP WebBrowserChrome::GetSiteWindow(void * *aSiteWindow)
-{
-   NS_ENSURE_ARG_POINTER(aSiteWindow);
-
-   *aSiteWindow = mNativeWindow;
-   return NS_OK;
-}
-
-
-//*****************************************************************************
-// WebBrowserChrome::nsIObserver
-//*****************************************************************************   
-
-NS_IMETHODIMP WebBrowserChrome::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
-{
-    nsresult rv = NS_OK;
-    if (strcmp(aTopic, "profile-change-teardown") == 0)
-    {
-        // A profile change means death for this window
-        WebBrowserChromeUI::Destroy(this);
-    }
-    return rv;
-}
-
-//*****************************************************************************
-// WebBrowserChrome::nsIContextMenuListener
-//*****************************************************************************   
-
-/* void OnShowContextMenu (in unsigned long aContextFlags, in nsIDOMEvent aEvent, in nsIDOMNode aNode); */
-NS_IMETHODIMP WebBrowserChrome::OnShowContextMenu(uint32_t aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode)
-{
-    WebBrowserChromeUI::ShowContextMenu(this, aContextFlags, aEvent, aNode);
-    return NS_OK;
-}
-
-//*****************************************************************************
-// WebBrowserChrome::nsITooltipListener
-//*****************************************************************************   
-
-/* void OnShowTooltip (in long aXCoords, in long aYCoords, in wstring aTipText); */
-NS_IMETHODIMP WebBrowserChrome::OnShowTooltip(int32_t aXCoords, int32_t aYCoords, const char16_t *aTipText)
-{
-    WebBrowserChromeUI::ShowTooltip(this, aXCoords, aYCoords, aTipText);
-    return NS_OK;
-}
-
-/* void OnHideTooltip (); */
-NS_IMETHODIMP WebBrowserChrome::OnHideTooltip()
-{
-    WebBrowserChromeUI::HideTooltip(this);
-    return NS_OK;
-}
deleted file mode 100644
--- a/embedding/tests/winEmbed/WebBrowserChrome.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: Mozilla-sample-code 1.0
- *
- * Copyright (c) 2002 Netscape Communications Corporation and
- * other contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this Mozilla sample software and associated documentation files
- * (the "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do so, subject to the
- * following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef __WebBrowserChrome__
-#define __WebBrowserChrome__
-
-// OS headers
-
-#include <windows.h>
-
-// FROZEN APIs
-
-#include "nsStringAPI.h"
-
-#include "nsIWebBrowserChrome.h"
-#include "nsIWebBrowserChromeFocus.h"
-
-#include "nsIContextMenuListener.h"
-#include "nsIEmbeddingSiteWindow.h"
-#include "nsIInterfaceRequestor.h"
-#include "nsIObserver.h"
-#include "nsISHistoryListener.h"
-#include "nsITooltipListener.h"
-#include "nsIWebProgressListener.h"
-#include "nsIWebBrowser.h"
-
-// GLUE APIs (not frozen, but safe because we're statically linking them)
-#include "nsCOMPtr.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "nsWeakReference.h"
-
-class WebBrowserChromeUI
-{
-public:
-    static HWND CreateNativeWindow(nsIWebBrowserChrome* chrome);
-    static void Destroy(nsIWebBrowserChrome* chrome);
-    static void Destroyed(nsIWebBrowserChrome* chrome);
-    static void SetFocus(nsIWebBrowserChrome *chrome);
-    static void UpdateStatusBarText(nsIWebBrowserChrome *aChrome, const char16_t* aStatusText);
-    static void UpdateCurrentURI(nsIWebBrowserChrome *aChrome);
-    static void UpdateBusyState(nsIWebBrowserChrome *aChrome, bool aBusy);
-    static void UpdateProgress(nsIWebBrowserChrome *aChrome, int32_t aCurrent, int32_t aMax);
-    static void GetResourceStringById(int32_t aID, char ** aReturn);
-    static void ShowContextMenu(nsIWebBrowserChrome *aChrome, uint32_t aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode);
-    static void ShowTooltip(nsIWebBrowserChrome *aChrome, int32_t aXCoords, int32_t aYCoords, const char16_t *aTipText);
-    static void HideTooltip(nsIWebBrowserChrome *aChrome);
-    static void ShowWindow(nsIWebBrowserChrome *aChrome, bool aShow);
-    static void SizeTo(nsIWebBrowserChrome *aChrome, int32_t aWidth, int32_t aHeight);
-};
-
-class WebBrowserChrome   : public nsIWebBrowserChrome,
-                           public nsIWebBrowserChromeFocus,
-                           public nsIWebProgressListener,
-                           public nsIEmbeddingSiteWindow,
-                           public nsIInterfaceRequestor,
-                           public nsISHistoryListener,
-                           public nsIObserver,
-                           public nsIContextMenuListener,
-                           public nsITooltipListener,
-                           public nsSupportsWeakReference
-
-{
-public:
-    WebBrowserChrome();
-    virtual ~WebBrowserChrome();
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIWEBBROWSERCHROME
-    NS_DECL_NSIWEBBROWSERCHROMEFOCUS
-    NS_DECL_NSIWEBPROGRESSLISTENER
-    NS_DECL_NSIEMBEDDINGSITEWINDOW
-    NS_DECL_NSIINTERFACEREQUESTOR
-    NS_DECL_NSISHISTORYLISTENER
-    NS_DECL_NSIOBSERVER
-    NS_DECL_NSICONTEXTMENULISTENER
-    NS_DECL_NSITOOLTIPLISTENER
-
-    nsresult CreateBrowser(int32_t aX, int32_t aY, int32_t aCX, int32_t aCY,
-                           nsIWebBrowser **aBrowser);
-
-    void     SetParent(nsIWebBrowserChrome *aParent)
-               { mDependentParent = aParent; }
-   
-protected:
-    nsresult SendHistoryStatusMessage(nsIURI * aURI, char * operation, int32_t info1=0, uint32_t info2=0);
-
-    void ContentFinishedLoading();
-
-    HWND         mNativeWindow;
-    uint32_t     mChromeFlags;
-    bool         mContinueModalLoop;
-    bool         mSizeSet;
-
-    nsCOMPtr<nsIWebBrowser> mWebBrowser;
-    nsCOMPtr<nsIWebBrowserChrome> mDependentParent; // opener (for dependent windows only)
-};
-
-#endif /* __WebBrowserChrome__ */
deleted file mode 100644
--- a/embedding/tests/winEmbed/WindowCreator.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: Mozilla-sample-code 1.0
- *
- * Copyright (c) 2002 Netscape Communications Corporation and
- * other contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this Mozilla sample software and associated documentation files
- * (the "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do so, subject to the
- * following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsIWebBrowserChrome.h"
-#include "WindowCreator.h"
-#include "winEmbed.h"
-
-WindowCreator::WindowCreator()
-{
-}
-
-WindowCreator::~WindowCreator()
-{
-}
-
-NS_IMPL_ISUPPORTS(WindowCreator, nsIWindowCreator)
-
-NS_IMETHODIMP
-WindowCreator::CreateChromeWindow(nsIWebBrowserChrome *parent,
-                                  uint32_t chromeFlags,
-                                  nsIWebBrowserChrome **_retval)
-{
-    NS_ENSURE_ARG_POINTER(_retval);
-    AppCallbacks::CreateBrowserWindow(int32_t(chromeFlags), parent, _retval);
-    return *_retval ? NS_OK : NS_ERROR_FAILURE;
-}
deleted file mode 100644
--- a/embedding/tests/winEmbed/WindowCreator.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: Mozilla-sample-code 1.0
- *
- * Copyright (c) 2002 Netscape Communications Corporation and
- * other contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this Mozilla sample software and associated documentation files
- * (the "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do so, subject to the
- * following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef __WindowCreator_h_
-#define __WindowCreator_h_
-
-#include "nsIWindowCreator.h"
-
-class WindowCreator :
-      public nsIWindowCreator
-{
-public:
-    WindowCreator();
-    virtual ~WindowCreator();
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIWINDOWCREATOR
-};
-
-#endif
-
deleted file mode 100644
--- a/embedding/tests/winEmbed/moz.build
+++ /dev/null
@@ -1,44 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-GeckoProgram('winEmbed')
-
-SOURCES += [
-    'WebBrowserChrome.cpp',
-    'WindowCreator.cpp',
-    'winEmbed.cpp',
-]
-
-XPI_NAME = 'winembed'
-
-RESFILE = 'winEmbed.res'
-
-if CONFIG['GNU_CC']:
-    # Get rid of console window
-    LDFLAGS += ['-mwindows']
-else:
-    # Control the default heap size.
-    # This is the heap returned by GetProcessHeap().
-    # As we use the CRT heap, the default size is too large and wastes VM.
-    #
-    # The default heap size is 1MB on Win32.
-    # The heap will grow if need be.
-    #
-    # Set it to 256k.  See bug 127069.
-    LDFLAGS += ['/HEAP:0x40000']
-
-DISABLE_STL_WRAPPING = True
-
-USE_LIBS += [
-    'profdirserviceprovidersa_s',
-]
-
-OS_LIBS += [
-    'ole32',
-    'comdlg32',
-    'shell32',
-    'version',
-]
deleted file mode 100644
--- a/embedding/tests/winEmbed/resource.h
+++ /dev/null
@@ -1,69 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Developer Studio generated include file.
-// Used by winEmbed.rc
-//
-#define IDC_MYICON                      2
-#define IDD_WINEMBED_DIALOG             102
-#define IDD_ABOUTBOX                    103
-#define IDS_APP_TITLE                   103
-#define IDM_ABOUT                       104
-#define MOZ_OpenURI                     104
-#define MOZ_GetURI                      104
-#define IDM_EXIT                        105
-#define IDS_HELLO                       106
-#define IDI_WINEMBED                    107
-#define IDS_ABOUT                       107
-#define IDI_SMALL                       108
-#define IDS_ABOUT_TITLE                 108
-#define IDC_WINEMBED                    109
-#define IDS_HIST_BACK                   109
-#define IDS_HIST_FORWARD                110
-#define IDS_HIST_RELOAD_NORMAL          111
-#define IDS_HIST_RELOAD_BYPASSPROXY     112
-#define IDS_HIST_RELOAD_BYPASSCACHE     113
-#define IDS_HIST_ADDURL                 114
-#define IDS_HIST_RELOAD_BYPASSPROXYANDCACHE 115
-#define IDS_HIST_PURGE                  116
-#define IDS_HIST_GOTO                   117
-#define IDS_HIST_URL                    118
-#define IDR_MAINFRAME                   128
-#define IDD_BROWSER                     130
-#define IDD_BROWSER_NC                  131
-#define IDD_CHOOSEPROFILE               132
-#define MOZ_EDIT_URI                    1001
-#define IDC_GO                          1003
-#define IDC_BROWSER                     1004
-#define IDC_ADDRESS                     1005
-#define IDC_STOP                        1006
-#define IDC_STATUS                      1007
-#define IDC_BACK                        1008
-#define IDC_FORWARD                     1009
-#define IDC_PROGRESS                    1010
-#define IDC_RELOAD                      1011
-#define IDC_PROFILELIST                 1011
-#define MOZ_Open                        32771
-#define MOZ_NewBrowser                  32773
-#define MOZ_NewEditor                   32774
-#define MOZ_Cut                         32776
-#define MOZ_Copy                        32777
-#define MOZ_Paste                       32778
-#define MOZ_Delete                      32779
-#define MOZ_SelectAll                   32780
-#define MOZ_SelectNone                  32781
-#define MOZ_GoBack                      32782
-#define MOZ_GoForward                   32783
-#define MOZ_About                       32784
-#define ID_DEBUG_THISSPACEFORRENT       32786
-#define MOZ_SwitchProfile               32787
-#define IDC_STATIC                      -1
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        133
-#define _APS_NEXT_COMMAND_VALUE         32788
-#define _APS_NEXT_CONTROL_VALUE         1012
-#define _APS_NEXT_SYMED_VALUE           110
-#endif
-#endif
deleted file mode 100644
index b276a959679bf59784dd4fcd071783a0e3b120a2..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/embedding/tests/winEmbed/winEmbed.cpp
+++ /dev/null
@@ -1,1135 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: Mozilla-sample-code 1.0
- *
- * Copyright (c) 2002 Netscape Communications Corporation and
- * other contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this Mozilla sample software and associated documentation files
- * (the "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do so, subject to the
- * following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Contributor(s):
- *   Doug Turner <dougt@netscape.com>
- *   Adam Lock <adamlock@netscape.com>
- *
- * ***** END LICENSE BLOCK ***** */
-
-// C RunTime Header Files
-#include <stdio.h>
-#include <stdlib.h>
-#include <malloc.h>
-#include <memory.h>
-#include <tchar.h>
-
-// Win32 header files
-#include <windows.h>
-#include <commctrl.h>
-#include <commdlg.h>
-
-// Mozilla Frozen APIs
-#include "nsXULAppAPI.h"
-
-XRE_InitEmbedding2Type XRE_InitEmbedding2;
-XRE_TermEmbeddingType XRE_TermEmbedding;
-
-#include "nsAppDirectoryServiceDefs.h"
-#include "nsDirectoryServiceDefs.h"
-#include "nsProfileDirServiceProvider.h"
-#include "nsStringAPI.h"
-#include "nsXPCOMGlue.h"
-
-#include "nsIClipboardCommands.h"
-#include "nsIInterfaceRequestor.h"
-#include "nsIObserverService.h"
-#include "nsIObserver.h"
-#include "nsIURI.h"
-#include "nsIWebBrowserFocus.h"
-#include "nsIWindowWatcher.h"
-
-// NON-FROZEN APIs!
-#include "nsIBaseWindow.h"
-#include "nsIWebNavigation.h"
-
-// Local header files
-#include "winEmbed.h"
-#include "WebBrowserChrome.h"
-#include "WindowCreator.h"
-#include "resource.h"
-
-#define MAX_LOADSTRING 100
-
-const TCHAR *szWindowClass = _T("WINEMBED");
-
-// Foward declarations of functions included in this code module:
-static ATOM             MyRegisterClass(HINSTANCE hInstance);
-static LRESULT CALLBACK BrowserWndProc(HWND, UINT, WPARAM, LPARAM);
-static INT_PTR CALLBACK BrowserDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
-
-static nsresult InitializeWindowCreator();
-static nsresult OpenWebPage(const char * url);
-static nsresult ResizeEmbedding(nsIWebBrowserChrome* chrome);
-
-// Profile chooser stuff
-static nsresult StartupProfile();
-
-// Global variables
-static UINT gDialogCount = 0;
-static HINSTANCE ghInstanceApp = nullptr;
-static char gFirstURL[1024];
-
-// like strpbrk but finds the *last* char, not the first
-static char*
-ns_strrpbrk(char *string, const char *strCharSet)
-{
-    char *found = nullptr;
-    for (; *string; ++string) {
-        for (const char *search = strCharSet; *search; ++search) {
-            if (*search == *string) {
-                found = string;
-                // Since we're looking for the last char, we save "found"
-                // until we're at the end of the string.
-            }
-        }
-    }
-
-    return found;
-}
-
-// A list of URLs to populate the URL drop down list with
-static const TCHAR *gDefaultURLs[] = 
-{
-    _T("http://www.mozilla.org/"),
-    _T("http://www.netscape.com/"),
-    _T("http://browsertest.web.aol.com/tests/javascript/javascpt/index.htm"),
-    _T("http://127.0.0.1/"),
-    _T("http://www.yahoo.com/"),
-    _T("http://www.travelocity.com/"),
-    _T("http://www.disney.com/"),
-    _T("http://www.go.com/"),
-    _T("http://www.google.com/"),
-    _T("http://www.ebay.com/"),
-    _T("http://www.shockwave.com/"),
-    _T("http://www.slashdot.org/"),
-    _T("http://www.quicken.com/"),
-    _T("http://www.hotmail.com/"),
-    _T("http://www.cnn.com/"),
-    _T("http://www.javasoft.com/")
-};
-
-int main(int argc, char *argv[])
-{
-    nsresult rv;
-
-    printf("You are embedded, man!\n\n");
-    printf("******************************************************************\n");
-    printf("*                                                                *\n");
-    printf("*  IMPORTANT NOTE:                                               *\n");
-    printf("*                                                                *\n");
-    printf("*  WinEmbed is not supported!!! Do not raise bugs on it unless   *\n");
-    printf("*  it is badly broken (e.g. crash on start/exit, build errors)   *\n");
-    printf("*  or you have the patch to make it better! MFCEmbed is now our  *\n");
-    printf("*  embedding test application on Win32 and all testing should    *\n");
-    printf("*  be done on that.                                              *\n");
-    printf("*                                                                *\n");
-    printf("******************************************************************\n");
-    printf("\n\n");
-    
-    // Sophisticated command-line parsing in action
-    char *szFirstURL = "http://www.mozilla.org/projects/embedding/";
-	int argn;
-    for (argn = 1; argn < argc; argn++)
-    {
-		szFirstURL = argv[argn];
-    }
-    strncpy(gFirstURL, szFirstURL, sizeof(gFirstURL) - 1);
-
-    ghInstanceApp = GetModuleHandle(nullptr);
-
-    // Initialize global strings
-    TCHAR szTitle[MAX_LOADSTRING];
-    LoadString(ghInstanceApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
-    MyRegisterClass(ghInstanceApp);
-
-    char path[_MAX_PATH];
-    GetModuleFileName(ghInstanceApp, path, sizeof(path));
-    char* lastslash = ns_strrpbrk(path, "/\\");
-    if (!lastslash)
-        return 7;
-
-    strcpy(lastslash, "\\xulrunner\\xpcom.dll");
-
-    rv = XPCOMGlueStartup(path);
-    if (NS_FAILED(rv))
-        return 3;
-
-    strcpy(lastslash, "\\xulrunner\\xul.dll");
-
-    HINSTANCE xulModule = LoadLibraryEx(path, nullptr, 0);
-    if (!xulModule)
-        return 4;
-
-    XRE_InitEmbedding2 =
-        (XRE_InitEmbedding2Type) GetProcAddress(xulModule, "XRE_InitEmbedding2");
-    if (!XRE_InitEmbedding2) {
-        fprintf(stderr, "Error: %i\n", GetLastError());
-        return 5;
-    }
-
-    XRE_TermEmbedding =
-        (XRE_TermEmbeddingType) GetProcAddress(xulModule, "XRE_TermEmbedding");
-    if (!XRE_TermEmbedding) {
-        fprintf(stderr, "Error: %i\n", GetLastError());
-        return 5;
-    }
-
-    int result = 0;
-
-    // Scope all the XPCOM stuff
-    {
-        strcpy(lastslash, "\\xulrunner");
-
-        nsCOMPtr<nsIFile> xuldir;
-        rv = NS_NewNativeLocalFile(nsCString(path), false,
-                                   getter_AddRefs(xuldir));
-        if (NS_FAILED(rv))
-            return 6;
-
-        *lastslash = '\0';
-
-        nsCOMPtr<nsIFile> appdir;
-        rv = NS_NewNativeLocalFile(nsCString(path), false,
-                                   getter_AddRefs(appdir));
-        if (NS_FAILED(rv))
-            return 8;
-
-        rv = XRE_InitEmbedding2(xuldir, appdir, nullptr);
-        if (NS_FAILED(rv))
-            return 9;
-
-        if (NS_FAILED(StartupProfile())) {
-            result = 8;
-        }
-        else {
-            InitializeWindowCreator();
-
-            // Open the initial browser window
-            OpenWebPage(gFirstURL);
-
-            // Main message loop.
-            // NOTE: We use a fake event and a timeout in order to process idle stuff for
-            //       Mozilla every 1/10th of a second.
-            bool runCondition = true;
-
-            result = AppCallbacks::RunEventLoop(runCondition);
-        }
-    }
-    XRE_TermEmbedding();
-
-    return result;
-}
-
-/* InitializeWindowCreator creates and hands off an object with a callback
-   to a window creation function. This is how all new windows are opened,
-   except any created directly by the embedding app. */
-nsresult
-InitializeWindowCreator()
-{
-    // create an nsWindowCreator and give it to the WindowWatcher service
-    nsCOMPtr<nsIWindowCreator> creator(new WindowCreator());
-    if (!creator)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
-    if (!wwatch)
-        return NS_ERROR_UNEXPECTED;
-
-    return wwatch->SetWindowCreator(creator);
-}
-
-//-----------------------------------------------------------------------------
-
-//
-//  FUNCTION: OpenWebPage()
-//
-//  PURPOSE: Opens a new browser dialog and starts it loading to the
-//           specified url.
-//
-nsresult OpenWebPage(const char *url)
-{
-    nsresult  rv;
-
-    // Create the chrome object. Note that it leaves this function
-    // with an extra reference so that it can released correctly during
-    // destruction (via Win32UI::Destroy)
-
-    nsCOMPtr<nsIWebBrowserChrome> chrome;
-    rv = AppCallbacks::CreateBrowserWindow(nsIWebBrowserChrome::CHROME_ALL,
-           nullptr, getter_AddRefs(chrome));
-    if (NS_SUCCEEDED(rv))
-    {
-        // Start loading a page
-        nsCOMPtr<nsIWebBrowser> newBrowser;
-        chrome->GetWebBrowser(getter_AddRefs(newBrowser));
-        nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(newBrowser));
-
-        return webNav->LoadURI(NS_ConvertASCIItoUTF16(url).get(),
-                               nsIWebNavigation::LOAD_FLAGS_NONE,
-                               nullptr,
-                               nullptr,
-                               nullptr);
-    }
-
-    return rv;
-}   
-
-//
-//  FUNCTION: GetBrowserFromChrome()
-//
-//  PURPOSE: Returns the HWND for the webbrowser container associated
-//           with the specified chrome.
-//
-HWND GetBrowserFromChrome(nsIWebBrowserChrome *aChrome)
-{
-    if (!aChrome)
-    {
-        return nullptr;
-    }
-    nsCOMPtr<nsIEmbeddingSiteWindow> baseWindow = do_QueryInterface(aChrome);
-    HWND hwnd = nullptr;
-    baseWindow->GetSiteWindow((void **) & hwnd);
-    return hwnd;
-}
-
-
-//
-//  FUNCTION: GetBrowserDlgFromChrome()
-//
-//  PURPOSE: Returns the HWND for the browser dialog associated with
-//           the specified chrome.
-//
-HWND GetBrowserDlgFromChrome(nsIWebBrowserChrome *aChrome)
-{
-    return GetParent(GetBrowserFromChrome(aChrome));
-}
-
-
-//
-//  FUNCTION: ResizeEmbedding()
-//
-//  PURPOSE: Resizes the webbrowser window to fit its container.
-//
-nsresult ResizeEmbedding(nsIWebBrowserChrome* chrome)
-{
-    if (!chrome)
-        return NS_ERROR_FAILURE;
-    
-    nsCOMPtr<nsIEmbeddingSiteWindow> embeddingSite = do_QueryInterface(chrome);
-    HWND hWnd;
-    embeddingSite->GetSiteWindow((void **) & hWnd);
-    
-    if (!hWnd)
-        return NS_ERROR_NULL_POINTER;
-    
-    RECT rect;
-    GetClientRect(hWnd, &rect);
-    
-    // Make sure the browser is visible and sized
-    nsCOMPtr<nsIWebBrowser> webBrowser;
-    chrome->GetWebBrowser(getter_AddRefs(webBrowser));
-    nsCOMPtr<nsIBaseWindow> webBrowserAsWin = do_QueryInterface(webBrowser);
-    if (webBrowserAsWin)
-    {
-        webBrowserAsWin->SetPositionAndSize(rect.left, 
-                                   rect.top, 
-                                   rect.right - rect.left, 
-                                   rect.bottom - rect.top,
-                                   true);
-        webBrowserAsWin->SetVisibility(true);
-    }
-
-    return NS_OK;
-}
-
-
-//
-//  FUNCTION: MyRegisterClass()
-//
-//  PURPOSE: Registers the window class.
-//
-//  COMMENTS:
-//
-//    This function and its usage is only necessary if you want this code
-//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
-//    function that was added to Windows 95. It is important to call this function
-//    so that the application will get 'well formed' small icons associated
-//    with it.
-//
-ATOM MyRegisterClass(HINSTANCE hInstance)
-{
-    WNDCLASSEX wcex;
-
-    memset(&wcex, 0, sizeof(wcex));
-    wcex.cbSize = sizeof(WNDCLASSEX); 
-
-    wcex.style            = CS_HREDRAW | CS_VREDRAW;
-    wcex.lpfnWndProc    = (WNDPROC) BrowserWndProc;
-    wcex.cbClsExtra        = 0;
-    wcex.cbWndExtra        = 0;
-    wcex.hInstance        = hInstance;
-    wcex.hIcon            = LoadIcon(ghInstanceApp, (LPCTSTR)IDI_WINEMBED);
-    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
-    wcex.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
-    wcex.lpszClassName    = szWindowClass;
-    wcex.hIconSm        = LoadIcon(ghInstanceApp, (LPCTSTR)IDI_SMALL);
-
-    return RegisterClassEx(&wcex);
-}
-
-
-//
-//  FUNCTION: UpdateUI()
-//
-//  PURPOSE: Refreshes the buttons and menu items in the browser dialog
-//
-void UpdateUI(nsIWebBrowserChrome *aChrome)
-{
-    HWND hwndDlg = GetBrowserDlgFromChrome(aChrome);
-    nsCOMPtr<nsIWebBrowser> webBrowser;
-    nsCOMPtr<nsIWebNavigation> webNavigation;
-    aChrome->GetWebBrowser(getter_AddRefs(webBrowser));
-    webNavigation = do_QueryInterface(webBrowser);
-
-    bool canGoBack = false;
-    bool canGoForward = false;
-    if (webNavigation)
-    {
-        webNavigation->GetCanGoBack(&canGoBack);
-        webNavigation->GetCanGoForward(&canGoForward);
-    }
-
-    bool canCutSelection = false;
-    bool canCopySelection = false;
-    bool canPaste = false;
-
-    nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
-    if (clipCmds)
-    {
-        clipCmds->CanCutSelection(&canCutSelection);
-        clipCmds->CanCopySelection(&canCopySelection);
-        clipCmds->CanPaste(&canPaste);
-    }
-
-    HMENU hmenu = GetMenu(hwndDlg);
-    if (hmenu)
-    {
-        EnableMenuItem(hmenu, MOZ_GoBack, MF_BYCOMMAND |
-            ((canGoBack) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
-        EnableMenuItem(hmenu, MOZ_GoForward, MF_BYCOMMAND |
-            ((canGoForward) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
-
-        EnableMenuItem(hmenu, MOZ_Cut, MF_BYCOMMAND |
-            ((canCutSelection) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
-        EnableMenuItem(hmenu, MOZ_Copy, MF_BYCOMMAND |
-            ((canCopySelection) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
-        EnableMenuItem(hmenu, MOZ_Paste, MF_BYCOMMAND |
-            ((canPaste) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
-    }
-
-    HWND button;
-    button = GetDlgItem(hwndDlg, IDC_BACK);
-    if (button)
-      EnableWindow(button, canGoBack);
-    button = GetDlgItem(hwndDlg, IDC_FORWARD);
-    if (button)
-      EnableWindow(button, canGoForward);
-}
-
-
-//
-//  FUNCTION: BrowserDlgProc()
-//
-//  PURPOSE: Browser dialog windows message handler.
-//
-//  COMMENTS:
-//
-//    The code for handling buttons and menu actions is here.
-//
-INT_PTR CALLBACK BrowserDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    // Get the browser and other pointers since they are used a lot below
-    HWND hwndBrowser = GetDlgItem(hwndDlg, IDC_BROWSER);
-    nsIWebBrowserChrome *chrome = nullptr ;
-    if (hwndBrowser)
-    {
-        chrome = (nsIWebBrowserChrome *) GetWindowLongPtr(hwndBrowser, GWLP_USERDATA);
-    }
-    nsCOMPtr<nsIWebBrowser> webBrowser;
-    nsCOMPtr<nsIWebNavigation> webNavigation;
-    if (chrome)
-    {
-        chrome->GetWebBrowser(getter_AddRefs(webBrowser));
-        webNavigation = do_QueryInterface(webBrowser);
-    }
-
-    // Test the message
-    switch (uMsg)
-    {
-    case WM_INITDIALOG:
-        return TRUE;
-
-    case WM_INITMENU:
-        UpdateUI(chrome);
-        return TRUE;
-
-    case WM_SYSCOMMAND:
-        if (wParam == SC_CLOSE)
-        {
-            WebBrowserChromeUI::Destroy(chrome);
-            return TRUE;
-        }
-        break;
-
-    case WM_DESTROY:
-        return TRUE;
-
-    case WM_COMMAND:
-        if (!webBrowser)
-        {
-            return TRUE;
-        }
-
-        // Test which command was selected
-        switch (LOWORD(wParam))
-        {
-        case IDC_ADDRESS:
-            if (HIWORD(wParam) == CBN_EDITCHANGE || HIWORD(wParam) == CBN_SELCHANGE)
-            {
-                // User has changed the address field so enable the Go button
-                EnableWindow(GetDlgItem(hwndDlg, IDC_GO), TRUE);
-            }
-            break;
-
-        case IDC_GO:
-            {
-                TCHAR szURL[2048];
-                memset(szURL, 0, sizeof(szURL));
-                GetDlgItemText(hwndDlg, IDC_ADDRESS, szURL,
-                    sizeof(szURL) / sizeof(szURL[0]) - 1);
-                webNavigation->LoadURI(
-                    NS_ConvertASCIItoUTF16(szURL).get(),
-                    nsIWebNavigation::LOAD_FLAGS_NONE,
-                    nullptr,
-                    nullptr,
-                    nullptr);
-            }
-            break;
-
-        case IDC_STOP:
-            webNavigation->Stop(nsIWebNavigation::STOP_ALL);
-            UpdateUI(chrome);
-            break;
-
-        case IDC_RELOAD:
-            webNavigation->Reload(nsIWebNavigation::LOAD_FLAGS_NONE);
-            break;
-
-        case IDM_EXIT:
-            PostMessage(hwndDlg, WM_SYSCOMMAND, SC_CLOSE, 0);
-            break;
-
-        // File menu commands
-
-        case MOZ_NewBrowser:
-            OpenWebPage(gFirstURL);
-            break;
-
-        // Edit menu commands
-
-        case MOZ_Cut:
-            {
-                nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
-                clipCmds->CutSelection();
-            }
-            break;
-
-        case MOZ_Copy:
-            {
-                nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
-                clipCmds->CopySelection();
-            }
-            break;
-
-        case MOZ_Paste:
-            {
-                nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
-                clipCmds->Paste();
-            }
-            break;
-
-        case MOZ_SelectAll:
-            {
-                nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
-                clipCmds->SelectAll();
-            }
-            break;
-
-        case MOZ_SelectNone:
-            {
-                nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
-                clipCmds->SelectNone();
-            }
-            break;
-
-        // Go menu commands
-        case IDC_BACK:
-        case MOZ_GoBack:
-            webNavigation->GoBack();
-            UpdateUI(chrome);
-            break;
-
-        case IDC_FORWARD:
-        case MOZ_GoForward:
-            webNavigation->GoForward();
-            UpdateUI(chrome);
-            break;
-
-        // Help menu commands
-        case MOZ_About:
-            {
-                TCHAR szAboutTitle[MAX_LOADSTRING];
-                TCHAR szAbout[MAX_LOADSTRING];
-                LoadString(ghInstanceApp, IDS_ABOUT_TITLE, szAboutTitle, MAX_LOADSTRING);
-                LoadString(ghInstanceApp, IDS_ABOUT, szAbout, MAX_LOADSTRING);
-                MessageBox(nullptr, szAbout, szAboutTitle, MB_OK);
-            }
-            break;
-        }
-
-        return TRUE;
-
-    case WM_ACTIVATE:
-        {
-            nsCOMPtr<nsIWebBrowserFocus> focus(do_GetInterface(webBrowser));
-            if(focus)
-            {
-                switch (wParam)
-                {
-                case WA_ACTIVE:
-                    focus->Activate();
-                    break;
-                case WA_INACTIVE:
-                    focus->Deactivate();
-                    break;
-                default:
-                    break;
-                }
-            }
-        }
-        break;
-
-    case WM_SIZE:
-        {
-            UINT newDlgWidth = LOWORD(lParam);
-            UINT newDlgHeight = HIWORD(lParam);
-
-            // TODO Reposition the control bar - for the moment it's fixed size
-
-            // Reposition the status area. Status bar
-            // gets any space that the fixed size progress bar doesn't use.
-            int progressWidth;
-            int statusWidth;
-            int statusHeight;
-            HWND hwndStatus = GetDlgItem(hwndDlg, IDC_STATUS);
-            if (hwndStatus) {
-              RECT rcStatus;
-              GetWindowRect(hwndStatus, &rcStatus);
-              statusHeight = rcStatus.bottom - rcStatus.top;
-            } else
-              statusHeight = 0;
-
-            HWND hwndProgress = GetDlgItem(hwndDlg, IDC_PROGRESS);
-            if (hwndProgress) {
-              RECT rcProgress;
-              GetWindowRect(hwndProgress, &rcProgress);
-              progressWidth = rcProgress.right - rcProgress.left;
-            } else
-              progressWidth = 0;
-            statusWidth = newDlgWidth - progressWidth;
-
-            if (hwndStatus)
-              SetWindowPos(hwndStatus,
-                           HWND_TOP,
-                           0, newDlgHeight - statusHeight,
-                           statusWidth,
-                           statusHeight,
-                           SWP_NOZORDER);
-            if (hwndProgress)
-              SetWindowPos(hwndProgress,
-                           HWND_TOP,
-                           statusWidth, newDlgHeight - statusHeight,
-                           0, 0,
-                           SWP_NOSIZE | SWP_NOZORDER);
-
-            // Resize the browser area (assuming the browse is
-            // sandwiched between the control bar and status area)
-            RECT rcBrowser;
-            POINT ptBrowser;
-            GetWindowRect(hwndBrowser, &rcBrowser);
-            ptBrowser.x = rcBrowser.left;
-            ptBrowser.y = rcBrowser.top;
-            ScreenToClient(hwndDlg, &ptBrowser);
-            int browserHeight = newDlgHeight - ptBrowser.y - statusHeight;
-            if (browserHeight < 1)
-            {
-                browserHeight = 1;
-            }
-            SetWindowPos(hwndBrowser,
-                         HWND_TOP,
-                         0, 0,
-                         newDlgWidth,
-                         newDlgHeight - ptBrowser.y - statusHeight,
-                         SWP_NOMOVE | SWP_NOZORDER);
-        }
-        return TRUE;
-    }
-    return FALSE;
-}
-
-
-//
-//  FUNCTION: BrowserWndProc(HWND, UINT, WRAPAM, LPARAM)
-//
-//  PURPOSE:  Processes messages for the browser container window.
-//
-LRESULT CALLBACK BrowserWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
-    nsIWebBrowserChrome *chrome = (nsIWebBrowserChrome *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
-    switch (message) 
-    {
-    case WM_SIZE:
-        // Resize the embedded browser
-        ResizeEmbedding(chrome);
-        return 0;
-    case WM_ERASEBKGND:
-        // Reduce flicker by not painting the non-visible background
-        return 1;
-    }
-    return DefWindowProc(hWnd, message, wParam, lParam);
-}
-
-//
-//  FUNCTION: StartupProfile()
-//
-//  PURPOSE: 
-//
-nsresult StartupProfile()
-{
-
-	nsCOMPtr<nsIFile> appDataDir;
-	nsresult rv = NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_DIR, getter_AddRefs(appDataDir));
-	if (NS_FAILED(rv))
-      return rv;
-
-	appDataDir->AppendNative(nsCString("winembed"));
-
-	nsCOMPtr<nsProfileDirServiceProvider> locProvider;
-    NS_NewProfileDirServiceProvider(true, getter_AddRefs(locProvider));
-    if (!locProvider)
-      return NS_ERROR_FAILURE;
-    
-	rv = locProvider->Register();
-    if (NS_FAILED(rv))
-      return rv;
-    
-	return locProvider->SetProfileDir(appDataDir);
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// WebBrowserChromeUI
-
-//
-//  FUNCTION: CreateNativeWindow()
-//
-//  PURPOSE: Creates a new browser dialog.
-//
-//  COMMENTS:
-//
-//    This function loads the browser dialog from a resource template
-//    and returns the HWND for the webbrowser container dialog item
-//    to the caller.
-//
-HWND WebBrowserChromeUI::CreateNativeWindow(nsIWebBrowserChrome* chrome)
-{
-  // Load the browser dialog from resource
-  HWND hwndDialog;
-  uint32_t chromeFlags;
-
-  chrome->GetChromeFlags(&chromeFlags);
-  if ((chromeFlags & nsIWebBrowserChrome::CHROME_ALL) == nsIWebBrowserChrome::CHROME_ALL)
-    hwndDialog = CreateDialog(ghInstanceApp,
-                              MAKEINTRESOURCE(IDD_BROWSER),
-                              nullptr,
-                              BrowserDlgProc);
-  else
-    hwndDialog = CreateDialog(ghInstanceApp,
-                              MAKEINTRESOURCE(IDD_BROWSER_NC),
-                              nullptr,
-                              BrowserDlgProc);
-  if (!hwndDialog)
-    return nullptr;
-
-  // Stick a menu onto it
-  if (chromeFlags & nsIWebBrowserChrome::CHROME_MENUBAR) {
-    HMENU hmenuDlg = LoadMenu(ghInstanceApp, MAKEINTRESOURCE(IDC_WINEMBED));
-    SetMenu(hwndDialog, hmenuDlg);
-  } else
-    SetMenu(hwndDialog, 0);
-
-  // Add some interesting URLs to the address drop down
-  HWND hwndAddress = GetDlgItem(hwndDialog, IDC_ADDRESS);
-  if (hwndAddress) {
-    for (int i = 0; i < sizeof(gDefaultURLs) / sizeof(gDefaultURLs[0]); i++)
-    {
-      SendMessage(hwndAddress, CB_ADDSTRING, 0, (LPARAM) gDefaultURLs[i]);
-    }
-  }
-
-  // Fetch the browser window handle
-  HWND hwndBrowser = GetDlgItem(hwndDialog, IDC_BROWSER);
-  SetWindowLongPtr(hwndBrowser, GWLP_USERDATA, (LONG_PTR)chrome);  // save the browser LONG_PTR.
-  SetWindowLongPtr(hwndBrowser, GWL_STYLE, GetWindowLongPtr(hwndBrowser, GWL_STYLE) | WS_CLIPCHILDREN);
-
-  // Activate the window
-  PostMessage(hwndDialog, WM_ACTIVATE, WA_ACTIVE, 0);
-
-  gDialogCount++;
-
-  return hwndBrowser;
-}
-
-
-//
-// FUNCTION: Destroy()
-//
-// PURPOSE: Destroy the window specified by the chrome
-//
-void WebBrowserChromeUI::Destroy(nsIWebBrowserChrome* chrome)
-{
-  nsCOMPtr<nsIWebBrowser> webBrowser;
-  nsCOMPtr<nsIWebNavigation> webNavigation;
-
-  chrome->GetWebBrowser(getter_AddRefs(webBrowser));
-  webNavigation = do_QueryInterface(webBrowser);
-  if (webNavigation)
-    webNavigation->Stop(nsIWebNavigation::STOP_ALL);
-
-  chrome->ExitModalEventLoop(NS_OK);
-
-  HWND hwndDlg = GetBrowserDlgFromChrome(chrome);
-  if (hwndDlg == nullptr)
-    return;
-
-  // Explicitly destroy the embedded browser and then the chrome
-
-  // First the browser
-  nsCOMPtr<nsIWebBrowser> browser = nullptr;
-  chrome->GetWebBrowser(getter_AddRefs(browser));
-  nsCOMPtr<nsIBaseWindow> browserAsWin = do_QueryInterface(browser);
-  if (browserAsWin)
-    browserAsWin->Destroy();
-
-      // Now the chrome
-  chrome->SetWebBrowser(nullptr);
-  NS_RELEASE(chrome);
-}
-
-
-//
-// FUNCTION: Called as the final act of a chrome object during its destructor
-//
-void WebBrowserChromeUI::Destroyed(nsIWebBrowserChrome* chrome)
-{
-    HWND hwndDlg = GetBrowserDlgFromChrome(chrome);
-    if (hwndDlg == nullptr)
-    {
-        return;
-    }
-
-    // Clear the window user data
-    HWND hwndBrowser = GetDlgItem(hwndDlg, IDC_BROWSER);
-    SetWindowLongPtr(hwndBrowser, GWLP_USERDATA, 0);
-    DestroyWindow(hwndBrowser);
-    DestroyWindow(hwndDlg);
-
-    --gDialogCount;
-    if (gDialogCount == 0)
-    {
-        // Quit when there are no more browser objects
-        PostQuitMessage(0);
-    }
-}
-
-
-//
-// FUNCTION: Set the input focus onto the browser window
-//
-void WebBrowserChromeUI::SetFocus(nsIWebBrowserChrome *chrome)
-{
-    HWND hwndDlg = GetBrowserDlgFromChrome(chrome);
-    if (hwndDlg == nullptr)
-    {
-        return;
-    }
-    
-    HWND hwndBrowser = GetDlgItem(hwndDlg, IDC_BROWSER);
-    ::SetFocus(hwndBrowser);
-}
-
-//
-//  FUNCTION: UpdateStatusBarText()
-//
-//  PURPOSE: Set the status bar text.
-//
-void WebBrowserChromeUI::UpdateStatusBarText(nsIWebBrowserChrome *aChrome, const char16_t* aStatusText)
-{
-    HWND hwndDlg = GetBrowserDlgFromChrome(aChrome);
-    nsCString status; 
-    if (aStatusText) {
-        nsString wStatusText(aStatusText);
-        NS_UTF16ToCString(wStatusText, NS_CSTRING_ENCODING_NATIVE_FILESYSTEM,
-                          status);
-    }
-
-    SetDlgItemText(hwndDlg, IDC_STATUS, status.get());
-}
-
-
-//
-//  FUNCTION: UpdateCurrentURI()
-//
-//  PURPOSE: Updates the URL address field
-//
-void WebBrowserChromeUI::UpdateCurrentURI(nsIWebBrowserChrome *aChrome)
-{
-    nsCOMPtr<nsIWebBrowser> webBrowser;
-    nsCOMPtr<nsIWebNavigation> webNavigation;
-    aChrome->GetWebBrowser(getter_AddRefs(webBrowser));
-    webNavigation = do_QueryInterface(webBrowser);
-
-    nsCOMPtr<nsIURI> currentURI;
-    webNavigation->GetCurrentURI(getter_AddRefs(currentURI));
-    if (currentURI)
-    {
-        nsCString uriString;
-        currentURI->GetAsciiSpec(uriString);
-        HWND hwndDlg = GetBrowserDlgFromChrome(aChrome);
-        SetDlgItemText(hwndDlg, IDC_ADDRESS, uriString.get());
-    }
-}
-
-
-//
-//  FUNCTION: UpdateBusyState()
-//
-//  PURPOSE: Refreshes the stop/go buttons in the browser dialog
-//
-void WebBrowserChromeUI::UpdateBusyState(nsIWebBrowserChrome *aChrome, bool aBusy)
-{
-    HWND hwndDlg = GetBrowserDlgFromChrome(aChrome);
-    HWND button;
-    button = GetDlgItem(hwndDlg, IDC_STOP);
-    if (button)
-        EnableWindow(button, aBusy);
-    button = GetDlgItem(hwndDlg, IDC_GO);
-    if (button)
-        EnableWindow(button, !aBusy);
-    UpdateUI(aChrome);
-}
-
-
-//
-//  FUNCTION: UpdateProgress()
-//
-//  PURPOSE: Refreshes the progress bar in the browser dialog
-//
-void WebBrowserChromeUI::UpdateProgress(nsIWebBrowserChrome *aChrome, int32_t aCurrent, int32_t aMax)
-{
-    HWND hwndDlg = GetBrowserDlgFromChrome(aChrome);
-    HWND hwndProgress = GetDlgItem(hwndDlg, IDC_PROGRESS);
-    if (aCurrent < 0)
-    {
-        aCurrent = 0;
-    }
-    if (aCurrent > aMax)
-    {
-        aMax = aCurrent + 20; // What to do?
-    }
-    if (hwndProgress)
-    {
-        SendMessage(hwndProgress, PBM_SETRANGE, 0, MAKELPARAM(0, aMax));
-        SendMessage(hwndProgress, PBM_SETPOS, aCurrent, 0);
-    }
-}
-
-//
-//  FUNCTION: ShowContextMenu()
-//
-//  PURPOSE: Display a context menu for the given node
-//
-void WebBrowserChromeUI::ShowContextMenu(nsIWebBrowserChrome *aChrome, uint32_t aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode)
-{
-    // TODO code to test context flags and display a popup menu should go here
-}
-
-//
-//  FUNCTION: ShowTooltip()
-//
-//  PURPOSE: Show a tooltip
-//
-void WebBrowserChromeUI::ShowTooltip(nsIWebBrowserChrome *aChrome, int32_t aXCoords, int32_t aYCoords, const char16_t *aTipText)
-{
-    // TODO code to show a tooltip should go here
-}
-
-//
-//  FUNCTION: HideTooltip()
-//
-//  PURPOSE: Hide the tooltip
-//
-void WebBrowserChromeUI::HideTooltip(nsIWebBrowserChrome *aChrome)
-{
-    // TODO code to hide a tooltip should go here
-}
-
-void WebBrowserChromeUI::ShowWindow(nsIWebBrowserChrome *aChrome, bool aShow)
-{
-  HWND win = GetBrowserDlgFromChrome(aChrome);
-  ::ShowWindow(win, aShow ? SW_RESTORE : SW_HIDE);
-}
-
-void WebBrowserChromeUI::SizeTo(nsIWebBrowserChrome *aChrome, int32_t aWidth, int32_t aHeight)
-{
-  HWND hchrome = GetBrowserDlgFromChrome(aChrome);
-  HWND hbrowser = GetBrowserFromChrome(aChrome);
-  RECT chromeRect, browserRect;
-
-  ::GetWindowRect(hchrome,  &chromeRect);
-  ::GetWindowRect(hbrowser, &browserRect);
-
-  int32_t decoration_x = (browserRect.left - chromeRect.left) + 
-                         (chromeRect.right - browserRect.right);
-  int32_t decoration_y = (browserRect.top - chromeRect.top) + 
-                         (chromeRect.bottom - browserRect.bottom);
-
-  ::MoveWindow(hchrome, chromeRect.left, chromeRect.top,
-      aWidth+decoration_x,
-      aHeight+decoration_y, TRUE);
-}
-
-//
-//  FUNCTION: GetResourceStringByID()
-//
-//  PURPOSE: Get the resource string for the ID
-//
-void WebBrowserChromeUI::GetResourceStringById(int32_t aID, char ** aReturn)
-{
-    char resBuf[MAX_LOADSTRING];
-    int retval = LoadString( ghInstanceApp, aID, (LPTSTR)resBuf, sizeof(resBuf) );
-    if (retval != 0)
-    {
-        size_t resLen = strlen(resBuf);
-        *aReturn = (char *)calloc(resLen+1, sizeof(char *));
-        if (!*aReturn) return;
-            strncpy(*aReturn, resBuf, resLen);
-    }
-    return;
-}
-
-//-----------------------------------------------------------------------------
-// AppCallbacks
-//-----------------------------------------------------------------------------
-
-nsresult AppCallbacks::CreateBrowserWindow(uint32_t aChromeFlags,
-           nsIWebBrowserChrome *aParent,
-           nsIWebBrowserChrome **aNewWindow)
-{
-  WebBrowserChrome * chrome = new WebBrowserChrome();
-  if (!chrome)
-    return NS_ERROR_FAILURE;
-
-  // the interface to return and one addref, which we assume will be
-  // immediately released
-  *aNewWindow = static_cast<nsIWebBrowserChrome*>(chrome);
-  // now an extra addref; the window owns itself (to be released by
-  // WebBrowserChromeUI::Destroy)
-  NS_ADDREF(*aNewWindow);
-
-  chrome->SetChromeFlags(aChromeFlags);
-  chrome->SetParent(aParent);
-
-  // Insert the browser
-  nsCOMPtr<nsIWebBrowser> newBrowser;
-  chrome->CreateBrowser(-1, -1, -1, -1, getter_AddRefs(newBrowser));
-  if (!newBrowser)
-    return NS_ERROR_FAILURE;
-
-  // Place it where we want it.
-  ResizeEmbedding(static_cast<nsIWebBrowserChrome*>(chrome));
-
-  // if opened as chrome, it'll be made visible after the chrome has loaded.
-  // otherwise, go ahead and show it now.
-  if (!(aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME))
-    WebBrowserChromeUI::ShowWindow(*aNewWindow, true);
-
-  return NS_OK;
-}
-
-void AppCallbacks::EnableChromeWindow(nsIWebBrowserChrome *aWindow,
-                      bool aEnabled)
-{
-  HWND hwnd = GetBrowserDlgFromChrome(aWindow);
-  ::EnableWindow(hwnd, aEnabled ? TRUE : FALSE);
-}
-
-uint32_t AppCallbacks::RunEventLoop(bool &aRunCondition)
-{
-  MSG msg;
-  HANDLE hFakeEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
-
-  while (aRunCondition ) {
-    // Process pending messages
-    while (::PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE)) {
-      if (!::GetMessage(&msg, nullptr, 0, 0)) {
-        // WM_QUIT
-        aRunCondition = false;
-        break;
-      }
-
-      ::TranslateMessage(&msg);
-      ::DispatchMessage(&msg);
-    }
-
-    // Do idle stuff
-    ::MsgWaitForMultipleObjects(1, &hFakeEvent, FALSE, 100, QS_ALLEVENTS);
-  }
-  ::CloseHandle(hFakeEvent);
-  return (uint32_t)msg.wParam;
-}
deleted file mode 100644
--- a/embedding/tests/winEmbed/winEmbed.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: Mozilla-sample-code 1.0
- *
- * Copyright (c) 2002 Netscape Communications Corporation and
- * other contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this Mozilla sample software and associated documentation files
- * (the "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do so, subject to the
- * following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nscore.h"
-
-class nsIWebBrowserChrome;
-
-namespace AppCallbacks {
-  nsresult CreateBrowserWindow(uint32_t aChromeFlags,
-             nsIWebBrowserChrome *aParent,
-             nsIWebBrowserChrome **aNewWindow);
-
-  void     EnableChromeWindow(nsIWebBrowserChrome *aWindow, bool aEnabled);
-
-  uint32_t RunEventLoop(bool &aRunCondition);
-}
deleted file mode 100644
--- a/embedding/tests/winEmbed/winEmbed.rc
+++ /dev/null
@@ -1,265 +0,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#define APSTUDIO_HIDDEN_SYMBOLS
-#include "windows.h"
-#undef APSTUDIO_HIDDEN_SYMBOLS
-#include "resource.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_WINEMBED            ICON                    "winEmbed.ICO"
-IDI_SMALL               ICON                    "SMALL.ICO"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Menu
-//
-
-IDC_WINEMBED MENU 
-BEGIN
-    POPUP "&File"
-    BEGIN
-        MENUITEM "New Browser...",              MOZ_NewBrowser
-        MENUITEM "E&xit",                       IDM_EXIT
-    END
-    POPUP "&Edit"
-    BEGIN
-        MENUITEM "Cu&t",                        MOZ_Cut
-        MENUITEM "&Copy",                       MOZ_Copy
-        MENUITEM "&Paste",                      MOZ_Paste
-        MENUITEM SEPARATOR
-        MENUITEM "Select All",                  MOZ_SelectAll
-        MENUITEM "Select None",                 MOZ_SelectNone
-    END
-    POPUP "&Go"
-    BEGIN
-        MENUITEM "&Back",                       MOZ_GoBack
-        MENUITEM "&Forward",                    MOZ_GoForward
-    END
-    POPUP "&Debug"
-    BEGIN
-        MENUITEM "&This space for rent",        ID_DEBUG_THISSPACEFORRENT
-        , GRAYED
-    END
-    POPUP "&Help"
-    BEGIN
-        MENUITEM "&About winEmbed...",          MOZ_About
-    END
-END
-
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-2 TEXTINCLUDE 
-BEGIN
-    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
-    "#include ""windows.h""\r\n"
-    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
-    "#include ""resource.h""\r\n"
-    "\0"
-END
-
-3 TEXTINCLUDE 
-BEGIN
-    "\r\n"
-    "\0"
-END
-
-1 TEXTINCLUDE 
-BEGIN
-    "resource.h\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE 
-BEGIN
-    IDS_APP_TITLE           "winEmbed"
-    IDS_HELLO               "Embedding Mozilla is so much fun!!"
-    IDS_ABOUT               "winEmbed - Gecko embedding sample"
-    IDS_ABOUT_TITLE         "About winEmbed"
-    IDS_HIST_BACK           "Going Back to: "
-    IDS_HIST_FORWARD        "Going Forward to: "
-    IDS_HIST_RELOAD_NORMAL  "Reloading url, (normal) :"
-END
-
-STRINGTABLE 
-BEGIN
-    IDS_HIST_RELOAD_BYPASSPROXY "Reloading url, (bypassing Proxy) :"
-    IDS_HIST_RELOAD_BYPASSCACHE "Reloading url, (bypassing cache) :"
-    IDS_HIST_ADDURL         " added to Session History"
-    IDS_HIST_RELOAD_BYPASSPROXYANDCACHE 
-                            "Reloading url, (bypassing Proxy and cache) :"
-    IDS_HIST_PURGE          "purged from session history"
-    IDS_HIST_GOTO           "Going to history index : "
-    IDS_HIST_URL            " URL : "
-END
-
-#endif    // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.K.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
-#pragma code_page(1252)
-#endif //_WIN32
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_BROWSER DIALOG  0, 0, 400, 217
-STYLE DS_SETFONT | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | 
-    WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-CAPTION "winEmbed sample - UNSUPPORTED"
-MENU IDC_WINEMBED
-FONT 8, "MS Sans Serif"
-BEGIN
-    PUSHBUTTON      "Back",IDC_BACK,1,1,21,13
-    PUSHBUTTON      "Forward",IDC_FORWARD,23,1,30,13
-    PUSHBUTTON      "Reload",IDC_RELOAD,57,1,28,13
-    PUSHBUTTON      "Stop",IDC_STOP,86,1,25,13
-    LTEXT           "Address:",IDC_STATIC,115,3,28,8
-    COMBOBOX        IDC_ADDRESS,145,1,193,52,CBS_DROPDOWN | CBS_AUTOHSCROLL | 
-                    WS_VSCROLL | WS_TABSTOP
-    DEFPUSHBUTTON   "Go",IDC_GO,340,1,25,13
-    CONTROL         "Embedded Browser",IDC_BROWSER,"WINEMBED",WS_TABSTOP,0,
-                    16,400,192
-    CONTROL         "Status",IDC_STATUS,"Static",SS_LEFTNOWORDWRAP | 
-                    SS_SUNKEN | WS_GROUP,0,208,316,9
-    CONTROL         "Progress1",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
-                    316,208,84,9
-END
-
-IDD_BROWSER_NC DIALOG  0, 0, 400, 217
-STYLE DS_SETFONT | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | 
-    WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-CAPTION "winEmbed chromeless sample"
-MENU IDC_WINEMBED
-FONT 8, "MS Sans Serif"
-BEGIN
-    CONTROL         "Embedded Browser",IDC_BROWSER,"WINEMBED",WS_TABSTOP,0,0,
-                    400,217
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO 
-BEGIN
-    IDD_BROWSER, DIALOG
-    BEGIN
-        RIGHTMARGIN, 292
-        BOTTOMMARGIN, 216
-    END
-END
-#endif    // APSTUDIO_INVOKED
-
-#endif    // English (U.K.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-/////////////////////////////////////////////////////////////////////////////
-// English (Ireland) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENI)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_EIRE
-#pragma code_page(1252)
-#endif //_WIN32
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_CHOOSEPROFILE DIALOG  0, 0, 186, 154
-STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | 
-    WS_SYSMENU
-CAPTION "Choose Profile"
-FONT 8, "MS Sans Serif"
-BEGIN
-    LTEXT           "Available Profiles:",IDC_STATIC,7,7,56,8
-    LISTBOX         IDC_PROFILELIST,7,18,117,129,LBS_NOINTEGRALHEIGHT | 
-                    WS_VSCROLL | WS_TABSTOP
-    DEFPUSHBUTTON   "Select",IDOK,129,18,50,14
-    PUSHBUTTON      "Cancel",IDCANCEL,129,36,50,14
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO 
-BEGIN
-    IDD_CHOOSEPROFILE, DIALOG
-    BEGIN
-        LEFTMARGIN, 7
-        RIGHTMARGIN, 179
-        TOPMARGIN, 7
-        BOTTOMMARGIN, 147
-    END
-END
-#endif    // APSTUDIO_INVOKED
-
-#endif    // English (Ireland) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
deleted file mode 100644
--- a/embedding/tests/winEmbed/winembed.dsp
+++ /dev/null
@@ -1,141 +0,0 @@
-# Microsoft Developer Studio Project File - Name="winembed" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) External Target" 0x0106
-
-CFG=winembed - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE 
-!MESSAGE NMAKE /f "winembed.mak".
-!MESSAGE 
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE 
-!MESSAGE NMAKE /f "winembed.mak" CFG="winembed - Win32 Debug"
-!MESSAGE 
-!MESSAGE Possible choices for configuration are:
-!MESSAGE 
-!MESSAGE "winembed - Win32 Release" (based on "Win32 (x86) External Target")
-!MESSAGE "winembed - Win32 Debug" (based on "Win32 (x86) External Target")
-!MESSAGE 
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-
-!IF  "$(CFG)" == "winembed - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Cmd_Line "NMAKE /f winembed.mak"
-# PROP BASE Rebuild_Opt "/a"
-# PROP BASE Target_File "winembed.exe"
-# PROP BASE Bsc_Name "winembed.bsc"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Cmd_Line "nmake /f makefile.win"
-# PROP Rebuild_Opt "/a"
-# PROP Target_File "win32_o.obj\winembed.exe"
-# PROP Bsc_Name ""
-# PROP Target_Dir ""
-
-!ELSEIF  "$(CFG)" == "winembed - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Cmd_Line "NMAKE /f winembed.mak"
-# PROP BASE Rebuild_Opt "/a"
-# PROP BASE Target_File "winembed.exe"
-# PROP BASE Bsc_Name "winembed.bsc"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Cmd_Line "nmake /f makefile.win"
-# PROP Rebuild_Opt "/a"
-# PROP Target_File "win32_d.obj\winembed.exe"
-# PROP Bsc_Name ""
-# PROP Target_Dir ""
-
-!ENDIF 
-
-# Begin Target
-
-# Name "winembed - Win32 Release"
-# Name "winembed - Win32 Debug"
-
-!IF  "$(CFG)" == "winembed - Win32 Release"
-
-!ELSEIF  "$(CFG)" == "winembed - Win32 Debug"
-
-!ENDIF 
-
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\WebBrowserChrome.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\WindowCreator.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\winEmbed.cpp
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\resource.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\WebBrowserChrome.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\WindowCreator.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\winEmbed.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# Begin Source File
-
-SOURCE=.\SMALL.ICO
-# End Source File
-# Begin Source File
-
-SOURCE=.\winEmbed.ICO
-# End Source File
-# Begin Source File
-
-SOURCE=.\winEmbed.rc
-# End Source File
-# End Group
-# End Target
-# End Project
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1634,20 +1634,24 @@ nsEventStatus AsyncPanZoomController::On
   mY.StartTouch(aEvent.mLocalPanStartPoint.y, aEvent.mTime);
 
   if (GetAxisLockMode() == FREE) {
     SetState(PANNING);
     return nsEventStatus_eConsumeNoDefault;
   }
 
   float dx = aEvent.mPanDisplacement.x, dy = aEvent.mPanDisplacement.y;
-  double angle = atan2(dy, dx); // range [-pi, pi]
-  angle = fabs(angle); // range [0, pi]
-
-  HandlePanning(angle);
+
+  if (dx || dy) {
+    double angle = atan2(dy, dx); // range [-pi, pi]
+    angle = fabs(angle); // range [0, pi]
+    HandlePanning(angle);
+  } else {
+    SetState(PANNING);
+  }
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent, ScrollSource aSource, bool aFingersOnTouchpad) {
   APZC_LOG("%p got a pan-pan in state %d\n", this, mState);
 
   if (mState == SMOOTH_SCROLL) {
--- a/gfx/qcms/iccread.c
+++ b/gfx/qcms/iccread.c
@@ -600,22 +600,24 @@ static struct lutmABType *read_tag_lutmA
 
 	lut = malloc(sizeof(struct lutmABType) + (clut_size) * sizeof(float));
 	if (!lut)
 		return NULL;
 	// we'll fill in the rest below
 	memset(lut, 0, sizeof(struct lutmABType));
 	lut->clut_table   = &lut->clut_table_data[0];
 
-	for (i = 0; i < num_in_channels; i++) {
-		lut->num_grid_points[i] = read_u8(src, clut_offset + i);
-		if (lut->num_grid_points[i] == 0) {
-			invalid_source(src, "bad grid_points");
+        if (clut_offset) {
+		for (i = 0; i < num_in_channels; i++) {
+			lut->num_grid_points[i] = read_u8(src, clut_offset + i);
+			if (lut->num_grid_points[i] == 0) {
+				invalid_source(src, "bad grid_points");
+			}
 		}
-	}
+        }
 
 	// Reverse the processing of transformation elements for mBA type.
 	lut->reversed = (type == LUT_MBA_TYPE);
 
 	lut->num_in_channels = num_in_channels;
 	lut->num_out_channels = num_out_channels;
 
 	if (matrix_offset) {
--- a/intl/uconv/nsUCSupport.h
+++ b/intl/uconv/nsUCSupport.h
@@ -145,53 +145,16 @@ public:
       char16_t * aDest, int32_t * aDestLength);
   NS_IMETHOD Reset();
   NS_IMETHOD GetMaxLength(const char *aSrc,
                           int32_t aSrcLength,
                           int32_t* aDestLength);
 };
 
 //----------------------------------------------------------------------
-// Class nsTableDecoderSupport [declaration]
-
-/**
- * Support class for a single-table-driven Unicode decoder.
- * 
- * @created         15/Mar/1999
- * @author  Catalin Rotaru [CATA]
- */
-class nsTableDecoderSupport : public nsBufferDecoderSupport
-{
-public:
-
-  /**
-   * Class constructor.
-   */
-  nsTableDecoderSupport(uScanClassID aScanClass, uShiftInTable * aShiftInTable,
-      uMappingTable * aMappingTable, uint32_t aMaxLengthFactor);
-
-  /**
-   * Class destructor.
-   */
-  virtual ~nsTableDecoderSupport();
-
-protected:
-
-  uScanClassID              mScanClass;
-  uShiftInTable             * mShiftInTable;
-  uMappingTable             * mMappingTable;
-
-  //--------------------------------------------------------------------
-  // Subclassing of nsBufferDecoderSupport class [declaration]
-
-  NS_IMETHOD ConvertNoBuff(const char * aSrc, int32_t * aSrcLength, 
-      char16_t * aDest, int32_t * aDestLength);
-};
-
-//----------------------------------------------------------------------
 // Class nsMultiTableDecoderSupport [declaration]
 
 /**
  * Support class for a multi-table-driven Unicode decoder.
  * 
  * @created         24/Mar/1999
  * @author  Catalin Rotaru [CATA]
  */
--- a/intl/uconv/ucvcn/nsGBKToUnicode.cpp
+++ b/intl/uconv/ucvcn/nsGBKToUnicode.cpp
@@ -7,65 +7,31 @@
  * 
  *
  * @created         07/Sept/1999
  * @author  Yueheng Xu, Yueheng.Xu@intel.com
  */
 
 #include "nsGBKToUnicode.h"
 #include "gbku.h"
-
-//------------------------------------------------------------
-// nsGB18030Unique2BytesToUnicode
-//------------------------------------------------------------
-class nsGB18030Unique2BytesToUnicode : public nsTableDecoderSupport 
-{
-public:
-  nsGB18030Unique2BytesToUnicode();
-  virtual ~nsGB18030Unique2BytesToUnicode() 
-    { }
-protected:
-};
+#include "nsUnicodeDecodeHelper.h"
 
 static const uint16_t g_utGB18030Unique2Bytes[] = {
 #include "gb18030uniq2b.ut"
 };
-nsGB18030Unique2BytesToUnicode::nsGB18030Unique2BytesToUnicode() 
-  : nsTableDecoderSupport(u2BytesCharset, nullptr,
-        (uMappingTable*) &g_utGB18030Unique2Bytes, 1) 
-{
-}
-
-//------------------------------------------------------------
-// nsGB18030Unique4BytesToUnicode
-//------------------------------------------------------------
-class nsGB18030Unique4BytesToUnicode : public nsTableDecoderSupport 
-{
-public:
-  nsGB18030Unique4BytesToUnicode();
-  virtual ~nsGB18030Unique4BytesToUnicode() 
-    { }
-protected:
-};
 
 static const uint16_t g_utGB18030Unique4Bytes[] = {
 #include "gb180304bytes.ut"
 };
-nsGB18030Unique4BytesToUnicode::nsGB18030Unique4BytesToUnicode() 
-  : nsTableDecoderSupport(u4BytesGB18030Charset, nullptr,
-        (uMappingTable*) &g_utGB18030Unique4Bytes, 1) 
-{
-}
-
 
 //----------------------------------------------------------------------
-// Class nsGBKToUnicode [implementation]
+// Class nsGB18030ToUnicode [implementation]
 
 //----------------------------------------------------------------------
-// Subclassing of nsTablesDecoderSupport class [implementation]
+// Subclassing of nsBufferDecoderSupport class [implementation]
 
 #define LEGAL_GBK_MULTIBYTE_FIRST_BYTE(c)  \
       (UINT8_IN_RANGE(0x81, (c), 0xFE))
 #define FIRST_BYTE_IS_SURROGATE(c)  \
       (UINT8_IN_RANGE(0x90, (c), 0xFE))
 #define LEGAL_GBK_2BYTE_SECOND_BYTE(c) \
       (UINT8_IN_RANGE(0x40, (c), 0x7E)|| UINT8_IN_RANGE(0x80, (c), 0xFE))
 #define LEGAL_GBK_4BYTE_SECOND_BYTE(c) \
@@ -202,24 +168,16 @@ NS_IMETHODIMP nsGB18030ToUnicode::Conver
     iDestlen++;
     aDest++;
     *aSrcLength = i+1;
   }
   *aDestLength = iDestlen;
   return rv;
 }
 
-void nsGB18030ToUnicode::CreateExtensionDecoder()
-{
-  mExtensionDecoder = new nsGB18030Unique2BytesToUnicode();
-}
-void nsGB18030ToUnicode::Create4BytesDecoder()
-{
-  m4BytesDecoder = new nsGB18030Unique4BytesToUnicode();
-}
 bool nsGB18030ToUnicode::DecodeToSurrogate(const char* aSrc, char16_t* aOut)
 {
   NS_ASSERTION(FIRST_BYTE_IS_SURROGATE(aSrc[0]),       "illegal first byte");
   NS_ASSERTION(LEGAL_GBK_4BYTE_SECOND_BYTE(aSrc[1]),   "illegal second byte");
   NS_ASSERTION(LEGAL_GBK_4BYTE_THIRD_BYTE(aSrc[2]),    "illegal third byte");
   NS_ASSERTION(LEGAL_GBK_4BYTE_FORTH_BYTE(aSrc[3]),    "illegal forth byte");
   if(! FIRST_BYTE_IS_SURROGATE(aSrc[0]))
     return false;
@@ -245,48 +203,37 @@ bool nsGB18030ToUnicode::DecodeToSurroga
 
   *aOut++ = 0xD800 | (idx >> 10);
   *aOut = 0xDC00 | (0x000003FF & idx);
 
   return true;
 }
 bool nsGB18030ToUnicode::TryExtensionDecoder(const char* aSrc, char16_t* aOut)
 {
-  if(!mExtensionDecoder)
-    CreateExtensionDecoder();
-  NS_ASSERTION(mExtensionDecoder, "cannot creqte 2 bytes unique converter");
-  if(mExtensionDecoder)
-  {
-    nsresult res = mExtensionDecoder->Reset();
-    NS_ASSERTION(NS_SUCCEEDED(res), "2 bytes unique conversoin reset failed");
-    int32_t len = 2;
-    int32_t dstlen = 1;
-    res = mExtensionDecoder->Convert(aSrc,&len, aOut, &dstlen); 
-    NS_ASSERTION(NS_FAILED(res) || ((len==2) && (dstlen == 1)), 
-       "some strange conversion result");
-     // if we failed, we then just use the 0xfffd 
-     // therefore, we ignore the res here. 
-    if(NS_SUCCEEDED(res)) 
-      return true;
-  }
-  return  false;
+  int32_t len = 2;
+  int32_t dstlen = 1;
+  nsresult res =
+    nsUnicodeDecodeHelper::ConvertByTable(aSrc, &len, aOut, &dstlen,
+                                          u2BytesCharset, nullptr,
+                                          (uMappingTable*) &g_utGB18030Unique2Bytes,
+                                          false);
+  NS_ASSERTION(NS_FAILED(res) || ((len==2) && (dstlen == 1)),
+               "some strange conversion result");
+  // if we failed, we then just use the 0xfffd
+  // therefore, we ignore the res here.
+  return NS_SUCCEEDED(res);
 }
 
 bool nsGB18030ToUnicode::Try4BytesDecoder(const char* aSrc, char16_t* aOut)
 {
-  if(!m4BytesDecoder)
-    Create4BytesDecoder();
-  if(m4BytesDecoder)
-  {
-    nsresult res = m4BytesDecoder->Reset();
-    NS_ASSERTION(NS_SUCCEEDED(res), "4 bytes unique conversoin reset failed");
-    int32_t len = 4;
-    int32_t dstlen = 1;
-    res = m4BytesDecoder->Convert(aSrc,&len, aOut, &dstlen); 
-    NS_ASSERTION(NS_FAILED(res) || ((len==4) && (dstlen == 1)), 
-       "some strange conversion result");
-     // if we failed, we then just use the 0xfffd 
-     // therefore, we ignore the res here. 
-    if(NS_SUCCEEDED(res)) 
-      return true;
-  }
-  return  false;
+  int32_t len = 4;
+  int32_t dstlen = 1;
+  nsresult res =
+    nsUnicodeDecodeHelper::ConvertByTable(aSrc, &len, aOut, &dstlen,
+                                          u4BytesGB18030Charset, nullptr,
+                                          (uMappingTable*) &g_utGB18030Unique4Bytes,
+                                          false); 
+  NS_ASSERTION(NS_FAILED(res) || ((len==4) && (dstlen == 1)),
+               "some strange conversion result");
+  // if we failed, we then just use the 0xfffd
+  // therefore, we ignore the res here.
+  return NS_SUCCEEDED(res);
 }
--- a/intl/uconv/ucvcn/nsGBKToUnicode.h
+++ b/intl/uconv/ucvcn/nsGBKToUnicode.h
@@ -24,33 +24,27 @@ class nsGB18030ToUnicode : public nsBuff
 {
 public:
 		  
   /**
    * Class constructor.
    */
   nsGB18030ToUnicode() : nsBufferDecoderSupport(1)
   {
-    mExtensionDecoder = nullptr;
-    m4BytesDecoder = nullptr;
   }
 
 protected:
 
   //--------------------------------------------------------------------
-  // Subclassing of nsDecoderSupport class [declaration]
+  // Subclassing of nsBufferDecoderSupport class [declaration]
   NS_IMETHOD ConvertNoBuff(const char* aSrc, int32_t * aSrcLength, char16_t *aDest, int32_t * aDestLength);
 
 protected:
   nsGBKConvUtil mUtil;
-  nsCOMPtr<nsIUnicodeDecoder> mExtensionDecoder;
-  nsCOMPtr<nsIUnicodeDecoder> m4BytesDecoder;
 
-  void CreateExtensionDecoder();
-  void Create4BytesDecoder();
   bool TryExtensionDecoder(const char* aSrc, char16_t* aDest);
   bool Try4BytesDecoder(const char* aSrc, char16_t* aDest);
   bool DecodeToSurrogate(const char* aSrc, char16_t* aDest);
 
 };
 
 #endif /* nsGBKToUnicode_h___ */
 
--- a/intl/uconv/util/nsUCSupport.cpp
+++ b/intl/uconv/util/nsUCSupport.cpp
@@ -194,49 +194,16 @@ NS_IMETHODIMP nsBufferDecoderSupport::Ge
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   *aDestLength = length.value();
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
-// Class nsTableDecoderSupport [implementation]
-
-nsTableDecoderSupport::nsTableDecoderSupport(uScanClassID aScanClass,
-                                             uShiftInTable* aShiftInTable,
-                                             uMappingTable* aMappingTable,
-                                             uint32_t aMaxLengthFactor)
-: nsBufferDecoderSupport(aMaxLengthFactor)
-{
-  mScanClass = aScanClass;
-  mShiftInTable = aShiftInTable;
-  mMappingTable = aMappingTable;
-}
-
-nsTableDecoderSupport::~nsTableDecoderSupport()
-{
-}
-
-//----------------------------------------------------------------------
-// Subclassing of nsBufferDecoderSupport class [implementation]
-
-NS_IMETHODIMP nsTableDecoderSupport::ConvertNoBuff(const char* aSrc,
-                                                   int32_t* aSrcLength,
-                                                   char16_t* aDest,
-                                                   int32_t* aDestLength)
-{
-  return nsUnicodeDecodeHelper::ConvertByTable(aSrc, aSrcLength,
-                                               aDest, aDestLength,
-                                               mScanClass,
-                                               mShiftInTable, mMappingTable,
-                                               mErrBehavior == kOnError_Signal);
-}
-
-//----------------------------------------------------------------------
 // Class nsMultiTableDecoderSupport [implementation]
 
 nsMultiTableDecoderSupport::nsMultiTableDecoderSupport(
                             int32_t aTableCount,
                             const uRange* aRangeArray,
                             uScanClassID* aScanClassArray,
                             uMappingTable** aMappingTable,
                             uint32_t aMaxLengthFactor)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/baseline/bug1153458.js
@@ -0,0 +1,13 @@
+// |jit-test| baseline-eager; error: TypeError
+try {
+    __defineGetter__("x", Iterator)()
+} catch (e) {}
+f = function() {
+    return (function() {
+        this.x
+    })
+}()
+try {
+    f()
+} catch (e) {}
+f()
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -7661,74 +7661,78 @@ ICGetProp_CallScripted::Compiler::genera
 
 bool
 ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler& masm)
 {
     MOZ_ASSERT(engine_ == Engine::Baseline);
 
     Label failure;
 
-    AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
+    AllocatableGeneralRegisterSet regs(availableGeneralRegs(1));
     Register objReg = InvalidReg;
 
     MOZ_ASSERT(!(inputDefinitelyObject_ && outerClass_));
     if (inputDefinitelyObject_) {
         objReg = R0.scratchReg();
     } else {
-        regs.take(R0);
         // Guard input is an object and unbox.
         masm.branchTestObject(Assembler::NotEqual, R0, &failure);
         objReg = masm.extractObject(R0, ExtractTemp0);
         if (outerClass_) {
             ValueOperand val = regs.takeAnyValue();
             Register tmp = regs.takeAny();
             masm.branchTestObjClass(Assembler::NotEqual, objReg, tmp, outerClass_, &failure);
             masm.loadPtr(Address(objReg, ProxyDataOffset + offsetof(ProxyDataLayout, values)), tmp);
             masm.loadValue(Address(tmp, offsetof(ProxyValueArray, privateSlot)), val);
-            objReg = masm.extractObject(val, ExtractTemp0);
+            masm.movePtr(masm.extractObject(val, ExtractTemp0), objReg);
             regs.add(val);
             regs.add(tmp);
         }
     }
-    regs.takeUnchecked(objReg);
 
     Register scratch = regs.takeAnyExcluding(ICTailCallReg);
 
     // Shape guard.
     GuardReceiverObject(masm, ReceiverGuard(receiver_), objReg, scratch,
                         ICGetProp_CallNative::offsetOfReceiverGuard(), &failure);
 
     if (receiver_ != holder_ ) {
         Register holderReg = regs.takeAny();
         masm.loadPtr(Address(ICStubReg, ICGetProp_CallNative::offsetOfHolder()), holderReg);
         masm.loadPtr(Address(ICStubReg, ICGetProp_CallNative::offsetOfHolderShape()), scratch);
         masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failure);
         regs.add(holderReg);
     }
 
+    // Box and push obj onto baseline frame stack for decompiler
+    if (inputDefinitelyObject_)
+        masm.tagValue(JSVAL_TYPE_OBJECT, objReg, R0);
+    EmitStowICValues(masm, 1);
+    if (inputDefinitelyObject_)
+        objReg = masm.extractObject(R0, ExtractTemp0);
+
     // Push a stub frame so that we can perform a non-tail call.
     enterStubFrame(masm, scratch);
 
     // Load callee function.
     Register callee = regs.takeAny();
     masm.loadPtr(Address(ICStubReg, ICGetProp_CallNative::offsetOfGetter()), callee);
 
     // Push args for vm call.
     masm.push(objReg);
     masm.push(callee);
 
-    if (!inputDefinitelyObject_)
-        regs.add(R0);
-    else
-        regs.add(objReg);
+    regs.add(R0);
 
     if (!callVM(DoCallNativeGetterInfo, masm))
         return false;
     leaveStubFrame(masm);
 
+    EmitUnstowICValues(masm, 1, /* discard = */true);
+
     // Enter type monitor IC to type-check result.
     EmitEnterTypeMonitorIC(masm);
 
     // Failure case - jump to next stub
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
--- a/js/src/jit/JitSpewer.h
+++ b/js/src/jit/JitSpewer.h
@@ -92,16 +92,17 @@ namespace jit {
 enum JitSpewChannel {
 #define JITSPEW_CHANNEL(name) JitSpew_##name,
     JITSPEW_CHANNEL_LIST(JITSPEW_CHANNEL)
 #undef JITSPEW_CHANNEL
     JitSpew_Terminator
 };
 
 class MIRGenerator;
+class TempAllocator;
 
 // 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/none/LIR-none.h
+++ b/js/src/jit/none/LIR-none.h
@@ -41,13 +41,14 @@ class LTableSwitchV : public LInstructio
     const LDefinition* tempPointer() { MOZ_CRASH(); }
 
     static const size_t InputValue = 0;
 };
 
 class LGuardShape : public LInstruction {};
 class LGuardObjectGroup : public LInstruction {};
 class LMulI : public LInstruction {};
+class LRandom : public LInstructionHelper<1, 0, 5> {};
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_none_LIR_none_h */
--- a/js/src/jit/none/Lowering-none.h
+++ b/js/src/jit/none/Lowering-none.h
@@ -80,17 +80,17 @@ class LIRGeneratorNone : public LIRGener
 
     LTableSwitch* newLTableSwitch(LAllocation, LDefinition, MTableSwitch*) { MOZ_CRASH(); }
     LTableSwitchV* newLTableSwitchV(MTableSwitch*) { MOZ_CRASH(); }
     void visitSimdSelect(MSimdSelect* ins) { MOZ_CRASH(); }
     void visitSimdSplatX4(MSimdSplatX4* ins) { MOZ_CRASH(); }
     void visitSimdValueX4(MSimdValueX4* lir) { MOZ_CRASH(); }
     void visitSubstr(MSubstr*) { MOZ_CRASH(); }
     void visitSimdBinaryArith(js::jit::MSimdBinaryArith*) { MOZ_CRASH(); }
-
+    void visitRandom(MRandom* ) { MOZ_CRASH(); }
 
 };
 
 typedef LIRGeneratorNone LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -138,16 +138,21 @@ class Assembler : public AssemblerShared
         MOZ_CRASH();
     }
 };
 
 class Operand
 {
   public:
     Operand (const Address&) { MOZ_CRASH();}
+    Operand (const Register) { MOZ_CRASH();}
+    Operand (const FloatRegister) { MOZ_CRASH();}
+    Operand (Register, Imm32 ) { MOZ_CRASH(); }
+    Operand (Register, int32_t ) { MOZ_CRASH(); }
+
 
 };
 
 class MacroAssemblerNone : public Assembler
 {
   public:
     MacroAssemblerNone() { MOZ_CRASH(); }
 
--- a/js/src/tests/lib/jittests.py
+++ b/js/src/tests/lib/jittests.py
@@ -210,16 +210,18 @@ class Test:
                         if options.can_test_also_noasmjs:
                             test.test_also.append(['--no-asmjs'])
                     elif name.startswith('test-also='):
                         test.test_also.append([name[len('test-also='):]])
                     elif name.startswith('test-join='):
                         test.test_join.append([name[len('test-join='):]])
                     elif name == 'ion-eager':
                         test.jitflags.append('--ion-eager')
+                    elif name == 'baseline-eager':
+                        test.jitflags.append('--baseline-eager')
                     elif name == 'dump-bytecode':
                         test.jitflags.append('--dump-bytecode')
                     elif name.startswith('--'):
                         # // |jit-test| --ion-gvn=off; --no-sse4
                         test.jitflags.append(name)
                     else:
                         print('{}: warning: unrecognized |jit-test| attribute'
                               ' {}'.format(path, part))
--- a/js/xpconnect/idl/nsIScriptError.idl
+++ b/js/xpconnect/idl/nsIScriptError.idl
@@ -7,17 +7,17 @@
  * nsIConsoleMessage subclass for representing JavaScript errors and warnings.
  */
 
 
 #include "nsISupports.idl"
 #include "nsIConsoleMessage.idl"
 
 %{C++
-#include "nsString.h" // for nsDependentCString
+#include "nsStringGlue.h" // for nsDependentCString
 %}
 
 [scriptable, uuid(248b2c94-2736-4d29-bfdf-bc64a2e60d35)]
 interface nsIScriptError : nsIConsoleMessage
 {
     /** pseudo-flag for default case */
     const unsigned long errorFlag = 0x0;
 
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -72,17 +72,17 @@ EXPORTS += [
     'nsDisplayList.h',
     'nsDisplayListInvalidation.h',
     'nsFrameManager.h',
     'nsFrameManagerBase.h',
     'nsFrameTraversal.h',
     'nsIFrameTraversal.h',
     'nsILayoutDebugger.h',
     'nsILayoutHistoryState.h',
-    'nsIPercentHeightObserver.h',
+    'nsIPercentBSizeObserver.h',
     'nsIPresShell.h',
     'nsIReflowCallback.h',
     'nsLayoutUtils.h',
     'nsPresArena.h',
     'nsPresContext.h',
     'nsPresState.h',
     'nsRefreshDriver.h',
     'nsStyleChangeList.h',
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -729,41 +729,54 @@ nsBidiPresUtils::ResolveParagraph(nsBloc
          (void*)aBlockFrame, NS_ConvertUTF16toUTF8(aBpd->mBuffer).get(), frameCount, runCount);
 #ifdef REALLY_NOISY_BIDI
   printf(" block frame tree=:\n");
   aBlockFrame->List(stdout, 0);
 #endif
 #endif
 #endif
 
-  if (runCount == 1 && frameCount == 1 &&
+  bool isNonBidi = false;
+
+  nsIFrame* frame0 = frameCount > 0 ? aBpd->FrameAt(0) : nullptr;
+  nsIFrame* frame1 = frameCount > 1 ? aBpd->FrameAt(1) : nullptr;
+
+  // Non-bidi frames
+  if (runCount == 1 && (frameCount == 1 || frameCount == 2) &&
       aBpd->mParagraphDepth == 0 && aBpd->GetDirection() == NSBIDI_LTR &&
-      aBpd->GetParaLevel() == 0) {
-    // We have a single left-to-right frame in a left-to-right paragraph,
+      aBpd->GetParaLevel() == 0 &&
+      frame0 != NS_BIDI_CONTROL_FRAME &&
+      !frame0->Properties().Get(nsIFrame::EmbeddingLevelProperty()) &&
+      !frame0->Properties().Get(nsIFrame::BaseLevelProperty())) {
+    // We have a left-to-right frame in a left-to-right paragraph,
     // without bidi isolation from the surrounding text.
-    // Make sure that the embedding level and base level frame properties aren't
+    // The embedding level and base level frame properties aren't
     // set (because if they are this frame used to have some other direction,
-    // so we can't do this optimization), and we're done.
-    nsIFrame* frame = aBpd->FrameAt(0);
-    if (frame != NS_BIDI_CONTROL_FRAME &&
-        !frame->Properties().Get(nsIFrame::EmbeddingLevelProperty()) &&
-        !frame->Properties().Get(nsIFrame::BaseLevelProperty())) {
+    // so we can't do this optimization)
+    // As long as this is the only frame, or it's followed by a linebreak,
+    // this is a non-bidi paragraph.
+    if (!frame1 || (frame1 != NS_BIDI_CONTROL_FRAME &&
+                    frame1->GetType() == nsGkAtoms::brFrame)) {
+      isNonBidi = true;
+    }
+  }
+
+  if (isNonBidi) {
 #ifdef DEBUG
 #ifdef NOISY_BIDI
-      printf("early return for single direction frame %p\n", (void*)frame);
+    printf("early return for single direction frame %p\n", (void*)frame);
 #endif
 #endif
-      frame->AddStateBits(NS_FRAME_IS_BIDI);
-      return NS_OK;
-    }
+    return NS_OK;
   }
 
   nsIFrame* firstFrame = nullptr;
   nsIFrame* lastFrame = nullptr;
 
+  // Bidi frames
   for (; ;) {
     if (fragmentLength <= 0) {
       // Get the next frame from mLogicalFrames
       if (++frameIndex >= frameCount) {
         break;
       }
       frame = aBpd->FrameAt(frameIndex);
       if (frame == NS_BIDI_CONTROL_FRAME ||
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -110,19 +110,24 @@ AdjustCaretFrameForLineEnd(nsIFrame** aF
       NS_ASSERTION(r->GetType() == nsGkAtoms::textFrame, "Expected text frame");
       *aOffset = (static_cast<nsTextFrame*>(r))->GetContentEnd();
       return;
     }
   }
 }
 
 static bool
-IsBidiUI()
+IsKeyboardRTL()
 {
-  return Preferences::GetBool("bidi.browser.ui");
+  bool isKeyboardRTL = false;
+  nsIBidiKeyboard* bidiKeyboard = nsContentUtils::GetBidiKeyboard();
+  if (bidiKeyboard) {
+    bidiKeyboard->IsLangRTL(&isKeyboardRTL);
+  }
+  return isKeyboardRTL;
 }
 
 nsCaret::nsCaret()
 : mOverrideOffset(0)
 , mIsBlinkOn(false)
 , mBlinkCount(-1)
 , mVisible(false)
 , mReadOnly(false)
@@ -473,28 +478,40 @@ nsCaret::SetCaretPosition(nsIDOMNode* aN
 {
   mOverrideContent = do_QueryInterface(aNode);
   mOverrideOffset = aOffset;
 
   ResetBlinking();
   SchedulePaint();
 }
 
+bool
+nsCaret::IsBidiUI()
+{
+  nsIFrame* frame = nullptr;
+
+  if(Selection* selection = GetSelectionInternal()) {
+    int32_t contentOffset;
+    frame = GetFrameAndOffset(selection, mOverrideContent, mOverrideOffset,
+                              &contentOffset);
+  }
+
+  return (frame && frame->GetStateBits() & NS_FRAME_IS_BIDI) ||
+         Preferences::GetBool("bidi.browser.ui");
+}
+
 void
 nsCaret::CheckSelectionLanguageChange()
 {
   if (!IsBidiUI()) {
     return;
   }
 
-  bool isKeyboardRTL = false;
-  nsIBidiKeyboard* bidiKeyboard = nsContentUtils::GetBidiKeyboard();
-  if (bidiKeyboard) {
-    bidiKeyboard->IsLangRTL(&isKeyboardRTL);
-  }
+  bool isKeyboardRTL = IsKeyboardRTL();
+
   // Call SelectionLanguageChange on every paint. Mostly it will be a noop
   // but it should be fast anyway. This guarantees we never paint the caret
   // at the wrong place.
   Selection* selection = GetSelectionInternal();
   if (selection) {
     selection->SelectionLanguageChange(isKeyboardRTL);
   }
 }
@@ -673,18 +690,19 @@ nsCaret::GetCaretFrameForNodeOffset(nsFr
   //
   // Direction Style from visibility->mDirection
   // ------------------
   // NS_STYLE_DIRECTION_LTR : LTR or Default
   // NS_STYLE_DIRECTION_RTL
   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)
+    if (aBidiLevel & BIDI_LEVEL_UNDEFINED) {
       aBidiLevel = NS_GET_EMBEDDING_LEVEL(theFrame);
+    }
 
     int32_t start;
     int32_t end;
     nsIFrame* frameBefore;
     nsIFrame* frameAfter;
     nsBidiLevel levelBefore; // Bidi level of the character before the caret
     nsBidiLevel levelAfter;  // Bidi level of the character after the caret
 
@@ -897,31 +915,32 @@ nsCaret::ComputeCaretRects(nsIFrame* aFr
   if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
     if (isVertical) {
       aCaretRect->y -= aCaretRect->height;
     } else {
       aCaretRect->x -= aCaretRect->width;
     }
   }
 
-  // Simon -- make a hook to draw to the left or right of the caret to show keyboard language direction
   aHookRect->SetEmpty();
-  if (!IsBidiUI()) {
+
+  Selection* selection = GetSelectionInternal();
+  if (!selection || !selection->GetFrameSelection()) {
     return;
   }
 
-  bool isCaretRTL;
-  nsIBidiKeyboard* bidiKeyboard = nsContentUtils::GetBidiKeyboard();
-  // if bidiKeyboard->IsLangRTL() fails, there is no way to tell the
-  // keyboard direction, or the user has no right-to-left keyboard
-  // installed, so we never draw the hook.
-  if (bidiKeyboard && NS_SUCCEEDED(bidiKeyboard->IsLangRTL(&isCaretRTL))) {
-    // If keyboard language is RTL, draw the hook on the left; if LTR, to the right
+  if (IsBidiUI() || IsKeyboardRTL()) {
+    // If caret level is RTL, draw the hook on the left; if LTR, to the right
     // The height of the hook rectangle is the same as the width of the caret
     // rectangle.
+    int caretBidiLevel = selection->GetFrameSelection()->GetCaretBidiLevel();
+    if (caretBidiLevel & BIDI_LEVEL_UNDEFINED) {
+      caretBidiLevel = NS_GET_EMBEDDING_LEVEL(aFrame);
+    }
+    bool isCaretRTL = caretBidiLevel % 2;
     if (isVertical) {
       aHookRect->SetRect(aCaretRect->XMost() - bidiIndicatorSize,
                          aCaretRect->y + (isCaretRTL ? bidiIndicatorSize * -1 :
                                                        aCaretRect->height),
                          aCaretRect->height,
                          bidiIndicatorSize);
     } else {
       aHookRect->SetRect(aCaretRect->x + (isCaretRTL ? bidiIndicatorSize * -1 :
--- a/layout/base/nsCaret.h
+++ b/layout/base/nsCaret.h
@@ -153,16 +153,17 @@ class nsCaret final : public nsISelectio
                                       int32_t   aFrameOffset,
                                       nscoord*  aBidiIndicatorSize);
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
 protected:
     static void   CaretBlinkCallback(nsITimer *aTimer, void *aClosure);
 
+    bool          IsBidiUI();
     void          CheckSelectionLanguageChange();
 
     void          ResetBlinking();
     void          StopBlinking();
 
     mozilla::dom::Selection* GetSelectionInternal();
 
     struct Metrics {
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -65,16 +65,17 @@
 #include "UnitTransforms.h"
 #include "LayersLogging.h"
 #include "FrameLayerBuilder.h"
 #include "mozilla/EventStateManager.h"
 #include "RestyleManager.h"
 #include "nsCaret.h"
 #include "nsISelection.h"
 #include "nsDOMTokenList.h"
+#include "mozilla/RuleNodeCacheConditions.h"
 
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount().
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 
 using namespace mozilla;
@@ -124,17 +125,17 @@ static void AddTransformFunctions(nsCSSV
     return;
   }
 
   for (const nsCSSValueList* curr = aList; curr; curr = curr->mNext) {
     const nsCSSValue& currElem = curr->mValue;
     NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
                  "Stream should consist solely of functions!");
     nsCSSValue::Array* array = currElem.GetArrayValue();
-    bool canStoreInRuleTree = true;
+    RuleNodeCacheConditions conditions;
     switch (nsStyleTransformMatrix::TransformFunctionOf(array)) {
       case eCSSKeyword_rotatex:
       {
         CSSAngle theta = MakeCSSAngle(array->Item(1));
         aFunctions.AppendElement(RotationX(theta));
         break;
       }
       case eCSSKeyword_rotatey:
@@ -196,62 +197,62 @@ static void AddTransformFunctions(nsCSSV
         double y = array->Item(2).GetFloatValue();
         double z = array->Item(3).GetFloatValue();
         aFunctions.AppendElement(Scale(x, y, z));
         break;
       }
       case eCSSKeyword_translatex:
       {
         double x = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(1), aContext, aPresContext, canStoreInRuleTree,
+          array->Item(1), aContext, aPresContext, conditions,
           &aRefBox, &TransformReferenceBox::Width);
         aFunctions.AppendElement(Translation(x, 0, 0));
         break;
       }
       case eCSSKeyword_translatey:
       {
         double y = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(1), aContext, aPresContext, canStoreInRuleTree,
+          array->Item(1), aContext, aPresContext, conditions,
           &aRefBox, &TransformReferenceBox::Height);
         aFunctions.AppendElement(Translation(0, y, 0));
         break;
       }
       case eCSSKeyword_translatez:
       {
         double z = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(1), aContext, aPresContext, canStoreInRuleTree,
+          array->Item(1), aContext, aPresContext, conditions,
           nullptr);
         aFunctions.AppendElement(Translation(0, 0, z));
         break;
       }
       case eCSSKeyword_translate:
       {
         double x = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(1), aContext, aPresContext, canStoreInRuleTree,
+          array->Item(1), aContext, aPresContext, conditions,
           &aRefBox, &TransformReferenceBox::Width);
         // translate(x) is shorthand for translate(x, 0)
         double y = 0;
         if (array->Count() == 3) {
            y = nsStyleTransformMatrix::ProcessTranslatePart(
-            array->Item(2), aContext, aPresContext, canStoreInRuleTree,
+            array->Item(2), aContext, aPresContext, conditions,
             &aRefBox, &TransformReferenceBox::Height);
         }
         aFunctions.AppendElement(Translation(x, y, 0));
         break;
       }
       case eCSSKeyword_translate3d:
       {
         double x = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(1), aContext, aPresContext, canStoreInRuleTree,
+          array->Item(1), aContext, aPresContext, conditions,
           &aRefBox, &TransformReferenceBox::Width);
         double y = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(2), aContext, aPresContext, canStoreInRuleTree,
+          array->Item(2), aContext, aPresContext, conditions,
           &aRefBox, &TransformReferenceBox::Height);
         double z = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(3), aContext, aPresContext, canStoreInRuleTree,
+          array->Item(3), aContext, aPresContext, conditions,
           nullptr);
 
         aFunctions.AppendElement(Translation(x, y, z));
         break;
       }
       case eCSSKeyword_skewx:
       {
         CSSAngle x = MakeCSSAngle(array->Item(1));
@@ -320,17 +321,17 @@ static void AddTransformFunctions(nsCSSV
         break;
       }
       case eCSSKeyword_interpolatematrix:
       {
         gfx3DMatrix matrix;
         nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix, array,
                                                          aContext,
                                                          aPresContext,
-                                                         canStoreInRuleTree,
+                                                         conditions,
                                                          aRefBox);
         aFunctions.AppendElement(TransformMatrix(gfx::ToMatrix4x4(matrix)));
         break;
       }
       case eCSSKeyword_perspective:
       {
         aFunctions.AppendElement(Perspective(array->Item(1).GetFloatValue()));
         break;
@@ -4904,17 +4905,17 @@ nsDisplayTransform::GetResultingTransfor
   if (aBoundsOverride &&
       (!frame || !(frame->GetStateBits() & NS_FRAME_SVG_LAYOUT))) {
     refBox.Init(aBoundsOverride->Size());
   } else {
     refBox.Init(frame);
   }
 
   /* Get the matrix, then change its basis to factor in the origin. */
-  bool dummy;
+  RuleNodeCacheConditions dummy;
   gfx3DMatrix result;
   // Call IsSVGTransformed() regardless of the value of
   // disp->mSpecifiedTransform, since we still need any transformFromSVGParent.
   Matrix svgTransform, transformFromSVGParent;
   bool hasSVGTransforms =
     frame && frame->IsSVGTransformed(&svgTransform, &transformFromSVGParent);
   bool hasTransformFromSVGParent =
     hasSVGTransforms && !transformFromSVGParent.IsIdentity();
rename from layout/base/nsIPercentHeightObserver.h
rename to layout/base/nsIPercentBSizeObserver.h
--- a/layout/base/nsIPercentHeightObserver.h
+++ b/layout/base/nsIPercentBSizeObserver.h
@@ -1,30 +1,31 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsIPercentHeightObserver_h___
-#define nsIPercentHeightObserver_h___
+#ifndef nsIPercentBSizeObserver_h___
+#define nsIPercentBSizeObserver_h___
 
 #include "nsQueryFrame.h"
 
 struct nsHTMLReflowState;
 
 /**
- * This interface is supported by frames that need to provide computed height
- * values to children during reflow which would otherwise not happen. Currently only
- * table cells support this.
+ * This interface is supported by frames that need to provide computed bsize
+ * values to children during reflow which would otherwise not happen. Currently
+ * only table cells support this.
  */
-class nsIPercentHeightObserver
+class nsIPercentBSizeObserver
 {
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsIPercentHeightObserver)
+  NS_DECL_QUERYFRAME_TARGET(nsIPercentBSizeObserver)
 
-  // Notify the observer that aReflowState has no computed height, but it has a percent height
-  virtual void NotifyPercentHeight(const nsHTMLReflowState& aReflowState) = 0;
+  // Notify the observer that aReflowState has no computed bsize,
+  // but it has a percent bsize
+  virtual void NotifyPercentBSize(const nsHTMLReflowState& aReflowState) = 0;
 
   // Ask the observer if it should observe aReflowState.frame
   virtual bool NeedsToObserve(const nsHTMLReflowState& aReflowState) = 0;
 };
 
-#endif // nsIPercentHeightObserver_h___ 
+#endif // nsIPercentBSizeObserver_h___ 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -94,16 +94,17 @@
 #include "LayersLogging.h"
 #include "mozilla/Preferences.h"
 #include "nsFrameSelection.h"
 #include "FrameLayerBuilder.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
+#include "mozilla/RuleNodeCacheConditions.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 
 #include "GeckoProfiler.h"
 #include "nsAnimationManager.h"
 #include "nsTransitionManager.h"
@@ -459,17 +460,17 @@ GetScaleForValue(const StyleAnimationVal
   nsCSSValueSharedList* list = aValue.GetCSSValueSharedListValue();
   MOZ_ASSERT(list->mHead);
 
   if (list->mHead->mValue.GetUnit() == eCSSUnit_None) {
     // There is an animation, but no actual transform yet.
     return gfxSize();
   }
 
-  bool dontCare;
+  RuleNodeCacheConditions dontCare;
   TransformReferenceBox refBox(aFrame);
   gfx3DMatrix transform = nsStyleTransformMatrix::ReadTransforms(
                             list->mHead,
                             aFrame->StyleContext(),
                             aFrame->PresContext(), dontCare, refBox,
                             aFrame->PresContext()->AppUnitsPerDevPixel());
 
   gfxMatrix transform2d;
--- a/layout/base/nsPresArena.h
+++ b/layout/base/nsPresArena.h
@@ -27,16 +27,18 @@ public:
   ~nsPresArena();
 
   enum ObjectID {
     nsLineBox_id = nsQueryFrame::NON_FRAME_MARKER,
     nsRuleNode_id,
     nsStyleContext_id,
     nsInheritedStyleData_id,
     nsResetStyleData_id,
+    nsConditionalResetStyleData_id,
+    nsConditionalResetStyleDataEntry_id,
     nsFrameList_id,
 
     CustomCounterStyle_id,
     DependentBuiltinCounterStyle_id,
 
     First_nsStyleStruct_id,
     DummyBeforeStyleStructs_id = First_nsStyleStruct_id - 1,
 
--- a/layout/base/tests/bug646382-1-ref.html
+++ b/layout/base/tests/bug646382-1-ref.html
@@ -1,17 +1,18 @@
 <html class="reftest-wait">
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   </head>
   <body onload="start()">
-    <textarea onfocus="done()" style="-moz-appearance: none">س</textarea>
+    <textarea onfocus="done()" style="-moz-appearance: none">س&lrm;</textarea>
     <script>
       var textarea = document.querySelector("textarea");
       function start() {
         textarea.focus();
       }
       function done() {
+        textarea.selectionStart = textarea.selectionEnd = 2;
         document.documentElement.removeAttribute("class");
       }
     </script>
   </body>
 </html>
--- a/layout/base/tests/bug646382-2-ref.html
+++ b/layout/base/tests/bug646382-2-ref.html
@@ -1,14 +1,15 @@
 <html class="reftest-wait">
   <body onload="start()">
-    <textarea dir="rtl" onfocus="done()" style="-moz-appearance: none">s</textarea>
+    <textarea dir="rtl" onfocus="done()" style="-moz-appearance: none">s&rlm;</textarea>
     <script>
       var textarea = document.querySelector("textarea");
       function start() {
         textarea.focus();
       }
       function done() {
+        textarea.selectionStart = textarea.selectionEnd = 2;
         document.documentElement.removeAttribute("class");
       }
     </script>
   </body>
 </html>
--- a/layout/generic/WritingModes.h
+++ b/layout/generic/WritingModes.h
@@ -467,16 +467,18 @@ public:
   /**
    * Check whether two modes are orthogonal to each other.
    */
   bool IsOrthogonalTo(const WritingMode& aOther) const
   {
     return IsVertical() != aOther.IsVertical();
   }
 
+  uint8_t GetBits() const { return mWritingMode; }
+
 private:
   friend class LogicalPoint;
   friend class LogicalSize;
   friend class LogicalMargin;
   friend class LogicalRect;
 
   friend struct IPC::ParamTraits<WritingMode>;
   // IMENotification cannot store this class directly since this has some
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -48,17 +48,17 @@
 #include "nsGkAtoms.h"
 #include "nsHtml5Atoms.h"
 #include "nsCSSAnonBoxes.h"
 
 #include "nsFrameTraversal.h"
 #include "nsRange.h"
 #include "nsITextControlFrame.h"
 #include "nsNameSpaceManager.h"
-#include "nsIPercentHeightObserver.h"
+#include "nsIPercentBSizeObserver.h"
 #include "nsStyleStructInlines.h"
 #include "FrameLayerBuilder.h"
 
 #include "nsBidiPresUtils.h"
 #include "RubyUtils.h"
 
 // For triple-click pref
 #include "imgIContainer.h"
@@ -4444,25 +4444,26 @@ nsFrame::DidReflow(nsPresContext*       
 
   nsSVGEffects::InvalidateDirectRenderingObservers(this, nsSVGEffects::INVALIDATE_REFLOW);
 
   if (nsDidReflowStatus::FINISHED == aStatus) {
     mState &= ~(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
                 NS_FRAME_HAS_DIRTY_CHILDREN);
   }
 
-  // Notify the percent height observer if there is a percent height.
+  // Notify the percent bsize observer if there is a percent bsize.
   // The observer may be able to initiate another reflow with a computed
-  // height. This happens in the case where a table cell has no computed
-  // height but can fabricate one when the cell height is known.
-  if (aReflowState && aReflowState->mPercentHeightObserver &&
+  // bsize. This happens in the case where a table cell has no computed
+  // bsize but can fabricate one when the cell bsize is known.
+  if (aReflowState && aReflowState->mPercentBSizeObserver &&
       !GetPrevInFlow()) {
-    const nsStyleCoord &height = aReflowState->mStylePosition->mHeight;
-    if (height.HasPercent()) {
-      aReflowState->mPercentHeightObserver->NotifyPercentHeight(*aReflowState);
+    const nsStyleCoord &bsize =
+      aReflowState->mStylePosition->BSize(aReflowState->GetWritingMode());
+    if (bsize.HasPercent()) {
+      aReflowState->mPercentBSizeObserver->NotifyPercentBSize(*aReflowState);
     }
   }
 
   aPresContext->ReflowedFrame();
 }
 
 void
 nsFrame::FinishReflowWithAbsoluteFrames(nsPresContext*           aPresContext,
@@ -9737,18 +9738,18 @@ static void DisplayReflowEnterPrint(nsPr
     printf("c=%s,%s ", width, height);
 
     if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY)
       printf("dirty ");
 
     if (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)
       printf("dirty-children ");
 
-    if (aReflowState.mFlags.mSpecialHeightReflow)
-      printf("special-height ");
+    if (aReflowState.mFlags.mSpecialBSizeReflow)
+      printf("special-bsize ");
 
     if (aReflowState.IsHResize())
       printf("h-resize ");
 
     if (aReflowState.IsVResize())
       printf("v-resize ");
 
     nsIFrame* inFlow = aFrame->GetPrevInFlow();
--- a/layout/generic/nsFrameIdList.h
+++ b/layout/generic/nsFrameIdList.h
@@ -44,17 +44,17 @@ FRAME_ID(nsIComboboxControlFrame)
 FRAME_ID(nsIFormControlFrame)
 FRAME_ID(nsIFrame)
 FRAME_ID(nsIFrameFrame)
 FRAME_ID(nsIListControlFrame)
 FRAME_ID(nsIMathMLFrame)
 FRAME_ID(nsIMenuFrame)
 FRAME_ID(nsIObjectFrame)
 FRAME_ID(nsIPageSequenceFrame)
-FRAME_ID(nsIPercentHeightObserver)
+FRAME_ID(nsIPercentBSizeObserver)
 FRAME_ID(nsIRootBox)
 FRAME_ID(nsISVGChildFrame)
 FRAME_ID(nsISVGSVGFrame)
 FRAME_ID(nsIScrollableFrame)
 FRAME_ID(nsIScrollbarMediator)
 FRAME_ID(nsISelectControlFrame)
 FRAME_ID(nsIStatefulFrame)
 FRAME_ID(nsITableCellLayout)
--- a/layout/generic/nsFrameSelection.h
+++ b/layout/generic/nsFrameSelection.h
@@ -616,17 +616,19 @@ private:
                      bool aContinueSelection,
                      bool aMultipleSelection);
 
   void BidiLevelFromMove(nsIPresShell* aPresShell,
                          nsIContent *aNode,
                          uint32_t aContentOffset,
                          nsSelectionAmount aAmount,
                          CaretAssociateHint aHint);
-  void BidiLevelFromClick(nsIContent *aNewFocus, uint32_t aContentOffset);
+  void BidiLevelFromClick(nsIContent *aNewFocus,
+                          uint32_t aContentOffset,
+                          CaretAssociateHint aHint);
   nsPrevNextBidiLevels GetPrevNextBidiLevels(nsIContent *aNode,
                                              uint32_t aContentOffset,
                                              CaretAssociateHint aHint,
                                              bool aJumpLines) const;
 
   bool AdjustForMaintainedSelection(nsIContent *aContent, int32_t aOffset);
 
 // post and pop reasons for notifications. we may stack these later
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -545,17 +545,17 @@ FRAME_STATE_BIT(Placeholder, 21, PLACEHO
 FRAME_STATE_BIT(Placeholder, 22, PLACEHOLDER_FOR_FIXEDPOS)
 FRAME_STATE_BIT(Placeholder, 23, PLACEHOLDER_FOR_POPUP)
 
 
 // == Frame state bits that apply to table cell frames ========================
 
 FRAME_STATE_GROUP(TableCell, nsTableCellFrame)
 
-FRAME_STATE_BIT(TableCell, 28, NS_TABLE_CELL_HAS_PCT_OVER_HEIGHT)
+FRAME_STATE_BIT(TableCell, 28, NS_TABLE_CELL_HAS_PCT_OVER_BSIZE)
 FRAME_STATE_BIT(TableCell, 29, NS_TABLE_CELL_HAD_SPECIAL_REFLOW)
 FRAME_STATE_BIT(TableCell, 31, NS_TABLE_CELL_CONTENT_EMPTY)
 
 
 // == Frame state bits that apply to table column frames ======================
 
 // Bits 28-31 on nsTableColFrames are used to store the column type.
 
@@ -574,28 +574,28 @@ FRAME_STATE_GROUP(TableRowAndRowGroup, n
 FRAME_STATE_BIT(TableRowAndRowGroup, 28, NS_REPEATED_ROW_OR_ROWGROUP)
 
 
 // == Frame state bits that apply to table row frames =========================
 
 FRAME_STATE_GROUP(TableRow, nsTableRowFrame)
 
 // Indicates whether this row has any cells that have
-// non-auto-height and rowspan=1
-FRAME_STATE_BIT(TableRow, 29, NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT)
+// non-auto-bsize and rowspan=1
+FRAME_STATE_BIT(TableRow, 29, NS_ROW_HAS_CELL_WITH_STYLE_BSIZE)
 
-FRAME_STATE_BIT(TableRow, 30, NS_TABLE_ROW_HAS_UNPAGINATED_HEIGHT)
+FRAME_STATE_BIT(TableRow, 30, NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE)
 
 
 // == Frame state bits that apply to table row group frames ===================
 
 FRAME_STATE_GROUP(TableRowGroup, nsTableRowGroupFrame)
 
 FRAME_STATE_BIT(TableRowGroup, 27, NS_ROWGROUP_HAS_ROW_CURSOR)
-FRAME_STATE_BIT(TableRowGroup, 30, NS_ROWGROUP_HAS_STYLE_HEIGHT)
+FRAME_STATE_BIT(TableRowGroup, 30, NS_ROWGROUP_HAS_STYLE_BSIZE)
 
 // thead or tfoot should be repeated on every printed page
 FRAME_STATE_BIT(TableRowGroup, 31, NS_ROWGROUP_REPEATABLE)
 
 FRAME_STATE_GROUP(Table, nsTableFrame)
 
 FRAME_STATE_BIT(Table, 28, NS_TABLE_PART_HAS_FIXED_BACKGROUND)
 
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -17,17 +17,17 @@
 #include "nsIPresShell.h"
 #include "nsFontMetrics.h"
 #include "nsBlockFrame.h"
 #include "nsLineBox.h"
 #include "nsFlexContainerFrame.h"
 #include "nsImageFrame.h"
 #include "nsTableFrame.h"
 #include "nsTableCellFrame.h"
-#include "nsIPercentHeightObserver.h"
+#include "nsIPercentBSizeObserver.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsFontInflationData.h"
 #include "StickyScrollContainer.h"
 #include "nsIFrameInlines.h"
 #include "CounterStyleManager.h"
 #include <algorithm>
 #include "mozilla/dom/HTMLInputElement.h"
@@ -70,17 +70,17 @@ nsHTMLReflowState::nsHTMLReflowState(nsP
   MOZ_ASSERT(aPresContext == aFrame->PresContext(), "wrong pres context");
   parentReflowState = nullptr;
   AvailableISize() = aAvailableSpace.ISize(mWritingMode);
   AvailableBSize() = aAvailableSpace.BSize(mWritingMode);
   mFloatManager = nullptr;
   mLineLayout = nullptr;
   memset(&mFlags, 0, sizeof(mFlags));
   mDiscoveredClearance = nullptr;
-  mPercentHeightObserver = nullptr;
+  mPercentBSizeObserver = nullptr;
 
   if (aFlags & DUMMY_PARENT_REFLOW_STATE) {
     mFlags.mDummyParentReflowState = true;
   }
 
   if (!(aFlags & CALLER_WILL_INIT)) {
     Init(aPresContext);
   }
@@ -174,26 +174,26 @@ nsHTMLReflowState::nsHTMLReflowState(
   , mBlockDelta(0)
   , mOrthogonalLimit(NS_UNCONSTRAINEDSIZE)
   , mReflowDepth(aParentReflowState.mReflowDepth + 1)
   , mFlags(aParentReflowState.mFlags)
 {
   MOZ_ASSERT(aPresContext, "no pres context");
   MOZ_ASSERT(aFrame, "no frame");
   MOZ_ASSERT(aPresContext == aFrame->PresContext(), "wrong pres context");
-  NS_PRECONDITION(!mFlags.mSpecialHeightReflow ||
+  NS_PRECONDITION(!mFlags.mSpecialBSizeReflow ||
                   !NS_SUBTREE_DIRTY(aFrame),
-                  "frame should be clean when getting special height reflow");
+                  "frame should be clean when getting special bsize reflow");
 
   parentReflowState = &aParentReflowState;
 
   // If the parent is dirty, then the child is as well.
   // XXX Are the other cases where the parent reflows a child a second
   // time, as a resize?
-  if (!mFlags.mSpecialHeightReflow)
+  if (!mFlags.mSpecialBSizeReflow)
     frame->AddStateBits(parentReflowState->frame->GetStateBits() &
                         NS_FRAME_IS_DIRTY);
 
   AvailableISize() = aAvailableSpace.ISize(mWritingMode);
   AvailableBSize() = aAvailableSpace.BSize(mWritingMode);
 
   if (mWritingMode.IsOrthogonalTo(aParentReflowState.GetWritingMode())) {
     // If we're setting up for an orthogonal flow, and the parent reflow state
@@ -218,19 +218,19 @@ nsHTMLReflowState::nsHTMLReflowState(
     CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
   mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = false;
   mFlags.mHasClearance = false;
   mFlags.mIsColumnBalancing = false;
   mFlags.mIsFlexContainerMeasuringHeight = false;
   mFlags.mDummyParentReflowState = false;
 
   mDiscoveredClearance = nullptr;
-  mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
-                            aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))
-                           ? aParentReflowState.mPercentHeightObserver : nullptr;
+  mPercentBSizeObserver = (aParentReflowState.mPercentBSizeObserver &&
+                            aParentReflowState.mPercentBSizeObserver->NeedsToObserve(*this))
+                           ? aParentReflowState.mPercentBSizeObserver : nullptr;
 
   if ((aFlags & DUMMY_PARENT_REFLOW_STATE) ||
       (parentReflowState->mFlags.mDummyParentReflowState &&
        frame->GetType() == nsGkAtoms::tableFrame)) {
     mFlags.mDummyParentReflowState = true;
   }
 
   if (!(aFlags & CALLER_WILL_INIT)) {
@@ -608,17 +608,17 @@ nsHTMLReflowState::InitResizeFlags(nsPre
   }
 
   SetIResize(!(frame->GetStateBits() & NS_FRAME_IS_DIRTY) &&
              isIResize);
 
   // XXX Should we really need to null check mCBReflowState?  (We do for
   // at least nsBoxFrame).
   if (IS_TABLE_CELL(aFrameType) &&
-      (mFlags.mSpecialHeightReflow ||
+      (mFlags.mSpecialBSizeReflow ||
        (frame->FirstInFlow()->GetStateBits() &
          NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) &&
       (frame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_BSIZE)) {
     // Need to set the bit on the cell so that
     // mCBReflowState->IsBResize() is set correctly below when
     // reflowing descendant.
     SetBResize(true);
   } else if (mCBReflowState && !nsLayoutUtils::IsNonWrapperBlock(frame)) {
@@ -657,36 +657,36 @@ nsHTMLReflowState::InitResizeFlags(nsPre
                  "bad line-height value");
 
     // line-height depends on block bsize
     frame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
     // but only on containing blocks if this frame is not a suitable block
     dependsOnCBBSize |= !nsLayoutUtils::IsNonWrapperBlock(frame);
   }
 
-  // If we're the descendant of a table cell that performs special height
+  // If we're the descendant of a table cell that performs special bsize
   // reflows and we could be the child that requires them, always set
   // the block-axis resize in case this is the first pass before the
-  // special height reflow.  However, don't do this if it actually is
-  // the special height reflow, since in that case it will already be
+  // special bsize reflow.  However, don't do this if it actually is
+  // the special bsize reflow, since in that case it will already be
   // set correctly above if we need it set.
   if (!IsBResize() && mCBReflowState &&
       (IS_TABLE_CELL(mCBReflowState->frame->GetType()) || 
        mCBReflowState->mFlags.mHeightDependsOnAncestorCell) &&
-      !mCBReflowState->mFlags.mSpecialHeightReflow && 
+      !mCBReflowState->mFlags.mSpecialBSizeReflow && 
       dependsOnCBBSize) {
     SetBResize(true);
     mFlags.mHeightDependsOnAncestorCell = true;
   }
 
   // Set NS_FRAME_CONTAINS_RELATIVE_BSIZE if it's needed.
 
   // It would be nice to check that |ComputedBSize != NS_AUTOHEIGHT|
   // &&ed with the percentage bsize check.  However, this doesn't get
-  // along with table special height reflows, since a special height
+  // along with table special bsize reflows, since a special bsize
   // reflow (a quirk that makes such percentage height work on children
   // of table cells) can cause not just a single percentage height to
   // become fixed, but an entire descendant chain of percentage height
   // to become fixed.
   if (dependsOnCBBSize && mCBReflowState) {
     const nsHTMLReflowState *rs = this;
     bool hitCBReflowState = false;
     do {
--- a/layout/generic/nsHTMLReflowState.h
+++ b/layout/generic/nsHTMLReflowState.h
@@ -13,17 +13,17 @@
 #include "nsIFrame.h"
 #include "mozilla/Assertions.h"
 #include <algorithm>
 
 class nsPresContext;
 class nsRenderingContext;
 class nsFloatManager;
 class nsLineLayout;
-class nsIPercentHeightObserver;
+class nsIPercentBSizeObserver;
 struct nsHypotheticalBox;
 
 /**
  * @return aValue clamped to [aMinValue, aMaxValue].
  *
  * @note This function needs to handle aMinValue > aMaxValue. In that case,
  *       aMinValue is returned.
  * @see http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
@@ -509,33 +509,33 @@ public:
   const nsStylePadding*    mStylePadding;
   const nsStyleText*       mStyleText;
 
   bool IsFloating() const;
 
   uint8_t GetDisplay() const;
 
   // a frame (e.g. nsTableCellFrame) which may need to generate a special 
-  // reflow for percent height calculations 
-  nsIPercentHeightObserver* mPercentHeightObserver;
+  // reflow for percent bsize calculations
+  nsIPercentBSizeObserver* mPercentBSizeObserver;
 
   // CSS margin collapsing sometimes requires us to reflow
   // optimistically assuming that margins collapse to see if clearance
   // is required. When we discover that clearance is required, we
   // store the frame in which clearance was discovered to the location
   // requested here.
   nsIFrame** mDiscoveredClearance;
 
   // This value keeps track of how deeply nested a given reflow state
   // is from the top of the frame tree.
   int16_t mReflowDepth;
 
   struct ReflowStateFlags {
-    uint16_t mSpecialHeightReflow:1; // used by tables to communicate special reflow (in process) to handle
-                                     // percent height frames inside cells which may not have computed heights
+    uint16_t mSpecialBSizeReflow:1;  // used by tables to communicate special reflow (in process) to handle
+                                     // percent bsize frames inside cells which may not have computed bsizes
     uint16_t mNextInFlowUntouched:1; // nothing in the frame's next-in-flow (or its descendants)
                                      // is changing
     uint16_t mIsTopOfPage:1;         // Is the current context at the top of a
                                      // page?  When true, we force something
                                      // that's too tall for a page/column to
                                      // fit anyway to avoid infinite loops.
     uint16_t mHasClearance:1;        // Block has clearance
     uint16_t mAssumingHScrollbar:1;  // parent frame is an nsIScrollableFrame and it
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -729,31 +729,49 @@ public:
    */
   void SetRect(mozilla::WritingMode aWritingMode,
                const mozilla::LogicalRect& aRect,
                nscoord aContainerWidth) {
     SetRect(aRect.GetPhysicalRect(aWritingMode, aContainerWidth));
   }
 
   /**
-   * Set this frame's size from a logical size in its own writing direction
+   * Set this frame's size from a logical size in its own writing direction.
+   * This leaves the frame's logical position unchanged, which means its
+   * physical position may change (for right-to-left modes).
    */
   void SetSize(const mozilla::LogicalSize& aSize) {
     SetSize(GetWritingMode(), aSize);
   }
   /*
-   * Set this frame's size from a logical size in a different writing direction
+   * Set this frame's size from a logical size in a different writing direction.
+   * This leaves the frame's logical position in the given mode unchanged,
+   * which means its physical position may change (for right-to-left modes).
    */
   void SetSize(mozilla::WritingMode aWritingMode,
-               const mozilla::LogicalSize& aSize) {
-    SetSize(aSize.GetPhysicalSize(aWritingMode));
+               const mozilla::LogicalSize& aSize)
+  {
+    if ((!aWritingMode.IsVertical() && !aWritingMode.IsBidiLTR()) ||
+        aWritingMode.IsVerticalRL()) {
+      nscoord oldWidth = mRect.width;
+      SetSize(aSize.GetPhysicalSize(aWritingMode));
+      mRect.x -= mRect.width - oldWidth;
+    } else {
+      SetSize(aSize.GetPhysicalSize(aWritingMode));
+    }
   }
+
+  /**
+   * Set this frame's physical size. This leaves the frame's physical position
+   * (topLeft) unchanged.
+   */
   void SetSize(const nsSize& aSize) {
     SetRect(nsRect(mRect.TopLeft(), aSize));
   }
+
   void SetPosition(const nsPoint& aPt) { mRect.MoveTo(aPt); }
   void SetPosition(mozilla::WritingMode aWritingMode,
                    const mozilla::LogicalPoint& aPt,
                    nscoord aContainerWidth) {
     // We subtract mRect.width from the container width to account for
     // the fact that logical origins in RTL coordinate systems are at
     // the top right of the frame instead of the top left.
     mRect.MoveTo(aPt.GetPhysicalPoint(aWritingMode,
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -1426,22 +1426,23 @@ void nsFrameSelection::BidiLevelFromMove
 
 /**
  * BidiLevelFromClick is called when the caret is repositioned by clicking the mouse
  *
  * @param aNode is the content node
  * @param aContentOffset is the new caret position, as an offset into aNode
  */
 void nsFrameSelection::BidiLevelFromClick(nsIContent *aNode,
-                                          uint32_t    aContentOffset)
+                                          uint32_t    aContentOffset,
+                                          CaretAssociateHint aHint)
 {
   nsIFrame* clickInFrame=nullptr;
   int32_t OffsetNotUsed;
 
-  clickInFrame = GetFrameForNodeOffset(aNode, aContentOffset, mHint, &OffsetNotUsed);
+  clickInFrame = GetFrameForNodeOffset(aNode, aContentOffset, aHint, &OffsetNotUsed);
   if (!clickInFrame)
     return;
 
   SetCaretBidiLevel(NS_GET_EMBEDDING_LEVEL(clickInFrame));
 }
 
 
 bool
@@ -1510,17 +1511,17 @@ nsFrameSelection::HandleClick(nsIContent
     if (!IsValidSelectionPoint(this, aNewFocus)) {
       mAncestorLimiter = nullptr;
     }
   }
 
   // Don't take focus when dragging off of a table
   if (!mDragSelectingCells)
   {
-    BidiLevelFromClick(aNewFocus, aContentOffset);
+    BidiLevelFromClick(aNewFocus, aContentOffset, aHint);
     PostReason(nsISelectionListener::MOUSEDOWN_REASON + nsISelectionListener::DRAG_REASON);
     if (aContinueSelection &&
         AdjustForMaintainedSelection(aNewFocus, aContentOffset))
       return NS_OK; //shift clicked to maintained selection. rejected.
 
     int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
     AutoPrepareFocusRange prep(mDomSelections[index], aContinueSelection, aMultipleSelection);
     return TakeFocus(aNewFocus, aContentOffset, aContentEndOffset, aHint,
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -614,29 +614,30 @@ int32_t nsTextFrame::GetContentEnd() con
 struct FlowLengthProperty {
   int32_t mStartOffset;
   // The offset of the next fixed continuation after mStartOffset, or
   // of the end of the text if there is none
   int32_t mEndFlowOffset;
 };
 
 int32_t nsTextFrame::GetInFlowContentLength() {
-  if (!(mState & NS_FRAME_IS_BIDI)) {
+  if (!(mState & NS_FRAME_IS_BIDI) &&
+      !StyleText()->NewlineIsSignificant(this)) {
     return mContent->TextLength() - mContentOffset;
   }
 
   FlowLengthProperty* flowLength =
     static_cast<FlowLengthProperty*>(mContent->GetProperty(nsGkAtoms::flowlength));
 
   /**
    * This frame must start inside the cached flow. If the flow starts at
    * mContentOffset but this frame is empty, logically it might be before the
    * start of the cached flow.
    */
-  if (flowLength && 
+  if (flowLength && !StyleText()->NewlineIsSignificant(this) &&
       (flowLength->mStartOffset < mContentOffset ||
        (flowLength->mStartOffset == mContentOffset && GetContentEnd() > mContentOffset)) &&
       flowLength->mEndFlowOffset > mContentOffset) {
 #ifdef DEBUG
     NS_ASSERTION(flowLength->mEndFlowOffset >= GetContentEnd(),
 		 "frame crosses fixed continuation boundary");
 #endif
     return flowLength->mEndFlowOffset - mContentOffset;
@@ -4799,16 +4800,28 @@ LazyGetLineBaselineOffset(nsIFrame* aChi
     aChildFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &offsetFound)
     );
 
   } else {
     return offset;
   }
 }
 
+static bool IsUnderlineRight(nsIFrame* aFrame)
+{
+  nsIAtom* langAtom = aFrame->StyleFont()->mLanguage;
+  if (!langAtom) {
+    return false;
+  }
+  nsAtomString langStr(langAtom);
+  return (StringBeginsWith(langStr, NS_LITERAL_STRING("ja")) ||
+          StringBeginsWith(langStr, NS_LITERAL_STRING("ko"))) &&
+         (langStr.Length() == 2 || langStr[2] == '-');
+}
+
 void
 nsTextFrame::GetTextDecorations(
                     nsPresContext* aPresContext,
                     nsTextFrame::TextDecorationColorResolution aColorResolution,
                     nsTextFrame::TextDecorations& aDecorations)
 {
   const nsCompatibility compatMode = aPresContext->CompatibilityMode();
 
@@ -4897,21 +4910,29 @@ nsTextFrame::GetTextDecorations(
         //     override the fill paint of the decoration.
         color = aColorResolution == eResolvedColors ?
                   nsLayoutUtils::GetColor(f, eCSSProperty_fill) :
                   NS_SAME_AS_FOREGROUND_COLOR;
       } else {
         color = nsLayoutUtils::GetColor(f, eCSSProperty_text_decoration_color);
       }
 
-      if (textDecorations & NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE) {
+      bool swapUnderlineAndOverline = vertical && IsUnderlineRight(f);
+      const uint8_t kUnderline =
+        swapUnderlineAndOverline ? NS_STYLE_TEXT_DECORATION_LINE_OVERLINE :
+                                   NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
+      const uint8_t kOverline =
+        swapUnderlineAndOverline ? NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE :
+                                   NS_STYLE_TEXT_DECORATION_LINE_OVERLINE;
+
+      if (textDecorations & kUnderline) {
         aDecorations.mUnderlines.AppendElement(
           nsTextFrame::LineDecoration(f, baselineOffset, color, style));
       }
-      if (textDecorations & NS_STYLE_TEXT_DECORATION_LINE_OVERLINE) {
+      if (textDecorations & kOverline) {
         aDecorations.mOverlines.AppendElement(
           nsTextFrame::LineDecoration(f, baselineOffset, color, style));
       }
       if (textDecorations & NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) {
         aDecorations.mStrikes.AppendElement(
           nsTextFrame::LineDecoration(f, baselineOffset, color, style));
       }
     }
@@ -5255,17 +5276,17 @@ static void DrawSelectionDecorations(gfx
     const gfxRect& aDirtyRect,
     SelectionType aType,
     nsTextFrame* aFrame,
     nsTextPaintStyle& aTextPaintStyle,
     const TextRangeStyle &aRangeStyle,
     const gfxPoint& aPt, gfxFloat aICoordInFrame, gfxFloat aWidth,
     gfxFloat aAscent, const gfxFont::Metrics& aFontMetrics,
     nsTextFrame::DrawPathCallbacks* aCallbacks,
-    bool aVertical)
+    bool aVertical, uint8_t aDecoration)
 {
   gfxPoint pt(aPt);
   gfxSize size(aWidth,
                ComputeSelectionUnderlineHeight(aTextPaintStyle.PresContext(),
                                                aFontMetrics, aType));
   gfxFloat descentLimit =
     ComputeDescentLimitForSelectionUnderline(aTextPaintStyle.PresContext(),
                                              aFrame, aFontMetrics);
@@ -5333,18 +5354,20 @@ static void DrawSelectionDecorations(gfx
       break;
     default:
       NS_WARNING("Requested selection decorations when there aren't any");
       return;
   }
   size.height *= relativeSize;
   PaintDecorationLine(aFrame, aContext, aDirtyRect, color, nullptr, pt,
     (aVertical ? (pt.y - aPt.y) : (pt.x - aPt.x)) + aICoordInFrame,
-    size, aAscent, aFontMetrics.underlineOffset,
-    NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, style, eSelectionDecoration,
+    size, aAscent, 
+    aDecoration == NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE ?
+      aFontMetrics.underlineOffset : aFontMetrics.maxAscent,
+    aDecoration, style, eSelectionDecoration,
     aCallbacks, aVertical, descentLimit);
 }
 
 /**
  * This function encapsulates all knowledge of how selections affect foreground
  * and background colors.
  * @return true if the selection affects colors, false otherwise
  * @param aForeground the foreground color to use
@@ -5799,16 +5822,20 @@ nsTextFrame::PaintTextSelectionDecoratio
         selectedChars[i] = sdptr;
       }
     }
     sdptr = sdptr->mNext;
   }
 
   gfxFont* firstFont = aProvider.GetFontGroup()->GetFirstValidFont();
   bool verticalRun = mTextRun->IsVertical();
+  bool rightUnderline = verticalRun && IsUnderlineRight(this);
+  const uint8_t kDecoration =
+    rightUnderline ? NS_STYLE_TEXT_DECORATION_LINE_OVERLINE :
+                     NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
   bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline();
   gfxFont::Metrics
     decorationMetrics(firstFont->GetMetrics(useVerticalMetrics ?
       gfxFont::eVertical : gfxFont::eHorizontal));
   if (!useVerticalMetrics) {
     // The potential adjustment from using gfxFontGroup::GetUnderlineOffset
     // is only valid for horizontal font metrics.
     decorationMetrics.underlineOffset =
@@ -5845,17 +5872,17 @@ nsTextFrame::PaintTextSelectionDecoratio
         pt.x = (aFramePt.x + iOffset -
                (mTextRun->IsRightToLeft() ? advance : 0)) / app;
       }
       gfxFloat width = Abs(advance) / app;
       gfxFloat xInFrame = pt.x - (aFramePt.x / app);
       DrawSelectionDecorations(aCtx, dirtyRect, aSelectionType, this,
                                aTextPaintStyle, selectedStyle, pt, xInFrame,
                                width, mAscent / app, decorationMetrics,
-                               aCallbacks, verticalRun);
+                               aCallbacks, verticalRun, kDecoration);
     }
     iterator.UpdateWithAdvance(advance);
   }
 }
 
 bool
 nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
     const gfxPoint& aFramePt,
--- a/layout/mathml/nsMathMLmtableFrame.cpp
+++ b/layout/mathml/nsMathMLmtableFrame.cpp
@@ -767,19 +767,17 @@ nsMathMLmtableOuterFrame::GetRowFrameAt(
   // if our inner table says that the index is valid, find the row now
   if (0 <= aRowIndex && aRowIndex <= rowCount) {
     nsIFrame* tableFrame = mFrames.FirstChild();
     NS_ASSERTION(tableFrame && tableFrame->GetType() == nsGkAtoms::tableFrame,
                  "should always have an inner table frame");
     nsIFrame* rgFrame = tableFrame->GetFirstPrincipalChild();
     if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
       return nullptr;
-    nsTableIterator rowIter(*rgFrame);
-    nsIFrame* rowFrame = rowIter.First();
-    for ( ; rowFrame; rowFrame = rowIter.Next()) {
+    for (nsIFrame* rowFrame : rgFrame->PrincipalChildList()) {
       if (aRowIndex == 0) {
         DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW);
         if (rowFrame->GetType() != nsGkAtoms::tableRowFrame)
           return nullptr;
 
         return rowFrame;
       }
       --aRowIndex;
--- a/layout/reftests/table-bordercollapse/border-collapse-rtl-ref.html
+++ b/layout/reftests/table-bordercollapse/border-collapse-rtl-ref.html
@@ -1,23 +1,23 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset=utf-8>
 <style>
 table {
   margin: 10px;
-  border: 3px solid silver;
+  border: 8px solid silver;
   border-right-color: gray;
   border-bottom-color: gray;
   border-spacing: 5px;
   border-collapse: collapse;
 }
 td {
-  border: 5px solid black;
+  border: 4px solid black;
   width: 50px;
   height: 20px;
   text-align: center;
 }
 td.w1 {
   width: 80px;
 }
 td.w2 {
--- a/layout/reftests/table-bordercollapse/border-collapse-rtl.html
+++ b/layout/reftests/table-bordercollapse/border-collapse-rtl.html
@@ -1,23 +1,23 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset=utf-8>
 <style>
 table {
   margin: 10px;
-  border: 3px solid silver;
+  border: 8px solid silver;
   border-right-color: gray;
   border-bottom-color: gray;
   border-spacing: 5px;
   border-collapse: collapse;
 }
 td {
-  border: 5px solid black;
+  border: 4px solid black;
   width: 50px;
   height: 20px;
   text-align: center;
 }
 td.w1 {
   width: 80px;
 }
 td.w2 {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/writing-mode/1175789-underline-overline-1-ref.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <title>Bug 1175789 - underline and overline in various language</title>
+  <style type="text/css">
+    body {
+      font-family: "Arial", "Helvetica", "sans-serif";
+    }
+    div {
+      padding: .5em 1em;
+      line-height: 2em;
+    }
+    .underline {
+      text-decoration: underline;
+    }
+    .overline {
+      text-decoration: overline;
+    }
+  </style>
+ </head>
+ <body>
+   <dl>
+     <dt>lang="en-US"</dt>
+     <dd lang="en-US">
+       <div style="writing-mode: vertical-rl;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+     </dd>
+     <dt>lang="ja"</dt>
+     <dd lang="en-US">
+       <div style="writing-mode: vertical-rl;">
+         <span class="overline">underline</span><br>
+         <span class="underline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="overline">underline</span><br>
+         <span class="underline">overline</span>
+       </div>
+     </dd>
+     <dt>lang="ko"</dt>
+     <dd lang="en-US">
+       <div style="writing-mode: vertical-rl;">
+         <span class="overline">underline</span><br>
+         <span class="underline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="overline">underline</span><br>
+         <span class="underline">overline</span>
+       </div>
+     </dd>
+     <dt>lang="ja-JP"</dt>
+     <dd lang="en-US">
+       <div style="writing-mode: vertical-rl;">
+         <span class="overline">underline</span><br>
+         <span class="underline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="overline">underline</span><br>
+         <span class="underline">overline</span>
+       </div>
+     </dd>
+     <dt>lang="ko-KR"</dt>
+     <dd lang="en-US">
+       <div style="writing-mode: vertical-rl;">
+         <span class="overline">underline</span><br>
+         <span class="underline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="overline">underline</span><br>
+         <span class="underline">overline</span>
+       </div>
+     </dd>
+     <dt>lang="zh"</dt>
+     <dd lang="en-US">
+       <div style="writing-mode: vertical-rl;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+     </dd>
+    </dl>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/writing-mode/1175789-underline-overline-1.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <title>Bug 1175789 - underline and overline in various language</title>
+  <style type="text/css">
+    body {
+      font-family: "Arial", "Helvetica", "sans-serif";
+    }
+    div {
+      padding: .5em 1em;
+      line-height: 2em;
+    }
+    .underline {
+      text-decoration: underline;
+    }
+    .overline {
+      text-decoration: overline;
+    }
+  </style>
+ </head>
+ <body>
+   <dl>
+     <dt>lang="en-US"</dt>
+     <dd lang="en-US">
+       <div style="writing-mode: vertical-rl;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+     </dd>
+     <dt>lang="ja"</dt>
+     <dd lang="ja">
+       <div style="writing-mode: vertical-rl;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+     </dd>
+     <dt>lang="ko"</dt>
+     <dd lang="ko">
+       <div style="writing-mode: vertical-rl;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+     </dd>
+     <dt>lang="ja-JP"</dt>
+     <dd lang="ja-JP">
+       <div style="writing-mode: vertical-rl;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+     </dd>
+     <dt>lang="ko-KR"</dt>
+     <dd lang="ko-KR">
+       <div style="writing-mode: vertical-rl;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+     </dd>
+     <dt>lang="zh"</dt>
+     <dd lang="zh">
+       <div style="writing-mode: vertical-rl;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+       <div style="writing-mode: vertical-lr;">
+         <span class="underline">underline</span><br>
+         <span class="overline">overline</span>
+       </div>
+     </dd>
+    </dl>
+ </body>
+</html>
--- a/layout/reftests/writing-mode/reftest.list
+++ b/layout/reftests/writing-mode/reftest.list
@@ -144,11 +144,12 @@ fails == 1147834-relative-overconstraine
 == 1172774-percent-margin-2.html 1172774-percent-horizontal-ref.html
 == 1172774-percent-margin-3.html 1172774-percent-vertical-ref.html
 == 1172774-percent-margin-4.html 1172774-percent-vertical-ref.html
 == 1172774-percent-padding-1.html 1172774-percent-horizontal-ref.html
 == 1172774-percent-padding-2.html 1172774-percent-horizontal-ref.html
 == 1172774-percent-padding-3.html 1172774-percent-vertical-ref.html
 == 1172774-percent-padding-4.html 1172774-percent-vertical-ref.html
 == 1174450-intrinsic-sizing.html 1174450-intrinsic-sizing-ref.html
+== 1175789-underline-overline-1.html 1175789-underline-overline-1-ref.html
 
 # Suite of tests from Gérard Talbot in bug 1079151
 include abspos/reftest.list
new file mode 100644
--- /dev/null
+++ b/layout/style/RuleNodeCacheConditions.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * an object that stores the result of determining whether a style struct that
+ * was computed can be cached in the rule tree, and if so, what the cache
+ * key is
+ */
+
+#include "RuleNodeCacheConditions.h"
+
+#include "nsStyleContext.h"
+#include "WritingModes.h"
+
+using namespace mozilla;
+
+bool
+RuleNodeCacheConditions::Matches(nsStyleContext* aStyleContext) const
+{
+  MOZ_ASSERT(Cacheable());
+  if ((mBits & eHaveFontSize) &&
+      mFontSize != aStyleContext->StyleFont()->mFont.size) {
+    return false;
+  }
+  if ((mBits & eHaveWritingMode) &&
+      (GetWritingMode() != WritingMode(aStyleContext).GetBits())) {
+    return false;
+  }
+  return true;
+}
+
+#ifdef DEBUG
+void
+RuleNodeCacheConditions::List() const
+{
+  printf("{ ");
+  bool first = true;
+  if (mBits & eHaveFontSize) {
+    printf("FontSize(%d)", mFontSize);
+    first = false;
+  }
+  if (mBits & eHaveWritingMode) {
+    if (!first) {
+      printf(", ");
+    }
+    printf("WritingMode(0x%x)", GetWritingMode());
+  }
+  printf(" }");
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/layout/style/RuleNodeCacheConditions.h
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * an object that stores the result of determining whether a style struct that
+ * was computed can be cached in the rule tree, and if so, what the conditions
+ * it relies on are
+ */
+
+#ifndef RuleNodeCacheConditions_h_
+#define RuleNodeCacheConditions_h_
+
+#include "mozilla/Attributes.h"
+#include "nsCoord.h"
+#include "nsTArray.h"
+
+class nsStyleContext;
+
+namespace mozilla {
+
+class RuleNodeCacheConditions
+{
+public:
+  RuleNodeCacheConditions()
+    : mFontSize(0), mBits(0) {}
+  RuleNodeCacheConditions(const RuleNodeCacheConditions& aOther)
+    : mFontSize(aOther.mFontSize), mBits(aOther.mBits) {}
+  RuleNodeCacheConditions& operator=(const RuleNodeCacheConditions& aOther)
+  {
+    mFontSize = aOther.mFontSize;
+    mBits = aOther.mBits;
+    return *this;
+  }
+  bool operator==(const RuleNodeCacheConditions& aOther) const
+  {
+    return mFontSize == aOther.mFontSize &&
+           mBits == aOther.mBits;
+  }
+  bool operator!=(const RuleNodeCacheConditions& aOther) const
+  {
+    return !(*this == aOther);
+  }
+
+  bool Matches(nsStyleContext* aStyleContext) const;
+
+  void SetFontSizeDependency(nscoord aCoord)
+  {
+    MOZ_ASSERT(!(mBits & eHaveFontSize) || mFontSize == aCoord);
+    mFontSize = aCoord;
+    mBits |= eHaveFontSize;
+  }
+
+  void SetWritingModeDependency(uint8_t aWritingMode)
+  {
+    MOZ_ASSERT(!(mBits & eHaveWritingMode) || GetWritingMode() == aWritingMode);
+    mBits |= (static_cast<uint64_t>(aWritingMode) << eWritingModeShift) |
+             eHaveWritingMode;
+  }
+
+  void SetUncacheable()
+  {
+    mBits |= eUncacheable;
+  }
+
+  bool Cacheable() const
+  {
+    return !(mBits & eUncacheable);
+  }
+
+  bool CacheableWithDependencies() const
+  {
+    return !(mBits & eUncacheable) &&
+           (mBits & eHaveBitsMask) != 0;
+  }
+
+  bool CacheableWithoutDependencies() const
+  {
+    // We're not uncacheable and we have don't have a font-size or
+    // writing mode value.
+    return (mBits & eHaveBitsMask) == 0;
+  }
+
+#ifdef DEBUG
+  void List() const;
+#endif
+
+private:
+  enum {
+    eUncacheable      = 0x0001,
+    eHaveFontSize     = 0x0002,
+    eHaveWritingMode  = 0x0004,
+    eHaveBitsMask     = 0x00ff,
+    eWritingModeMask  = 0xff00,
+    eWritingModeShift = 8,
+  };
+
+  uint8_t GetWritingMode() const
+  {
+    return static_cast<uint8_t>(
+        (mBits & eWritingModeMask) >> eWritingModeShift);
+  }
+
+  // The font size from which em units are derived.
+  nscoord mFontSize;
+
+  // Values in mBits:
+  //   bit 0:      are we set to "uncacheable"?
+  //   bit 1:      do we have a font size value?
+  //   bit 2:      do we have a writing mode value?
+  //   bits 2-7:   unused
+  //   bits 8-15:  writing mode (uint8_t)
+  //   bits 16-31: unused
+  uint32_t mBits;
+};
+
+} // namespace mozilla
+
+#endif // !defined(RuleNodeCacheConditions_h_)
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -2,17 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Utilities for animation of computed style values */
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/MathAlgorithms.h"
-
+#include "mozilla/RuleNodeCacheConditions.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "nsStyleTransformMatrix.h"
 #include "nsCOMArray.h"
 #include "nsIStyleRule.h"
 #include "mozilla/css/StyleRule.h"
 #include "nsString.h"
 #include "nsStyleContext.h"
 #include "nsStyleSet.h"
@@ -2585,17 +2585,17 @@ StyleAnimationValue::ComputeValue(nsCSSP
     // Force walk of rule tree
     nsStyleStructID sid = nsCSSProps::kSIDTable[aProperty];
     tmpStyleContext->StyleData(sid);
 
     // If the rule node will have cached style data if the value is not
     // context-sensitive. So if there's nothing cached, it's not context
     // sensitive.
     *aIsContextSensitive =
-      !tmpStyleContext->RuleNode()->NodeHasCachedData(sid);
+      !tmpStyleContext->RuleNode()->NodeHasCachedUnconditionalData(sid);
   }
 
   // If we're not concerned whether the property is context sensitive then just
   // add the rule to a new temporary style context alongside the target
   // element's style context.
   // Also, if we previously discovered that this property IS context-sensitive
   // then we need to throw the temporary style context out since the property's
   // value may have been biased by the 'initial' values supplied.
@@ -2863,41 +2863,41 @@ SetPositionValue(const nsStyleBackground
  * replaced with the equivalent in pixels, and any non-canonical calc()
  * expressions replaced with canonical ones.
  */
 static void
 SubstitutePixelValues(nsStyleContext* aStyleContext,
                       const nsCSSValue& aInput, nsCSSValue& aOutput)
 {
   if (aInput.IsCalcUnit()) {
-    bool canStoreInRuleTree = true;
+    RuleNodeCacheConditions conditions;
     nsRuleNode::ComputedCalc c =
       nsRuleNode::SpecifiedCalcToComputedCalc(aInput, aStyleContext,
                                               aStyleContext->PresContext(),
-                                              canStoreInRuleTree);
+                                              conditions);
     nsStyleCoord::CalcValue c2;
     c2.mLength = c.mLength;
     c2.mPercent = c.mPercent;
     c2.mHasPercent = true; // doesn't matter for transform translate
     SetCalcValue(&c2, aOutput);
   } else if (aInput.UnitHasArrayValue()) {
     const nsCSSValue::Array *inputArray = aInput.GetArrayValue();
     nsRefPtr<nsCSSValue::Array> outputArray =
       nsCSSValue::Array::Create(inputArray->Count());
     for (size_t i = 0, i_end = inputArray->Count(); i < i_end; ++i) {
       SubstitutePixelValues(aStyleContext,
                             inputArray->Item(i), outputArray->Item(i));
     }
     aOutput.SetArrayValue(outputArray, aInput.GetUnit());
   } else if (aInput.IsLengthUnit() &&
              aInput.GetUnit() != eCSSUnit_Pixel) {
-    bool canStoreInRuleTree = true;
+    RuleNodeCacheConditions conditions;
     nscoord len = nsRuleNode::CalcLength(aInput, aStyleContext,
                                          aStyleContext->PresContext(),
-                                         canStoreInRuleTree);
+                                         conditions);
     aOutput.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(len),
                           eCSSUnit_Pixel);
   } else {
     aOutput = aInput;
   }
 }
 
 bool
--- a/layout/style/html.css
+++ b/layout/style/html.css
@@ -251,17 +251,16 @@ xmp, pre, plaintext {
   white-space: pre;
   margin-block-start: 1em;
   margin-block-end: 1em;
 }
 
 /* tables */
 
 table {
-  writing-mode: horizontal-tb !important; /* XXX remove when bug 1077521 is fixed */
   display: table;
   border-spacing: 2px;
   border-collapse: separate;
   /* XXXldb do we want this if we're border-collapse:collapse ? */
   box-sizing: border-box;
   text-indent: 0;
 }
 
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -80,16 +80,17 @@ EXPORTS += [
 ]
 
 EXPORTS.mozilla += [
     'CSSStyleSheet.h',
     'CSSVariableDeclarations.h',
     'CSSVariableResolver.h',
     'CSSVariableValues.h',
     'IncrementalClearCOMRuleArray.h',
+    'RuleNodeCacheConditions.h',
     'StyleAnimationValue.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'CSS.h',
     'CSSLexer.h',
     'CSSRuleList.h',
     'CSSValue.h',
@@ -158,16 +159,17 @@ UNIFIED_SOURCES += [
     'nsRuleNode.cpp',
     'nsStyleContext.cpp',
     'nsStyleCoord.cpp',
     'nsStyleSet.cpp',
     'nsStyleStruct.cpp',
     'nsStyleTransformMatrix.cpp',
     'nsStyleUtil.cpp',
     'nsTransitionManager.cpp',
+    'RuleNodeCacheConditions.cpp',
     'StyleAnimationValue.cpp',
     'StyleRule.cpp',
     'SVGAttrAnimationRuleProcessor.cpp',
 ]
 
 # FontFaceSet.cpp needs to be built separately because it redefines LOG.
 # nsCSSRuleProcessor.cpp needs to be built separately because it uses plarena.h.
 SOURCES += [
--- a/layout/style/nsCSSDataBlock.cpp
+++ b/layout/style/nsCSSDataBlock.cpp
@@ -249,17 +249,18 @@ nsCSSCompressedDataBlock::MapRuleInfoInt
         nsCSSProperty iProp = PropertyAtIndex(i);
         if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) &
             aRuleData->mSIDs) {
             if (nsCSSProps::PropHasFlags(iProp, CSS_PROPERTY_LOGICAL)) {
                 EnsurePhysicalProperty(iProp, aRuleData);
                 // We can't cache anything on the rule tree if we use any data from
                 // the style context, since data cached in the rule tree could be
                 // used with a style context with a different value.
-                aRuleData->mCanStoreInRuleTree = false;
+                uint8_t wm = WritingMode(aRuleData->mStyleContext).GetBits();
+                aRuleData->mConditions.SetWritingModeDependency(wm);
             }
             nsCSSValue* target = aRuleData->ValueFor(iProp);
             if (target->GetUnit() == eCSSUnit_Null) {
                 const nsCSSValue *val = ValueAtIndex(i);
                 MapSinglePropertyInto(iProp, val, target, aRuleData);
             }
         }
     }
@@ -688,17 +689,18 @@ nsCSSExpandedDataBlock::MapRuleInfoInto(
   MOZ_ASSERT(!nsCSSProps::IsShorthand(aPropID));
 
   const nsCSSValue* src = PropertyAt(aPropID);
   MOZ_ASSERT(src->GetUnit() != eCSSUnit_Null);
 
   nsCSSProperty physicalProp = aPropID;
   if (nsCSSProps::PropHasFlags(aPropID, CSS_PROPERTY_LOGICAL)) {
     EnsurePhysicalProperty(physicalProp, aRuleData);
-    aRuleData->mCanStoreInRuleTree = false;
+    uint8_t wm = WritingMode(aRuleData->mStyleContext).GetBits();
+    aRuleData->mConditions.SetWritingModeDependency(wm);
   }
 
   nsCSSValue* dest = aRuleData->ValueFor(physicalProp);
   MOZ_ASSERT(dest->GetUnit() == eCSSUnit_TokenStream &&
              dest->GetTokenStreamValue()->mPropertyID == aPropID);
 
   MapSinglePropertyInto(physicalProp, src, dest, aRuleData);
 }
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1260,17 +1260,17 @@ nsComputedDOMStyle::DoGetTransform()
    * the transform based on the size of the element.  However, this poses a
    * problem, because only two of these values can be explicitly referenced
    * using the named transforms.  Until a real solution is found, we'll just
    * use this approach.
    */
   nsStyleTransformMatrix::TransformReferenceBox refBox(mInnerFrame,
                                                        nsSize(0, 0));
 
-   bool dummy;
+   RuleNodeCacheConditions dummy;
    gfx3DMatrix matrix =
      nsStyleTransformMatrix::ReadTransforms(display->mSpecifiedTransform->mHead,
                                             mStyleContextHolder,
                                             mStyleContextHolder->PresContext(),
                                             dummy,
                                             refBox,
                                             float(mozilla::AppUnitsPerCSSPixel()));
 
--- a/layout/style/nsRuleData.cpp
+++ b/layout/style/nsRuleData.cpp
@@ -23,17 +23,16 @@ nsRuleData::GetPoisonOffset()
   uintptr_t framePoisonValue = mozPoisonValue();
   return size_t(framePoisonValue - uintptr_t(mValueStorage)) /
          sizeof(nsCSSValue);
 }
 
 nsRuleData::nsRuleData(uint32_t aSIDs, nsCSSValue* aValueStorage,
                        nsPresContext* aContext, nsStyleContext* aStyleContext)
   : mSIDs(aSIDs),
-    mCanStoreInRuleTree(true),
     mPresContext(aContext),
     mStyleContext(aStyleContext),
     mValueStorage(aValueStorage)
 {
 #ifndef MOZ_VALGRIND
   size_t framePoisonOffset = GetPoisonOffset();
   for (size_t i = 0; i < nsStyleStructID_Length; ++i) {
     mValueOffsets[i] = framePoisonOffset;
--- a/layout/style/nsRuleData.h
+++ b/layout/style/nsRuleData.h
@@ -7,30 +7,31 @@
  * temporary (expanded) representation of property-value pairs used to
  * hold data from matched rules during style data computation.
  */
 
 #ifndef nsRuleData_h_
 #define nsRuleData_h_
 
 #include "mozilla/CSSVariableDeclarations.h"
+#include "mozilla/RuleNodeCacheConditions.h"
 #include "nsCSSProps.h"
 #include "nsCSSValue.h"
 #include "nsStyleStructFwd.h"
 
 class nsPresContext;
 class nsStyleContext;
 struct nsRuleData;
 
 typedef void (*nsPostResolveFunc)(void* aStyleStruct, nsRuleData* aData);
 
 struct nsRuleData
 {
   const uint32_t mSIDs;
-  bool mCanStoreInRuleTree;
+  mozilla::RuleNodeCacheConditions mConditions;
   bool mIsImportantRule;
   uint16_t mLevel; // an nsStyleSet::sheetType
   nsPresContext* const mPresContext;
   nsStyleContext* const mStyleContext;
 
   // We store nsCSSValues needed to compute the data for one or more
   // style structs (specified by the bitfield mSIDs).  These are stored
   // in a single array allocation (which our caller allocates; see
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -43,16 +43,17 @@
 #include "nsRenderingContext.h"
 #include "nsStyleUtil.h"
 #include "nsIDocument.h"
 #include "prtime.h"
 #include "CSSVariableResolver.h"
 #include "nsCSSParser.h"
 #include "CounterStyleManager.h"
 #include "nsCSSPropertySet.h"
+#include "mozilla/RuleNodeCacheConditions.h"
 
 #if defined(_MSC_VER) || defined(__MINGW32__)
 #include <malloc.h>
 #ifdef _MSC_VER
 #define alloca _alloca
 #endif
 #endif
 #ifdef SOLARIS
@@ -79,17 +80,17 @@ using namespace mozilla::dom;
   }
 
 /* Helper function to convert a CSS <position> specified value into its
  * computed-style form. */
 static void
   ComputePositionValue(nsStyleContext* aStyleContext,
                        const nsCSSValue& aValue,
                        nsStyleBackground::Position& aComputedValue,
-                       bool& aCanStoreInRuleTree);
+                       RuleNodeCacheConditions& aConditions);
 
 /*
  * For storage of an |nsRuleNode|'s children in a PLDHashTable.
  */
 
 struct ChildrenHashEntry : public PLDHashEntryHdr {
   // key is |mRuleNode->GetKey()|
   nsRuleNode *mRuleNode;
@@ -222,49 +223,49 @@ nsRuleNode::EnsureInlineDisplay(uint8_t&
 
 static nscoord CalcLengthWith(const nsCSSValue& aValue,
                               nscoord aFontSize,
                               const nsStyleFont* aStyleFont,
                               nsStyleContext* aStyleContext,
                               nsPresContext* aPresContext,
                               bool aUseProvidedRootEmSize,
                               bool aUseUserFontSet,
-                              bool& aCanStoreInRuleTree);
+                              RuleNodeCacheConditions& aConditions);
 
 struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
                            public css::NumbersAlreadyNormalizedOps
 {
   // All of the parameters to CalcLengthWith except aValue.
   const nscoord mFontSize;
   const nsStyleFont* const mStyleFont;
   nsStyleContext* const mStyleContext;
   nsPresContext* const mPresContext;
   const bool mUseProvidedRootEmSize;
   const bool mUseUserFontSet;
-  bool& mCanStoreInRuleTree;
+  RuleNodeCacheConditions& mConditions;
 
   CalcLengthCalcOps(nscoord aFontSize, const nsStyleFont* aStyleFont,
                     nsStyleContext* aStyleContext, nsPresContext* aPresContext,
                     bool aUseProvidedRootEmSize, bool aUseUserFontSet,
-                    bool& aCanStoreInRuleTree)
+                    RuleNodeCacheConditions& aConditions)
     : mFontSize(aFontSize),
       mStyleFont(aStyleFont),
       mStyleContext(aStyleContext),
       mPresContext(aPresContext),
       mUseProvidedRootEmSize(aUseProvidedRootEmSize),
       mUseUserFontSet(aUseUserFontSet),
-      mCanStoreInRuleTree(aCanStoreInRuleTree)
+      mConditions(aConditions)
   {
   }
 
   result_type ComputeLeafValue(const nsCSSValue& aValue)
   {
     return CalcLengthWith(aValue, mFontSize, mStyleFont,
                           mStyleContext, mPresContext, mUseProvidedRootEmSize,
-                          mUseUserFontSet, mCanStoreInRuleTree);
+                          mUseUserFontSet, mConditions);
   }
 };
 
 static inline nscoord ScaleCoordRound(const nsCSSValue& aValue, float aFactor)
 {
   return NSToCoordRoundWithClamp(aValue.GetFloatValue() * aFactor);
 }
 
@@ -360,17 +361,17 @@ static nscoord CalcLengthWith(const nsCS
                               const nsStyleFont* aStyleFont,
                               nsStyleContext* aStyleContext,
                               nsPresContext* aPresContext,
                               bool aUseProvidedRootEmSize,
                               // aUseUserFontSet should always be true
                               // except when called from
                               // CalcLengthWithInitialFont.
                               bool aUseUserFontSet,
-                              bool& aCanStoreInRuleTree)
+                              RuleNodeCacheConditions& aConditions)
 {
   NS_ASSERTION(aValue.IsLengthUnit() || aValue.IsCalcUnit(),
                "not a length or calc unit");
   NS_ASSERTION(aStyleFont || aStyleContext,
                "Must have style data");
   NS_ASSERTION(!aStyleFont || !aStyleContext,
                "Duplicate sources of data");
   NS_ASSERTION(aPresContext, "Must have prescontext");
@@ -385,17 +386,17 @@ static nscoord CalcLengthWith(const nsCS
     // For properties for which lengths are the *only* units accepted in
     // calc(), we can handle calc() here and just compute a final
     // result.  We ensure that we don't get to this code for other
     // properties by not calling CalcLength in those cases:  SetCoord
     // only calls CalcLength for a calc when it is appropriate to do so.
     CalcLengthCalcOps ops(aFontSize, aStyleFont,
                           aStyleContext, aPresContext,
                           aUseProvidedRootEmSize, aUseUserFontSet,
-                          aCanStoreInRuleTree);
+                          aConditions);
     return css::ComputeCalc(aValue, ops);
   }
   switch (aValue.GetUnit()) {
     // nsPresContext::SetVisibleArea and
     // nsPresContext::MediaFeatureValuesChanged handle dynamic changes
     // of the basis for viewport units by rebuilding the rule tree and
     // style context tree.  Not caching them in the rule tree wouldn't
     // be sufficient to handle these changes because we also need a way
@@ -435,19 +436,19 @@ static nscoord CalcLengthWith(const nsCS
     // other things).  And since the font size of the root element
     // changes rarely, we instead handle dynamic changes to the root
     // element's font size by rebuilding all style data in
     // nsCSSFrameConstructor::RestyleElement.
     case eCSSUnit_RootEM: {
       aPresContext->SetUsesRootEMUnits(true);
       nscoord rootFontSize;
 
-      // NOTE: Be very careful with |styleFont|, since we haven't set
-      // aCanStoreInRuleTree to false yet, so we don't want to introduce
-      // any dependencies on aStyleContext's data here.
+      // NOTE: Be very careful with |styleFont|, since we haven't added any
+      // conditions to aConditions or set it to uncacheable yet, so we don't
+      // want to introduce any dependencies on aStyleContext's data here.
       const nsStyleFont *styleFont =
         aStyleFont ? aStyleFont : aStyleContext->StyleFont();
 
       if (aUseProvidedRootEmSize) {
         // We should use the provided aFontSize as the reference length to
         // scale. This only happens when we are calculating font-size or
         // an equivalent (scriptminsize or CalcLengthWithInitialFont) on
         // the root element, in which case aFontSize is already the
@@ -489,115 +490,117 @@ static nscoord CalcLengthWith(const nsCS
     }
     default:
       // Fall through to the code for units that can't be stored in the
       // rule tree because they depend on font data.
       break;
   }
   // Common code for units that depend on the element's font data and
   // thus can't be stored in the rule tree:
-  aCanStoreInRuleTree = false;
   const nsStyleFont *styleFont =
     aStyleFont ? aStyleFont : aStyleContext->StyleFont();
   if (aFontSize == -1) {
     // XXX Should this be styleFont->mSize instead to avoid taking minfontsize
     // prefs into account?
     aFontSize = styleFont->mFont.size;
   }
   switch (aValue.GetUnit()) {
     case eCSSUnit_EM: {
       // CSS2.1 specifies that this unit scales to the computed font
       // size, not the em-width in the font metrics, despite the name.
+      aConditions.SetFontSizeDependency(aFontSize);
       return ScaleCoordRound(aValue, float(aFontSize));
     }
     case eCSSUnit_XHeight: {
       aPresContext->SetUsesExChUnits(true);
       nsRefPtr<nsFontMetrics> fm =
         GetMetricsFor(aPresContext, aStyleContext, styleFont,
                       aFontSize, aUseUserFontSet);
+      aConditions.SetUncacheable();
       return ScaleCoordRound(aValue, float(fm->XHeight()));
     }
     case eCSSUnit_Char: {
       aPresContext->SetUsesExChUnits(true);
       nsRefPtr<nsFontMetrics> fm =
         GetMetricsFor(aPresContext, aStyleContext, styleFont,
                       aFontSize, aUseUserFontSet);
       gfxFloat zeroWidth =
         fm->GetThebesFontGroup()->GetFirstValidFont()->
           GetMetrics(fm->Orientation()).zeroOrAveCharWidth;
 
+      aConditions.SetUncacheable();
       return ScaleCoordRound(aValue, ceil(aPresContext->AppUnitsPerDevPixel() *
                                           zeroWidth));
     }
     default:
       NS_NOTREACHED("unexpected unit");
       break;
   }
   return 0;
 }
 
 /* static */ nscoord
 nsRuleNode::CalcLength(const nsCSSValue& aValue,
                        nsStyleContext* aStyleContext,
                        nsPresContext* aPresContext,
-                       bool& aCanStoreInRuleTree)
+                       RuleNodeCacheConditions& aConditions)
 {
   NS_ASSERTION(aStyleContext, "Must have style data");
 
   return CalcLengthWith(aValue, -1, nullptr,
                         aStyleContext, aPresContext,
-                        false, true, aCanStoreInRuleTree);
+                        false, true, aConditions);
 }
 
 /* Inline helper function to redirect requests to CalcLength. */
 static inline nscoord CalcLength(const nsCSSValue& aValue,
                                  nsStyleContext* aStyleContext,
                                  nsPresContext* aPresContext,
-                                 bool& aCanStoreInRuleTree)
+                                 RuleNodeCacheConditions& aConditions)
 {
   return nsRuleNode::CalcLength(aValue, aStyleContext,
-                                aPresContext, aCanStoreInRuleTree);
+                                aPresContext, aConditions);
 }
 
 /* static */ nscoord
 nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
                                       const nsCSSValue& aValue)
 {
   nsStyleFont defaultFont(aPresContext); // FIXME: best language?
-  bool canStoreInRuleTree;
+  RuleNodeCacheConditions conditions;
   return CalcLengthWith(aValue, -1, &defaultFont,
                         nullptr, aPresContext,
-                        true, false, canStoreInRuleTree);
+                        true, false, conditions);
 }
 
 struct LengthPercentPairCalcOps : public css::NumbersAlreadyNormalizedOps
 {
   typedef nsRuleNode::ComputedCalc result_type;
 
   LengthPercentPairCalcOps(nsStyleContext* aContext,
                            nsPresContext* aPresContext,
-                           bool& aCanStoreInRuleTree)
+                           RuleNodeCacheConditions& aConditions)
     : mContext(aContext),
       mPresContext(aPresContext),
-      mCanStoreInRuleTree(aCanStoreInRuleTree),
+      mConditions(aConditions),
       mHasPercent(false) {}
 
   nsStyleContext* mContext;
   nsPresContext* mPresContext;
-  bool& mCanStoreInRuleTree;
+  RuleNodeCacheConditions& mConditions;
   bool mHasPercent;
 
   result_type ComputeLeafValue(const nsCSSValue& aValue)
   {
     if (aValue.GetUnit() == eCSSUnit_Percent) {
       mHasPercent = true;
       return result_type(0, aValue.GetPercentValue());
     }
     return result_type(CalcLength(aValue, mContext, mPresContext,
-                                  mCanStoreInRuleTree),
+                                  mConditions),
                        0.0f);
   }
 
   result_type
   MergeAdditive(nsCSSUnit aCalcFunction,
                 result_type aValue1, result_type aValue2)
   {
     if (aCalcFunction == eCSSUnit_Calc_Plus) {
@@ -636,39 +639,39 @@ struct LengthPercentPairCalcOps : public
                        aValue1.mPercent * aValue2);
   }
 
 };
 
 static void
 SpecifiedCalcToComputedCalc(const nsCSSValue& aValue, nsStyleCoord& aCoord, 
                             nsStyleContext* aStyleContext,
-                            bool& aCanStoreInRuleTree)
+                            RuleNodeCacheConditions& aConditions)
 {
   LengthPercentPairCalcOps ops(aStyleContext, aStyleContext->PresContext(),
-                               aCanStoreInRuleTree);
+                               aConditions);
   nsRuleNode::ComputedCalc vals = ComputeCalc(aValue, ops);
 
   nsStyleCoord::Calc* calcObj = new nsStyleCoord::Calc;
 
   calcObj->mLength = vals.mLength;
   calcObj->mPercent = vals.mPercent;
   calcObj->mHasPercent = ops.mHasPercent;
 
   aCoord.SetCalcValue(calcObj);
 }
 
 /* static */ nsRuleNode::ComputedCalc
 nsRuleNode::SpecifiedCalcToComputedCalc(const nsCSSValue& aValue,
                                         nsStyleContext* aStyleContext,
                                         nsPresContext* aPresContext,
-                                        bool& aCanStoreInRuleTree)
+                                        RuleNodeCacheConditions& aConditions)
 {
   LengthPercentPairCalcOps ops(aStyleContext, aPresContext,
-                               aCanStoreInRuleTree);
+                               aConditions);
   return ComputeCalc(aValue, ops);
 }
 
 // This is our public API for handling calc() expressions that involve
 // percentages.
 /* static */ nscoord
 nsRuleNode::ComputeComputedCalc(const nsStyleCoord& aValue,
                                 nscoord aPercentageBasis)
@@ -762,28 +765,28 @@ GetFloatFromBoxPosition(int32_t aEnumVal
 #define SETCOORD_IA     (SETCOORD_INTEGER | SETCOORD_AUTO)
 #define SETCOORD_LAE    (SETCOORD_LENGTH | SETCOORD_AUTO | SETCOORD_ENUMERATED)
 
 // changes aCoord iff it returns true
 static bool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
                        const nsStyleCoord& aParentCoord,
                        int32_t aMask, nsStyleContext* aStyleContext,
                        nsPresContext* aPresContext,
-                       bool& aCanStoreInRuleTree)
+                       RuleNodeCacheConditions& aConditions)
 {
   bool result = true;
   if (aValue.GetUnit() == eCSSUnit_Null) {
     result = false;
   }
   else if ((((aMask & SETCOORD_LENGTH) != 0) &&
             aValue.IsLengthUnit()) ||
            (((aMask & SETCOORD_CALC_LENGTH_ONLY) != 0) &&
             aValue.IsCalcUnit())) {
     nscoord len = CalcLength(aValue, aStyleContext, aPresContext,
-                             aCanStoreInRuleTree);
+                             aConditions);
     if ((aMask & SETCOORD_CALC_CLAMP_NONNEGATIVE) && len < 0) {
       NS_ASSERTION(aValue.IsCalcUnit(),
                    "parser should have ensured no nonnegative lengths");
       len = 0;
     }
     aCoord.SetCoordValue(len);
   }
   else if (((aMask & SETCOORD_PERCENT) != 0) &&
@@ -806,34 +809,34 @@ static bool SetCoord(const nsCSSValue& a
            (aValue.GetUnit() == eCSSUnit_Auto)) {
     aCoord.SetAutoValue();
   }
   else if ((((aMask & SETCOORD_INHERIT) != 0) &&
             aValue.GetUnit() == eCSSUnit_Inherit) ||
            (((aMask & SETCOORD_UNSET_INHERIT) != 0) &&
             aValue.GetUnit() == eCSSUnit_Unset)) {
     aCoord = aParentCoord;  // just inherit value from parent
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
   }
   else if (((aMask & SETCOORD_NORMAL) != 0) &&
            (aValue.GetUnit() == eCSSUnit_Normal)) {
     aCoord.SetNormalValue();
   }
   else if (((aMask & SETCOORD_NONE) != 0) &&
            (aValue.GetUnit() == eCSSUnit_None)) {
     aCoord.SetNoneValue();
   }
   else if (((aMask & SETCOORD_FACTOR) != 0) &&
            (aValue.GetUnit() == eCSSUnit_Number)) {
     aCoord.SetFactorValue(aValue.GetFloatValue());
   }
   else if (((aMask & SETCOORD_STORE_CALC) != 0) &&
            (aValue.IsCalcUnit())) {
     SpecifiedCalcToComputedCalc(aValue, aCoord, aStyleContext,
-                                aCanStoreInRuleTree);
+                                aConditions);
   }
   else if (aValue.GetUnit() == eCSSUnit_Initial ||
            (aValue.GetUnit() == eCSSUnit_Unset &&
             ((aMask & SETCOORD_UNSET_INITIAL) != 0))) {
     if ((aMask & SETCOORD_INITIAL_AUTO) != 0) {
       aCoord.SetAutoValue();
     }
     else if ((aMask & SETCOORD_INITIAL_ZERO) != 0) {
@@ -891,53 +894,53 @@ static inline bool SetAbsCoord(const nsC
              "does not handle SETCOORD_LENGTH, SETCOORD_INHERIT and "
              "SETCOORD_UNSET_*");
 
   // The values of the following variables will never be used; so it does not
   // matter what to set.
   const nsStyleCoord dummyParentCoord;
   nsStyleContext* dummyStyleContext = nullptr;
   nsPresContext* dummyPresContext = nullptr;
-  bool dummyCanStoreInRuleTree = true;
+  RuleNodeCacheConditions dummyCacheKey;
 
   bool rv = SetCoord(aValue, aCoord, dummyParentCoord, aMask,
                        dummyStyleContext, dummyPresContext,
-                       dummyCanStoreInRuleTree);
-  MOZ_ASSERT(dummyCanStoreInRuleTree,
-             "SetCoord() should not modify dummyCanStoreInRuleTree.");
+                       dummyCacheKey);
+  MOZ_ASSERT(dummyCacheKey.CacheableWithoutDependencies(),
+             "SetCoord() should not modify dummyCacheKey.");
 
   return rv;
 }
 
 /* Given a specified value that might be a pair value, call SetCoord twice,
  * either using each member of the pair, or using the unpaired value twice.
  */
 static bool
 SetPairCoords(const nsCSSValue& aValue,
               nsStyleCoord& aCoordX, nsStyleCoord& aCoordY,
               const nsStyleCoord& aParentX, const nsStyleCoord& aParentY,
               int32_t aMask, nsStyleContext* aStyleContext,
-              nsPresContext* aPresContext, bool& aCanStoreInRuleTree)
+              nsPresContext* aPresContext, RuleNodeCacheConditions& aConditions)
 {
   const nsCSSValue& valX =
     aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mXValue : aValue;
   const nsCSSValue& valY =
     aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mYValue : aValue;
 
   bool cX = SetCoord(valX, aCoordX, aParentX, aMask, aStyleContext,
-                       aPresContext, aCanStoreInRuleTree);
+                       aPresContext, aConditions);
   mozilla::DebugOnly<bool> cY = SetCoord(valY, aCoordY, aParentY, aMask, 
-                       aStyleContext, aPresContext, aCanStoreInRuleTree);
+                       aStyleContext, aPresContext, aConditions);
   MOZ_ASSERT(cX == cY, "changed one but not the other");
   return cX;
 }
 
 static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
                        nsPresContext* aPresContext, nsStyleContext *aContext,
-                       nscolor& aResult, bool& aCanStoreInRuleTree)
+                       nscolor& aResult, RuleNodeCacheConditions& aConditions)
 {
   bool    result = false;
   nsCSSUnit unit = aValue.GetUnit();
 
   if (aValue.IsNumericColorUnit()) {
     aResult = aValue.GetColorValue();
     result = true;
   }
@@ -978,17 +981,17 @@ static bool SetColor(const nsCSSValue& a
           if (aPresContext) {
             aResult = aPresContext->DefaultActiveLinkColor();
             result = true;
           }
           break;
         case NS_COLOR_CURRENTCOLOR:
           // The data computed from this can't be shared in the rule tree
           // because they could be used on a node with a different color
-          aCanStoreInRuleTree = false;
+          aConditions.SetUncacheable();
           if (aContext) {
             aResult = aContext->StyleColor()->mColor;
             result = true;
           }
           break;
         case NS_COLOR_MOZ_DEFAULT_COLOR:
           if (aPresContext) {
             aResult = aPresContext->DefaultColor();
@@ -1005,62 +1008,62 @@ static bool SetColor(const nsCSSValue& a
           NS_NOTREACHED("Should never have an unknown negative colorID.");
           break;
       }
     }
   }
   else if (eCSSUnit_Inherit == unit) {
     aResult = aParentColor;
     result = true;
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
   }
   else if (eCSSUnit_Enumerated == unit &&
            aValue.GetIntValue() == NS_STYLE_COLOR_INHERIT_FROM_BODY) {
     NS_ASSERTION(aPresContext->CompatibilityMode() == eCompatibility_NavQuirks,
                  "Should only get this value in quirks mode");
     // We just grab the color from the prescontext, and rely on the fact that
     // if the body color ever changes all its descendants will get new style
     // contexts (but NOT necessarily new rulenodes).
     aResult = aPresContext->BodyTextColor();
     result = true;
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
   }
   return result;
 }
 
 static void SetGradientCoord(const nsCSSValue& aValue, nsPresContext* aPresContext,
                              nsStyleContext* aContext, nsStyleCoord& aResult,
-                             bool& aCanStoreInRuleTree)
+                             RuleNodeCacheConditions& aConditions)
 {
   // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
   if (!SetCoord(aValue, aResult, nsStyleCoord(),
                 SETCOORD_LPO | SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC,
-                aContext, aPresContext, aCanStoreInRuleTree)) {
+                aContext, aPresContext, aConditions)) {
     NS_NOTREACHED("unexpected unit for gradient anchor point");
     aResult.SetNoneValue();
   }
 }
 
 static void SetGradient(const nsCSSValue& aValue, nsPresContext* aPresContext,
                         nsStyleContext* aContext, nsStyleGradient& aResult,
-                        bool& aCanStoreInRuleTree)
+                        RuleNodeCacheConditions& aConditions)
 {
   MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Gradient,
              "The given data is not a gradient");
 
   const nsCSSValueGradient* gradient = aValue.GetGradientValue();
 
   if (gradient->mIsExplicitSize) {
     SetCoord(gradient->GetRadiusX(), aResult.mRadiusX, nsStyleCoord(),
              SETCOORD_LP | SETCOORD_STORE_CALC,
-             aContext, aPresContext, aCanStoreInRuleTree);
+             aContext, aPresContext, aConditions);
     if (gradient->GetRadiusY().GetUnit() != eCSSUnit_None) {
       SetCoord(gradient->GetRadiusY(), aResult.mRadiusY, nsStyleCoord(),
                SETCOORD_LP | SETCOORD_STORE_CALC,
-               aContext, aPresContext, aCanStoreInRuleTree);
+               aContext, aPresContext, aConditions);
       aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
     } else {
       aResult.mRadiusY = aResult.mRadiusX;
       aResult.mShape = NS_STYLE_GRADIENT_SHAPE_CIRCULAR;
     }
     aResult.mSize = NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE;
   } else if (gradient->mIsRadial) {
     if (gradient->GetRadialShape().GetUnit() == eCSSUnit_Enumerated) {
@@ -1085,52 +1088,52 @@ static void SetGradient(const nsCSSValue
     aResult.mShape = NS_STYLE_GRADIENT_SHAPE_LINEAR;
     aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
   }
 
   aResult.mLegacySyntax = gradient->mIsLegacySyntax;
 
   // bg-position
   SetGradientCoord(gradient->mBgPos.mXValue, aPresContext, aContext,
-                   aResult.mBgPosX, aCanStoreInRuleTree);
+                   aResult.mBgPosX, aConditions);
 
   SetGradientCoord(gradient->mBgPos.mYValue, aPresContext, aContext,
-                   aResult.mBgPosY, aCanStoreInRuleTree);
+                   aResult.mBgPosY, aConditions);
 
   aResult.mRepeating = gradient->mIsRepeating;
 
   // angle
   const nsStyleCoord dummyParentCoord;
   if (!SetCoord(gradient->mAngle, aResult.mAngle, dummyParentCoord, SETCOORD_ANGLE,
-                aContext, aPresContext, aCanStoreInRuleTree)) {
+                aContext, aPresContext, aConditions)) {
     NS_ASSERTION(gradient->mAngle.GetUnit() == eCSSUnit_None,
                  "bad unit for gradient angle");
     aResult.mAngle.SetNoneValue();
   }
 
   // stops
   for (uint32_t i = 0; i < gradient->mStops.Length(); i++) {
     nsStyleGradientStop stop;
     const nsCSSValueGradientStop &valueStop = gradient->mStops[i];
 
     if (!SetCoord(valueStop.mLocation, stop.mLocation,
                   nsStyleCoord(), SETCOORD_LPO | SETCOORD_STORE_CALC,
-                  aContext, aPresContext, aCanStoreInRuleTree)) {
+                  aContext, aPresContext, aConditions)) {
       NS_NOTREACHED("unexpected unit for gradient stop location");
     }
 
     stop.mIsInterpolationHint = valueStop.mIsInterpolationHint;
 
     // inherit is not a valid color for stops, so we pass in a dummy
     // parent color
     NS_ASSERTION(valueStop.mColor.GetUnit() != eCSSUnit_Inherit,
                  "inherit is not a valid color for gradient stops");
     if (!valueStop.mIsInterpolationHint) {
       SetColor(valueStop.mColor, NS_RGB(0, 0, 0), aPresContext,
-              aContext, stop.mColor, aCanStoreInRuleTree);
+              aContext, stop.mColor, aConditions);
     } else {
       // Always initialize to the same color so we don't need to worry
       // about comparisons.
       stop.mColor = NS_RGB(0, 0, 0);
     }
 
     aResult.mStops.AppendElement(stop);
   }
@@ -1171,17 +1174,17 @@ static void SetStyleImageToImageRect(nsS
     cropRect.Set(side, coord);
   }
   aResult.SetCropRect(&cropRect);
 }
 
 static void SetStyleImage(nsStyleContext* aStyleContext,
                           const nsCSSValue& aValue,
                           nsStyleImage& aResult,
-                          bool& aCanStoreInRuleTree)
+                          RuleNodeCacheConditions& aConditions)
 {
   if (aValue.GetUnit() == eCSSUnit_Null) {
     return;
   }
 
   aResult.SetNull();
 
   switch (aValue.GetUnit()) {
@@ -1197,17 +1200,17 @@ static void SetStyleImage(nsStyleContext
         NS_NOTREACHED("-moz-image-rect() is the only expected function");
       }
       break;
     case eCSSUnit_Gradient:
     {
       nsStyleGradient* gradient = new nsStyleGradient();
       if (gradient) {
         SetGradient(aValue, aStyleContext->PresContext(), aStyleContext,
-                    *gradient, aCanStoreInRuleTree);
+                    *gradient, aConditions);
         aResult.SetGradientData(gradient);
       }
       break;
     }
     case eCSSUnit_Element:
       aResult.SetElementId(aValue.GetStringBufferValue());
       break;
     case eCSSUnit_Initial:
@@ -1237,32 +1240,32 @@ static void SetStyleImage(nsStyleContext
 #define SETDSC_UNSET_INHERIT          0x00400000
 #define SETDSC_UNSET_INITIAL          0x00800000
 
 // no caller cares whether aField was changed or not
 template <typename FieldT,
           typename T1, typename T2, typename T3, typename T4, typename T5>
 static void
 SetDiscrete(const nsCSSValue& aValue, FieldT & aField,
-            bool& aCanStoreInRuleTree, uint32_t aMask,
+            RuleNodeCacheConditions& aConditions, uint32_t aMask,
             FieldT aParentValue,
             T1 aInitialValue,
             T2 aAutoValue,
             T3 aNoneValue,
             T4 aNormalValue,
             T5 aSystemFontValue)
 {
   switch (aValue.GetUnit()) {
   case eCSSUnit_Null:
     return;
 
     // every caller of SetDiscrete provides inherit and initial
     // alternatives, so we don't require them to say so in the mask
   case eCSSUnit_Inherit:
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aField = aParentValue;
     return;
 
   case eCSSUnit_Initial:
     aField = aInitialValue;
     return;
 
     // every caller provides one or other of these alternatives,
@@ -1307,17 +1310,17 @@ SetDiscrete(const nsCSSValue& aValue, Fi
     if (aMask & SETDSC_SYSTEM_FONT) {
       aField = aSystemFontValue;
       return;
     }
     break;
 
   case eCSSUnit_Unset:
     if (aMask & SETDSC_UNSET_INHERIT) {
-      aCanStoreInRuleTree = false;
+      aConditions.SetUncacheable();
       aField = aParentValue;
       return;
     }
     if (aMask & SETDSC_UNSET_INITIAL) {
       aField = aInitialValue;
       return;
     }
     break;
@@ -1332,17 +1335,17 @@ SetDiscrete(const nsCSSValue& aValue, Fi
 // flags for SetFactor
 #define SETFCT_POSITIVE 0x01        // assert value is >= 0.0f
 #define SETFCT_OPACITY  0x02        // clamp value to [0.0f .. 1.0f]
 #define SETFCT_NONE     0x04        // allow _None (uses aInitialValue).
 #define SETFCT_UNSET_INHERIT  0x00400000
 #define SETFCT_UNSET_INITIAL  0x00800000
 
 static void
-SetFactor(const nsCSSValue& aValue, float& aField, bool& aCanStoreInRuleTree,
+SetFactor(const nsCSSValue& aValue, float& aField, RuleNodeCacheConditions& aConditions,
           float aParentValue, float aInitialValue, uint32_t aFlags = 0)
 {
   switch (aValue.GetUnit()) {
   case eCSSUnit_Null:
     return;
 
   case eCSSUnit_Number:
     aField = aValue.GetFloatValue();
@@ -1355,34 +1358,34 @@ SetFactor(const nsCSSValue& aValue, floa
       if (aField < 0.0f)
         aField = 0.0f;
       if (aField > 1.0f)
         aField = 1.0f;
     }
     return;
 
   case eCSSUnit_Inherit:
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aField = aParentValue;
     return;
 
   case eCSSUnit_Initial:
     aField = aInitialValue;
     return;
 
   case eCSSUnit_None:
     if (aFlags & SETFCT_NONE) {
       aField = aInitialValue;
       return;
     }
     break;
 
   case eCSSUnit_Unset:
     if (aFlags & SETFCT_UNSET_INHERIT) {
-      aCanStoreInRuleTree = false;
+      aConditions.SetUncacheable();
       aField = aParentValue;
       return;
     }
     if (aFlags & SETFCT_UNSET_INITIAL) {
       aField = aInitialValue;
       return;
     }
     break;
@@ -2182,17 +2185,17 @@ nsRuleNode::ResolveVariableReferences(co
 
     // XXX Should pass in sheet here (see bug 952338).
     parser.ParsePropertyWithVariableReferences(
         tokenStream->mPropertyID, tokenStream->mShorthandPropertyID,
         tokenStream->mTokenStream, variables, aRuleData,
         tokenStream->mSheetURI, tokenStream->mBaseURI,
         tokenStream->mSheetPrincipal, nullptr,
         tokenStream->mLineNumber, tokenStream->mLineOffset);
-    aRuleData->mCanStoreInRuleTree = false;
+    aRuleData->mConditions.SetUncacheable();
     anyTokenStreams = true;
   }
 
   return anyTokenStreams;
 }
 
 const void*
 nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
@@ -2314,17 +2317,17 @@ nsRuleNode::WalkRuleTree(const nsStyleSt
                                 detail != eRuleFullMixed &&
                                 detail != eRuleFullInherited),
                "can't have start struct and be fully specified");
 
   bool isReset = nsCachedStyleData::IsReset(aSID);
   if (!highestNode)
     highestNode = rootNode;
 
-  if (!ruleData.mCanStoreInRuleTree)
+  if (!ruleData.mConditions.CacheableWithoutDependencies())
     detail = eRulePartialMixed; // Treat as though some data is specified to avoid
                                 // the optimizations and force data computation.
 
   if (detail == eRuleNone && startStruct) {
     // We specified absolutely no rule information, but a parent rule in the tree
     // specified all the rule information.  We set a bit along the branch from our
     // node in the tree to the node that specified the data that tells nodes on that
     // branch that they never need to examine their rules for this particular struct type
@@ -2376,27 +2379,28 @@ nsRuleNode::WalkRuleTree(const nsStyleSt
     else
       // We are the root.  In the case of fonts, the default values just
       // come from the pres context.
       return SetDefaultOnRoot(aSID, aContext);
   }
 
   typedef const void* (nsRuleNode::*ComputeFunc)(void*, const nsRuleData*,
                                                  nsStyleContext*, nsRuleNode*,
-                                                 RuleDetail, const bool);
+                                                 RuleDetail,
+                                                 const RuleNodeCacheConditions);
   static const ComputeFunc sComputeFuncs[] = {
 #define STYLE_STRUCT(name, checkdata_cb) &nsRuleNode::Compute##name##Data,
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
   };
 
   // We need to compute the data from the information that the rules specified.
   return (this->*sComputeFuncs[aSID])(startStruct, &ruleData, aContext,
                                       highestNode, detail,
-                                      ruleData.mCanStoreInRuleTree);
+                                      ruleData.mConditions);
 }
 
 const void*
 nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
 {
   switch (aSID) {
     case eStyleStruct_Font:
     {
@@ -2575,46 +2579,46 @@ nsRuleNode::SetDefaultOnRoot(const nsSty
   NS_ASSERTION(aRuleDetail != eRuleFullInherited,                             \
                "should not have bothered calling Compute*Data");              \
                                                                               \
   nsStyleContext* parentContext = aContext->GetParent();                      \
                                                                               \
   nsStyle##type_* data_ = nullptr;                                            \
   mozilla::Maybe<nsStyle##type_> maybeFakeParentData;                         \
   const nsStyle##type_* parentdata_ = nullptr;                                \
-  bool canStoreInRuleTree = aCanStoreInRuleTree;                              \
+  RuleNodeCacheConditions conditions = aConditions;                                      \
                                                                               \
-  /* If |canStoreInRuleTree| might be true by the time we're done, we */      \
+  /* If |conditions.Cacheable()| might be true by the time we're done, we */    \
   /* can't call parentContext->Style##type_() since it could recur into */    \
   /* setting the same struct on the same rule node, causing a leak. */        \
   if (aRuleDetail != eRuleFullReset &&                                        \
       (!aStartStruct || (aRuleDetail != eRulePartialReset &&                  \
                          aRuleDetail != eRuleNone))) {                        \
     if (parentContext) {                                                      \
       parentdata_ = parentContext->Style##type_();                            \
     } else {                                                                  \
       maybeFakeParentData.emplace ctorargs_;                                  \
       parentdata_ = maybeFakeParentData.ptr();                                \
     }                                                                         \
   }                                                                           \
   if (eStyleStruct_##type_ == eStyleStruct_Variables)                         \
     /* no need to copy construct an nsStyleVariables, as we will copy */      \
-    /* inherited variables (and set canStoreInRuleTree to false) in */        \
+    /* inherited variables (and call SetUncacheable()) in */                  \
     /* ComputeVariablesData */                                                \
     data_ = new (mPresContext) nsStyle##type_ ctorargs_;                      \
   else if (aStartStruct)                                                      \
     /* We only need to compute the delta between this computed data and */    \
     /* our computed data. */                                                  \
     data_ = new (mPresContext)                                                \
             nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct));      \
   else {                                                                      \
     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {     \
       /* No question. We will have to inherit. Go ahead and init */           \
       /* with inherited vals from parent. */                                  \
-      canStoreInRuleTree = false;                                             \
+      conditions.SetUncacheable();                                              \
       if (parentdata_)                                                        \
         data_ = new (mPresContext) nsStyle##type_(*parentdata_);              \
       else                                                                    \
         data_ = new (mPresContext) nsStyle##type_ ctorargs_;                  \
     }                                                                         \
     else                                                                      \
       data_ = new (mPresContext) nsStyle##type_ ctorargs_;                    \
   }                                                                           \
@@ -2648,46 +2652,47 @@ nsRuleNode::SetDefaultOnRoot(const nsSty
   if (aStartStruct)                                                           \
     /* We only need to compute the delta between this computed data and */    \
     /* our computed data. */                                                  \
     data_ = new (mPresContext)                                                \
             nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct));      \
   else                                                                        \
     data_ = new (mPresContext) nsStyle##type_ ctorargs_;                      \
                                                                               \
-  /* If |canStoreInRuleTree| might be true by the time we're done, we */      \
+  /* If |conditions.Cacheable()| might be true by the time we're done, we */    \
   /* can't call parentContext->Style##type_() since it could recur into */    \
   /* setting the same struct on the same rule node, causing a leak. */        \
   mozilla::Maybe<nsStyle##type_> maybeFakeParentData;                         \
   const nsStyle##type_* parentdata_ = data_;                                  \
   if (aRuleDetail != eRuleFullReset &&                                        \
       aRuleDetail != eRulePartialReset &&                                     \
       aRuleDetail != eRuleNone) {                                             \
     if (parentContext) {                                                      \
       parentdata_ = parentContext->Style##type_();                            \
     } else {                                                                  \
       maybeFakeParentData.emplace ctorargs_;                                  \
       parentdata_ = maybeFakeParentData.ptr();                                \
     }                                                                         \
   }                                                                           \
-  bool canStoreInRuleTree = aCanStoreInRuleTree;
+  RuleNodeCacheConditions conditions = aConditions;
 
 /**
  * End an nsRuleNode::Compute*Data function for an inherited struct.
  *
  * @param type_ The nsStyle* type this function computes.
  * @param data_ Variable holding the result of this function.
  */
 #define COMPUTE_END_INHERITED(type_, data_)                                   \
-  NS_POSTCONDITION(!canStoreInRuleTree || aRuleDetail == eRuleFullReset ||    \
+  NS_POSTCONDITION(!conditions.CacheableWithoutDependencies() ||                \
+                   aRuleDetail == eRuleFullReset ||                           \
                    (aStartStruct && aRuleDetail == eRulePartialReset),        \
-                   "canStoreInRuleTree must be false for inherited structs "  \
-                   "unless all properties have been specified with values "   \
-                   "other than inherit");                                     \
-  if (canStoreInRuleTree) {                                                   \
+                   "conditions.CacheableWithoutDependencies() must be false "   \
+                   "for inherited structs unless all properties have been "   \
+                   "specified with values other than inherit");               \
+  if (conditions.CacheableWithoutDependencies()) {                              \
     /* We were fully specified and can therefore be cached right on the */    \
     /* rule node. */                                                          \
     if (!aHighestNode->mStyleData.mInheritedData) {                           \
       aHighestNode->mStyleData.mInheritedData =                               \
         new (mPresContext) nsInheritedStyleData;                              \
     }                                                                         \
     NS_ASSERTION(!aHighestNode->mStyleData.mInheritedData->                   \
                    mStyleStructs[eStyleStruct_##type_],                       \
@@ -2707,40 +2712,51 @@ nsRuleNode::SetDefaultOnRoot(const nsSty
 
 /**
  * End an nsRuleNode::Compute*Data function for a reset struct.
  *
  * @param type_ The nsStyle* type this function computes.
  * @param data_ Variable holding the result of this function.
  */
 #define COMPUTE_END_RESET(type_, data_)                                       \
-  NS_POSTCONDITION(!canStoreInRuleTree ||                                     \
+  NS_POSTCONDITION(!conditions.CacheableWithoutDependencies() ||                \
                    aRuleDetail == eRuleNone ||                                \
                    aRuleDetail == eRulePartialReset ||                        \
                    aRuleDetail == eRuleFullReset,                             \
-                   "canStoreInRuleTree must be false for reset structs "      \
-                   "if any properties were specified as inherit");            \
-  if (!canStoreInRuleTree)                                                    \
-    /* We can't be cached in the rule node.  We have to be put right */       \
-    /* on the style context. */                                               \
-    aContext->SetStyle(eStyleStruct_##type_, data_);                          \
-  else {                                                                      \
+                   "conditions.CacheableWithoutDependencies() must be false "   \
+                   "for reset structs if any properties were specified as "   \
+                   "inherit");                                                \
+  if (conditions.CacheableWithoutDependencies()) {                              \
     /* We were fully specified and can therefore be cached right on the */    \
     /* rule node. */                                                          \
     if (!aHighestNode->mStyleData.mResetData) {                               \
       aHighestNode->mStyleData.mResetData =                                   \
-        new (mPresContext) nsResetStyleData;                                  \
+        new (mPresContext) nsConditionalResetStyleData;                       \
     }                                                                         \
     NS_ASSERTION(!aHighestNode->mStyleData.mResetData->                       \
-                   mStyleStructs[eStyleStruct_##type_],                       \
+                   GetStyleData(eStyleStruct_##type_),                        \
                  "Going to leak style data");                                 \
     aHighestNode->mStyleData.mResetData->                                     \
-      mStyleStructs[eStyleStruct_##type_] = data_;                            \
+      SetStyleData(eStyleStruct_##type_, data_);                              \
     /* Propagate the bit down. */                                             \
     PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_);         \
+  } else if (conditions.Cacheable()) {                                        \
+    if (!mStyleData.mResetData) {                                             \
+      mStyleData.mResetData = new (mPresContext) nsConditionalResetStyleData; \
+    }                                                                         \
+    mStyleData.mResetData->                                                   \
+      SetStyleData(eStyleStruct_##type_, mPresContext, data_, conditions);    \
+    /* Tell the style context that it doesn't own the data */                 \
+    aContext->                                                                \
+      AddStyleBit(nsCachedStyleData::GetBitForSID(eStyleStruct_##type_));     \
+    aContext->SetStyle(eStyleStruct_##type_, data_);                          \
+  } else {                                                                    \
+    /* We can't be cached in the rule node.  We have to be put right */       \
+    /* on the style context. */                                               \
+    aContext->SetStyle(eStyleStruct_##type_, data_);                          \
   }                                                                           \
                                                                               \
   return data_;
 
 // This function figures out how much scaling should be suppressed to
 // satisfy scriptminsize. This is our attempt to implement
 // http://www.w3.org/TR/MathML2/chapter3.html#id.3.3.4.2.2
 // This is called after mScriptLevel, mScriptMinSize and mScriptSizeMultiplier
@@ -3066,46 +3082,46 @@ nsRuleNode::FindNextLargerFontSize(nscoo
 struct SetFontSizeCalcOps : public css::BasicCoordCalcOps,
                             public css::NumbersAlreadyNormalizedOps
 {
   // The parameters beyond aValue that we need for CalcLengthWith.
   const nscoord mParentSize;
   const nsStyleFont* const mParentFont;
   nsPresContext* const mPresContext;
   const bool mAtRoot;
-  bool& mCanStoreInRuleTree;
+  RuleNodeCacheConditions& mConditions;
 
   SetFontSizeCalcOps(nscoord aParentSize, const nsStyleFont* aParentFont,
                      nsPresContext* aPresContext, bool aAtRoot,
-                     bool& aCanStoreInRuleTree)
+                     RuleNodeCacheConditions& aConditions)
     : mParentSize(aParentSize),
       mParentFont(aParentFont),
       mPresContext(aPresContext),
       mAtRoot(aAtRoot),
-      mCanStoreInRuleTree(aCanStoreInRuleTree)
+      mConditions(aConditions)
   {
   }
 
   result_type ComputeLeafValue(const nsCSSValue& aValue)
   {
     nscoord size;
     if (aValue.IsLengthUnit()) {
       // Note that font-based length units use the parent's size
       // unadjusted for scriptlevel changes. A scriptlevel change
       // between us and the parent is simply ignored.
       size = CalcLengthWith(aValue, mParentSize,
                             mParentFont,
                             nullptr, mPresContext, mAtRoot,
-                            true, mCanStoreInRuleTree);
+                            true, mConditions);
       if (!aValue.IsRelativeLengthUnit() && mParentFont->mAllowZoom) {
         size = nsStyleFont::ZoomText(mPresContext, size);
       }
     }
     else if (eCSSUnit_Percent == aValue.GetUnit()) {
-      mCanStoreInRuleTree = false;
+      mConditions.SetUncacheable();
       // Note that % units use the parent's size unadjusted for scriptlevel
       // changes. A scriptlevel change between us and the parent is simply
       // ignored.
       // aValue.GetPercentValue() may be negative for, e.g., calc(-50%)
       size = NSCoordSaturatingMultiply(mParentSize, aValue.GetPercentValue());
     } else {
       MOZ_ASSERT(false, "unexpected value");
       size = mParentSize;
@@ -3121,17 +3137,17 @@ nsRuleNode::SetFontSize(nsPresContext* a
                         const nsStyleFont* aFont,
                         const nsStyleFont* aParentFont,
                         nscoord* aSize,
                         const nsFont& aSystemFont,
                         nscoord aParentSize,
                         nscoord aScriptLevelAdjustedParentSize,
                         bool aUsedStartStruct,
                         bool aAtRoot,
-                        bool& aCanStoreInRuleTree)
+                        RuleNodeCacheConditions& aConditions)
 {
   // If false, means that *aSize has not been zoomed.  If true, means that
   // *aSize has been zoomed iff aParentFont->mAllowZoom is true.
   bool sizeIsZoomedAccordingToParent = false;
 
   int32_t baseSize = (int32_t) aPresContext->
     GetDefaultFont(aFont->mGenericID, aFont->mLanguage)->size;
   const nsCSSValue* sizeValue = aRuleData->ValueForFontSize();
@@ -3144,17 +3160,17 @@ nsRuleNode::SetFontSize(nsPresContext* a
                        aPresContext, eFontSize_CSS);
     }
     else if (NS_STYLE_FONT_SIZE_XXXLARGE == value) {
       // <font size="7"> is not specified in CSS, so we don't use eFontSize_CSS.
       *aSize = CalcFontPointSize(value, baseSize, aPresContext);
     }
     else if (NS_STYLE_FONT_SIZE_LARGER  == value ||
              NS_STYLE_FONT_SIZE_SMALLER == value) {
-      aCanStoreInRuleTree = false;
+      aConditions.SetUncacheable();
 
       // Un-zoom so we use the tables correctly.  We'll then rezoom due
       // to the |zoom = true| above.
       // Note that relative units here use the parent's size unadjusted
       // for scriptlevel changes. A scriptlevel change between us and the parent
       // is simply ignored.
       nscoord parentSize = aParentSize;
       if (aParentFont->mAllowZoom) {
@@ -3179,34 +3195,34 @@ nsRuleNode::SetFontSize(nsPresContext* a
       NS_NOTREACHED("unexpected value");
     }
   }
   else if (sizeValue->IsLengthUnit() ||
            sizeValue->GetUnit() == eCSSUnit_Percent ||
            sizeValue->IsCalcUnit()) {
     SetFontSizeCalcOps ops(aParentSize, aParentFont,
                            aPresContext, aAtRoot,
-                           aCanStoreInRuleTree);
+                           aConditions);
     *aSize = css::ComputeCalc(*sizeValue, ops);
     if (*aSize < 0) {
       MOZ_ASSERT(sizeValue->IsCalcUnit(),
                  "negative lengths and percents should be rejected by parser");
       *aSize = 0;
     }
     // The calc ops will always zoom its result according to the value
     // of aParentFont->mAllowZoom.
     sizeIsZoomedAccordingToParent = true;
   }
   else if (eCSSUnit_System_Font == sizeValue->GetUnit()) {
     // this becomes our cascading size
     *aSize = aSystemFont.size;
   }
   else if (eCSSUnit_Inherit == sizeValue->GetUnit() ||
            eCSSUnit_Unset == sizeValue->GetUnit()) {
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     // We apply scriptlevel change for this case, because the default is
     // to inherit and we don't want explicit "inherit" to differ from the
     // default.
     *aSize = aScriptLevelAdjustedParentSize;
     sizeIsZoomedAccordingToParent = true;
   }
   else if (eCSSUnit_Initial == sizeValue->GetUnit()) {
     // The initial value is 'medium', which has magical sizing based on
@@ -3218,17 +3234,17 @@ nsRuleNode::SetFontSize(nsPresContext* a
     // if aUsedStartStruct is true, then every single property in the
     // font struct is being set all at once. This means scriptlevel is not
     // going to have any influence on the font size; there is no need to
     // do anything here.
     if (!aUsedStartStruct && aParentSize != aScriptLevelAdjustedParentSize) {
       // There was no rule affecting the size but the size has been
       // affected by the parent's size via scriptlevel change. So we cannot
       // store the data in the rule tree.
-      aCanStoreInRuleTree = false;
+      aConditions.SetUncacheable();
       *aSize = aScriptLevelAdjustedParentSize;
       sizeIsZoomedAccordingToParent = true;
     } else {
       return;
     }
   }
 
   // We want to zoom the cascaded size so that em-based measurements,
@@ -3250,17 +3266,17 @@ static int8_t ClampTo8Bit(int32_t aValue
   return int8_t(aValue);
 }
 
 /* static */ void
 nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
                     uint8_t aGenericFontID, const nsRuleData* aRuleData,
                     const nsStyleFont* aParentFont,
                     nsStyleFont* aFont, bool aUsedStartStruct,
-                    bool& aCanStoreInRuleTree)
+                    RuleNodeCacheConditions& aConditions)
 {
   bool atRoot = !aContext->GetParent();
 
   // -x-text-zoom: none, inherit, initial
   bool allowZoom;
   const nsCSSValue* textZoomValue = aRuleData->ValueForTextZoom();
   if (eCSSUnit_Null != textZoomValue->GetUnit()) {
     if (eCSSUnit_Inherit == textZoomValue->GetUnit()) {
@@ -3397,17 +3413,17 @@ nsRuleNode::SetFont(nsPresContext* aPres
   }
   else if (eCSSUnit_System_Font == familyValue->GetUnit()) {
     aFont->mFont.fontlist = systemFont.fontlist;
     aFont->mFont.systemFont = true;
     aFont->mGenericID = kGenericFont_NONE;
   }
   else if (eCSSUnit_Inherit == familyValue->GetUnit() ||
            eCSSUnit_Unset == familyValue->GetUnit()) {
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aFont->mFont.fontlist = aParentFont->mFont.fontlist;
     aFont->mFont.systemFont = aParentFont->mFont.systemFont;
     aFont->mGenericID = aParentFont->mGenericID;
   }
   else if (eCSSUnit_Initial == familyValue->GetUnit()) {
     aFont->mFont.fontlist = defaultVariableFont->fontlist;
     aFont->mFont.systemFont = defaultVariableFont->systemFont;
     aFont->mGenericID = kGenericFont_NONE;
@@ -3418,43 +3434,43 @@ nsRuleNode::SetFont(nsPresContext* aPres
   // to be careful not to touch it when we're called directly from
   // ComputeFontData, because we could have a start struct.
   if (aGenericFontID != kGenericFont_NONE) {
     aFont->mGenericID = aGenericFontID;
   }
 
   // -moz-math-variant: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForMathVariant(), aFont->mMathVariant,
-              aCanStoreInRuleTree,
+              aConditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               aParentFont->mMathVariant, NS_MATHML_MATHVARIANT_NONE,
               0, 0, 0, 0);
 
   // -moz-math-display: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForMathDisplay(), aFont->mMathDisplay,
-              aCanStoreInRuleTree,
+              aConditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               aParentFont->mMathDisplay, NS_MATHML_DISPLAYSTYLE_INLINE,
               0, 0, 0, 0);
 
   // font-smoothing: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForOsxFontSmoothing(),
-              aFont->mFont.smoothing, aCanStoreInRuleTree,
+              aFont->mFont.smoothing, aConditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               aParentFont->mFont.smoothing,
               defaultVariableFont->smoothing,
               0, 0, 0, 0);
 
   // font-style: enum, inherit, initial, -moz-system-font
   if (aFont->mMathVariant != NS_MATHML_MATHVARIANT_NONE) {
     // -moz-math-variant overrides font-style
     aFont->mFont.style = NS_FONT_STYLE_NORMAL;
   } else {
     SetDiscrete(*aRuleData->ValueForFontStyle(),
-                aFont->mFont.style, aCanStoreInRuleTree,
+                aFont->mFont.style, aConditions,
                 SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
                 aParentFont->mFont.style,
                 defaultVariableFont->style,
                 0, 0, 0, systemFont.style);
   }
 
   // font-weight: int, enum, inherit, initial, -moz-system-font
   // special handling for enum
@@ -3465,50 +3481,50 @@ nsRuleNode::SetFont(nsPresContext* aPres
   } else if (eCSSUnit_Enumerated == weightValue->GetUnit()) {
     int32_t value = weightValue->GetIntValue();
     switch (value) {
       case NS_STYLE_FONT_WEIGHT_NORMAL:
       case NS_STYLE_FONT_WEIGHT_BOLD:
         aFont->mFont.weight = value;
         break;
       case NS_STYLE_FONT_WEIGHT_BOLDER: {
-        aCanStoreInRuleTree = false;
+        aConditions.SetUncacheable();
         int32_t inheritedValue = aParentFont->mFont.weight;
         if (inheritedValue <= 300) {
           aFont->mFont.weight = 400;
         } else if (inheritedValue <= 500) {
           aFont->mFont.weight = 700;
         } else {
           aFont->mFont.weight = 900;
         }
         break;
       }
       case NS_STYLE_FONT_WEIGHT_LIGHTER: {
-        aCanStoreInRuleTree = false;
+        aConditions.SetUncacheable();
         int32_t inheritedValue = aParentFont->mFont.weight;
         if (inheritedValue < 600) {
           aFont->mFont.weight = 100;
         } else if (inheritedValue < 800) {
           aFont->mFont.weight = 400;
         } else {
           aFont->mFont.weight = 700;
         }
         break;
       }
     }
   } else
-    SetDiscrete(*weightValue, aFont->mFont.weight, aCanStoreInRuleTree,
+    SetDiscrete(*weightValue, aFont->mFont.weight, aConditions,
                 SETDSC_INTEGER | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
                 aParentFont->mFont.weight,
                 defaultVariableFont->weight,
                 0, 0, 0, systemFont.weight);
 
   // font-stretch: enum, inherit, initial, -moz-system-font
   SetDiscrete(*aRuleData->ValueForFontStretch(),
-              aFont->mFont.stretch, aCanStoreInRuleTree,
+              aFont->mFont.stretch, aConditions,
               SETDSC_SYSTEM_FONT | SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               aParentFont->mFont.stretch,
               defaultVariableFont->stretch,
               0, 0, 0, systemFont.stretch);
 
   // Compute scriptlevel, scriptminsize and scriptsizemultiplier now so
   // they're available for font-size computation.
 
@@ -3517,81 +3533,81 @@ nsRuleNode::SetFont(nsPresContext* aPres
   if (scriptMinSizeValue->IsLengthUnit()) {
     // scriptminsize in font units (em, ex) has to be interpreted relative
     // to the parent font, or the size definitions are circular and we
     //
     aFont->mScriptMinSize =
       CalcLengthWith(*scriptMinSizeValue, aParentFont->mSize,
                      aParentFont,
                      nullptr, aPresContext, atRoot, true,
-                     aCanStoreInRuleTree);
+                     aConditions);
   }
 
   // -moz-script-size-multiplier: factor, inherit, initial
   SetFactor(*aRuleData->ValueForScriptSizeMultiplier(),
             aFont->mScriptSizeMultiplier,
-            aCanStoreInRuleTree, aParentFont->mScriptSizeMultiplier,
+            aConditions, aParentFont->mScriptSizeMultiplier,
             NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER,
             SETFCT_POSITIVE | SETFCT_UNSET_INHERIT);
 
   // -moz-script-level: integer, number, inherit
   const nsCSSValue* scriptLevelValue = aRuleData->ValueForScriptLevel();
   if (eCSSUnit_Integer == scriptLevelValue->GetUnit()) {
     // "relative"
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel + scriptLevelValue->GetIntValue());
   }
   else if (eCSSUnit_Number == scriptLevelValue->GetUnit()) {
     // "absolute"
     aFont->mScriptLevel = ClampTo8Bit(int32_t(scriptLevelValue->GetFloatValue()));
   }
   else if (eCSSUnit_Auto == scriptLevelValue->GetUnit()) {
     // auto
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel +
                                       (aParentFont->mMathDisplay ==
                                        NS_MATHML_DISPLAYSTYLE_INLINE ? 1 : 0));
   }
   else if (eCSSUnit_Inherit == scriptLevelValue->GetUnit() ||
            eCSSUnit_Unset == scriptLevelValue->GetUnit()) {
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aFont->mScriptLevel = aParentFont->mScriptLevel;
   }
   else if (eCSSUnit_Initial == scriptLevelValue->GetUnit()) {
     aFont->mScriptLevel = 0;
   }
 
   // font-kerning: none, enum, inherit, initial, -moz-system-font
   SetDiscrete(*aRuleData->ValueForFontKerning(),
-              aFont->mFont.kerning, aCanStoreInRuleTree,
+              aFont->mFont.kerning, aConditions,
               SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
               aParentFont->mFont.kerning,
               defaultVariableFont->kerning,
               0, 0, 0, systemFont.kerning);
 
   // font-synthesis: none, enum (bit field), inherit, initial, -moz-system-font
   SetDiscrete(*aRuleData->ValueForFontSynthesis(),
-              aFont->mFont.synthesis, aCanStoreInRuleTree,
+              aFont->mFont.synthesis, aConditions,
               SETDSC_NONE | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
                 SETDSC_UNSET_INHERIT,
               aParentFont->mFont.synthesis,
               defaultVariableFont->synthesis,
               0, 0, 0, systemFont.synthesis);
 
   // font-variant-alternates: normal, enum (bit field) + functions, inherit,
   //                          initial, -moz-system-font
   const nsCSSValue* variantAlternatesValue =
     aRuleData->ValueForFontVariantAlternates();
   int32_t variantAlternates = 0;
 
   switch (variantAlternatesValue->GetUnit()) {
   case eCSSUnit_Inherit:
   case eCSSUnit_Unset:
     aFont->mFont.CopyAlternates(aParentFont->mFont);
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     break;
 
   case eCSSUnit_Initial:
   case eCSSUnit_Normal:
     aFont->mFont.variantAlternates = 0;
     aFont->mFont.alternateValues.Clear();
     aFont->mFont.featureValueLookup = nullptr;
     break;
@@ -3617,57 +3633,57 @@ nsRuleNode::SetFont(nsPresContext* aPres
     break;
 
   default:
     break;
   }
 
   // font-variant-caps: normal, enum, inherit, initial, -moz-system-font
   SetDiscrete(*aRuleData->ValueForFontVariantCaps(),
-              aFont->mFont.variantCaps, aCanStoreInRuleTree,
+              aFont->mFont.variantCaps, aConditions,
               SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
                 SETDSC_UNSET_INHERIT,
               aParentFont->mFont.variantCaps,
               defaultVariableFont->variantCaps,
               0, 0, 0, systemFont.variantCaps);
 
   // font-variant-east-asian: normal, enum (bit field), inherit, initial,
   //                          -moz-system-font
   SetDiscrete(*aRuleData->ValueForFontVariantEastAsian(),
-              aFont->mFont.variantEastAsian, aCanStoreInRuleTree,
+              aFont->mFont.variantEastAsian, aConditions,
               SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
                 SETDSC_UNSET_INHERIT,
               aParentFont->mFont.variantEastAsian,
               defaultVariableFont->variantEastAsian,
               0, 0, 0, systemFont.variantEastAsian);
 
   // font-variant-ligatures: normal, none, enum (bit field), inherit, initial,
   //                         -moz-system-font
   SetDiscrete(*aRuleData->ValueForFontVariantLigatures(),
-              aFont->mFont.variantLigatures, aCanStoreInRuleTree,
+              aFont->mFont.variantLigatures, aConditions,
               SETDSC_NORMAL | SETDSC_NONE | SETDSC_ENUMERATED |
                 SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
               aParentFont->mFont.variantLigatures,
               defaultVariableFont->variantLigatures,
               0, NS_FONT_VARIANT_LIGATURES_NONE, 0, systemFont.variantLigatures);
 
   // font-variant-numeric: normal, enum (bit field), inherit, initial,
   //                       -moz-system-font
   SetDiscrete(*aRuleData->ValueForFontVariantNumeric(),
-              aFont->mFont.variantNumeric, aCanStoreInRuleTree,
+              aFont->mFont.variantNumeric, aConditions,
               SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
                 SETDSC_UNSET_INHERIT,
               aParentFont->mFont.variantNumeric,
               defaultVariableFont->variantNumeric,
               0, 0, 0, systemFont.variantNumeric);
 
   // font-variant-position: normal, enum, inherit, initial,
   //                        -moz-system-font
   SetDiscrete(*aRuleData->ValueForFontVariantPosition(),
-              aFont->mFont.variantPosition, aCanStoreInRuleTree,
+              aFont->mFont.variantPosition, aConditions,
               SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
                 SETDSC_UNSET_INHERIT,
               aParentFont->mFont.variantPosition,
               defaultVariableFont->variantPosition,
               0, 0, 0, systemFont.variantPosition);
 
   // font-feature-settings
   const nsCSSValue* featureSettingsValue =
@@ -3679,17 +3695,17 @@ nsRuleNode::SetFont(nsPresContext* aPres
 
   case eCSSUnit_Normal:
   case eCSSUnit_Initial:
     aFont->mFont.fontFeatureSettings.Clear();
     break;
 
   case eCSSUnit_Inherit:
   case eCSSUnit_Unset:
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aFont->mFont.fontFeatureSettings = aParentFont->mFont.fontFeatureSettings;
     break;
 
   case eCSSUnit_System_Font:
     aFont->mFont.fontFeatureSettings = systemFont.fontFeatureSettings;
     break;
 
   case eCSSUnit_PairList:
@@ -3703,17 +3719,17 @@ nsRuleNode::SetFont(nsPresContext* aPres
     break;
   }
 
   // font-language-override
   const nsCSSValue* languageOverrideValue =
     aRuleData->ValueForFontLanguageOverride();
   if (eCSSUnit_Inherit == languageOverrideValue->GetUnit() ||
       eCSSUnit_Unset == languageOverrideValue->GetUnit()) {
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aFont->mFont.languageOverride = aParentFont->mFont.languageOverride;
   } else if (eCSSUnit_Normal == languageOverrideValue->GetUnit() ||
              eCSSUnit_Initial == languageOverrideValue->GetUnit()) {
     aFont->mFont.languageOverride.Truncate();
   } else if (eCSSUnit_System_Font == languageOverrideValue->GetUnit()) {
     aFont->mFont.languageOverride = systemFont.languageOverride;
   } else if (eCSSUnit_String == languageOverrideValue->GetUnit()) {
     languageOverrideValue->GetStringValue(aFont->mFont.languageOverride);
@@ -3725,31 +3741,31 @@ nsRuleNode::SetFont(nsPresContext* aPres
   scriptLevelAdjustedParentSize =
     ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
                            &scriptLevelAdjustedUnconstrainedParentSize);
   NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
                "If we have a start struct, we should have reset everything coming in here");
   SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
               &aFont->mSize,
               systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
-              aUsedStartStruct, atRoot, aCanStoreInRuleTree);
+              aUsedStartStruct, atRoot, aConditions);
   if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize &&
       scriptLevelAdjustedParentSize == scriptLevelAdjustedUnconstrainedParentSize) {
     // Fast path: we have not been affected by scriptminsize so we don't
     // need to call SetFontSize again to compute the
     // scriptminsize-unconstrained size. This is OK even if we have a
     // start struct, because if we have a start struct then 'font-size'
     // was specified and so scriptminsize has no effect.
     aFont->mScriptUnconstrainedSize = aFont->mSize;
   } else {
     SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
                 &aFont->mScriptUnconstrainedSize,
                 systemFont, aParentFont->mScriptUnconstrainedSize,
                 scriptLevelAdjustedUnconstrainedParentSize,
-                aUsedStartStruct, atRoot, aCanStoreInRuleTree);
+                aUsedStartStruct, atRoot, aConditions);
   }
   NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
                "scriptminsize should never be making things bigger");
 
   nscoord fontSize = aFont->mSize;
 
   // enforce the user' specified minimum font-size on the value that we expose
   // (but don't change font-size:0, since that would unhide hidden text)
@@ -3766,17 +3782,17 @@ nsRuleNode::SetFont(nsPresContext* aPres
   aFont->mFont.size = fontSize;
 
   // font-size-adjust: number, none, inherit, initial, -moz-system-font
   const nsCSSValue* sizeAdjustValue = aRuleData->ValueForFontSizeAdjust();
   if (eCSSUnit_System_Font == sizeAdjustValue->GetUnit()) {
     aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
   } else
     SetFactor(*sizeAdjustValue, aFont->mFont.sizeAdjust,
-              aCanStoreInRuleTree, aParentFont->mFont.sizeAdjust, -1.0f,
+              aConditions, aParentFont->mFont.sizeAdjust, -1.0f,
               SETFCT_NONE | SETFCT_UNSET_INHERIT);
 }
 
 /* static */ void
 nsRuleNode::ComputeFontFeatures(const nsCSSValuePairList *aFeaturesList,
                                 nsTArray<gfxFontFeature>& aFeatureSettings)
 {
   aFeatureSettings.Clear();
@@ -3839,17 +3855,16 @@ nsRuleNode::SetGenericFont(nsPresContext
     aPresContext->GetDefaultFont(aGenericFontID, aFont->mLanguage);
   nsStyleFont parentFont(*defaultFont, aPresContext);
   if (higherContext) {
     const nsStyleFont* tmpFont = higherContext->StyleFont();
     parentFont = *tmpFont;
   }
   *aFont = parentFont;
 
-  bool dummy;
   uint32_t fontBit = nsCachedStyleData::GetBitForSID(eStyleStruct_Font);
 
   // use placement new[] on the result of alloca() to allocate a
   // variable-sized stack array, including execution of constructors,
   // and use an RAII class to run the destructors too.
   size_t nprops = nsCSSProps::PropertyCountInStruct(eStyleStruct_Font);
   void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
 
@@ -3883,16 +3898,17 @@ nsRuleNode::SetGenericFont(nsPresContext
 
     // Avoid unnecessary operations in SetFont().  But we care if it's
     // the final value that we're computing.
     if (i != 0)
       ruleData.ValueForFontFamily()->Reset();
 
     ResolveVariableReferences(eStyleStruct_Font, &ruleData, aContext);
 
+    RuleNodeCacheConditions dummy;
     nsRuleNode::SetFont(aPresContext, context,
                         aGenericFontID, &ruleData, &parentFont, aFont,
                         false, dummy);
 
     parentFont = *aFont;
   }
 
   if (higherContext && contextPath.Length() > 1) {
@@ -3904,17 +3920,17 @@ nsRuleNode::SetGenericFont(nsPresContext
 }
 
 const void*
 nsRuleNode::ComputeFontData(void* aStartStruct,
                             const nsRuleData* aRuleData,
                             nsStyleContext* aContext,
                             nsRuleNode* aHighestNode,
                             const RuleDetail aRuleDetail,
-                            const bool aCanStoreInRuleTree)
+                            const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(Font, (mPresContext), font, parentFont)
 
   // NOTE:  The |aRuleDetail| passed in is a little bit conservative due
   // to the -moz-system-font property.  We really don't need to consider
   // it here in determining whether to cache in the rule tree.  However,
   // we do need to consider it in WalkRuleTree when deciding whether to
   // walk further up the tree.  So this means that when the font struct
@@ -3995,21 +4011,21 @@ nsRuleNode::ComputeFontData(void* aStart
     }
   }
 
   // Now compute our font struct
   if (generic == kGenericFont_NONE) {
     // continue the normal processing
     nsRuleNode::SetFont(mPresContext, aContext, generic,
                         aRuleData, parentFont, font,
-                        aStartStruct != nullptr, canStoreInRuleTree);
+                        aStartStruct != nullptr, conditions);
   }
   else {
     // re-calculate the font as a generic font
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
                                font);
   }
 
   COMPUTE_END_INHERITED(Font, font)
 }
 
 template <typename T>
@@ -4024,17 +4040,17 @@ inline uint32_t ListLength(const T* aLis
 }
 
 
 
 already_AddRefed<nsCSSShadowArray>
 nsRuleNode::GetShadowData(const nsCSSValueList* aList,
                           nsStyleContext* aContext,
                           bool aIsBoxShadow,
-                          bool& aCanStoreInRuleTree)
+                          RuleNodeCacheConditions& aConditions)
 {
   uint32_t arrayLength = ListLength(aList);
 
   MOZ_ASSERT(arrayLength > 0,
              "Non-null text-shadow list, yet we counted 0 items.");
   nsRefPtr<nsCSSShadowArray> shadowList =
     new(arrayLength) nsCSSShadowArray(arrayLength);
 
@@ -4047,54 +4063,54 @@ nsRuleNode::GetShadowData(const nsCSSVal
        aList;
        aList = aList->mNext, ++item) {
     MOZ_ASSERT(aList->mValue.GetUnit() == eCSSUnit_Array,
                "expecting a plain array value");
     nsCSSValue::Array *arr = aList->mValue.GetArrayValue();
     // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
     unitOK = SetCoord(arr->Item(0), tempCoord, nsStyleCoord(),
                       SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
-                      aContext, mPresContext, aCanStoreInRuleTree);
+                      aContext, mPresContext, aConditions);
     NS_ASSERTION(unitOK, "unexpected unit");
     item->mXOffset = tempCoord.GetCoordValue();
 
     unitOK = SetCoord(arr->Item(1), tempCoord, nsStyleCoord(),
                       SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
-                      aContext, mPresContext, aCanStoreInRuleTree);
+                      aContext, mPresContext, aConditions);
     NS_ASSERTION(unitOK, "unexpected unit");
     item->mYOffset = tempCoord.GetCoordValue();
 
     // Blur radius is optional in the current box-shadow spec
     if (arr->Item(2).GetUnit() != eCSSUnit_Null) {
       unitOK = SetCoord(arr->Item(2), tempCoord, nsStyleCoord(),
                         SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY |
                           SETCOORD_CALC_CLAMP_NONNEGATIVE,
-                        aContext, mPresContext, aCanStoreInRuleTree);
+                        aContext, mPresContext, aConditions);
       NS_ASSERTION(unitOK, "unexpected unit");
       item->mRadius = tempCoord.GetCoordValue();
     } else {
       item->mRadius = 0;
     }
 
     // Find the spread radius
     if (aIsBoxShadow && arr->Item(3).GetUnit() != eCSSUnit_Null) {
       unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(),
                         SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
-                        aContext, mPresContext, aCanStoreInRuleTree);
+                        aContext, mPresContext, aConditions);
       NS_ASSERTION(unitOK, "unexpected unit");
       item->mSpread = tempCoord.GetCoordValue();
     } else {
       item->mSpread = 0;
     }
 
     if (arr->Item(4).GetUnit() != eCSSUnit_Null) {
       item->mHasColor = true;
       // 2nd argument can be bogus since inherit is not a valid color
       unitOK = SetColor(arr->Item(4), 0, mPresContext, aContext, item->mColor,
-                        aCanStoreInRuleTree);
+                        aConditions);
       NS_ASSERTION(unitOK, "unexpected unit");
     }
 
     if (aIsBoxShadow && arr->Item(5).GetUnit() == eCSSUnit_Enumerated) {
       NS_ASSERTION(arr->Item(5).GetIntValue() == NS_STYLE_BOX_SHADOW_INSET,
                    "invalid keyword type for box shadow");
       item->mInset = true;
     } else {
@@ -4106,76 +4122,76 @@ nsRuleNode::GetShadowData(const nsCSSVal
 }
 
 const void*
 nsRuleNode::ComputeTextData(void* aStartStruct,
                             const nsRuleData* aRuleData,
                             nsStyleContext* aContext,
                             nsRuleNode* aHighestNode,
                             const RuleDetail aRuleDetail,
-                            const bool aCanStoreInRuleTree)
+                            const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(Text, (), text, parentText)
 
   // tab-size: integer, inherit
   SetDiscrete(*aRuleData->ValueForTabSize(),
-              text->mTabSize, canStoreInRuleTree,
+              text->mTabSize, conditions,
               SETDSC_INTEGER | SETDSC_UNSET_INHERIT, parentText->mTabSize,
               NS_STYLE_TABSIZE_INITIAL, 0, 0, 0, 0);
 
   // letter-spacing: normal, length, inherit
   SetCoord(*aRuleData->ValueForLetterSpacing(),
            text->mLetterSpacing, parentText->mLetterSpacing,
            SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
              SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INHERIT,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
 
   // text-shadow: none, list, inherit, initial
   const nsCSSValue* textShadowValue = aRuleData->ValueForTextShadow();
   if (textShadowValue->GetUnit() != eCSSUnit_Null) {
     text->mTextShadow = nullptr;
 
     // Don't need to handle none/initial explicitly: The above assignment
     // takes care of that
     if (textShadowValue->GetUnit() == eCSSUnit_Inherit ||
         textShadowValue->GetUnit() == eCSSUnit_Unset) {
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       text->mTextShadow = parentText->mTextShadow;
     } else if (textShadowValue->GetUnit() == eCSSUnit_List ||
                textShadowValue->GetUnit() == eCSSUnit_ListDep) {
       // List of arrays
       text->mTextShadow = GetShadowData(textShadowValue->GetListValue(),
-                                        aContext, false, canStoreInRuleTree);
+                                        aContext, false, conditions);
     }
   }
 
   // line-height: normal, number, length, percent, inherit
   const nsCSSValue* lineHeightValue = aRuleData->ValueForLineHeight();
   if (eCSSUnit_Percent == lineHeightValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     // Use |mFont.size| to pick up minimum font size.
     text->mLineHeight.SetCoordValue(
         NSToCoordRound(float(aContext->StyleFont()->mFont.size) *
                        lineHeightValue->GetPercentValue()));
   }
   else if (eCSSUnit_Initial == lineHeightValue->GetUnit() ||
            eCSSUnit_System_Font == lineHeightValue->GetUnit()) {
     text->mLineHeight.SetNormalValue();
   }
   else {
     SetCoord(*lineHeightValue, text->mLineHeight, parentText->mLineHeight,
              SETCOORD_LEH | SETCOORD_FACTOR | SETCOORD_NORMAL |
                SETCOORD_UNSET_INHERIT,
-             aContext, mPresContext, canStoreInRuleTree);
+             aContext, mPresContext, conditions);
     if (lineHeightValue->IsLengthUnit() &&
         !lineHeightValue->IsRelativeLengthUnit()) {
       nscoord lh = nsStyleFont::ZoomText(mPresContext,
                                          text->mLineHeight.GetCoordValue());
 
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       const nsStyleFont *font = aContext->StyleFont();
       nscoord minimumFontSize = mPresContext->MinFontSize(font->mLanguage);
 
       if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
         if (font->mSize != 0) {
           lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
         } else {
           lh = minimumFontSize;
@@ -4190,24 +4206,24 @@ nsRuleNode::ComputeTextData(void* aStart
   // NOTE: string is not implemented yet.
   const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
   text->mTextAlignTrue = false;
   if (eCSSUnit_String == textAlignValue->GetUnit()) {
     NS_NOTYETIMPLEMENTED("align string");
   } else if (eCSSUnit_Enumerated == textAlignValue->GetUnit() &&
              NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT ==
                textAlignValue->GetIntValue()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     uint8_t parentAlign = parentText->mTextAlign;
     text->mTextAlign = (NS_STYLE_TEXT_ALIGN_DEFAULT == parentAlign) ?
       NS_STYLE_TEXT_ALIGN_CENTER : parentAlign;
   } else if (eCSSUnit_Enumerated == textAlignValue->GetUnit() &&
              NS_STYLE_TEXT_ALIGN_MATCH_PARENT ==
                textAlignValue->GetIntValue()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     nsStyleContext* parent = aContext->GetParent();
     if (parent) {
       uint8_t parentAlign = parentText->mTextAlign;
       uint8_t parentDirection = parent->StyleVisibility()->mDirection;
       switch (parentAlign) {
         case NS_STYLE_TEXT_ALIGN_DEFAULT:
           text->mTextAlign = parentDirection == NS_STYLE_DIRECTION_RTL ?
             NS_STYLE_TEXT_ALIGN_RIGHT : NS_STYLE_TEXT_ALIGN_LEFT;
@@ -4234,17 +4250,17 @@ nsRuleNode::ComputeTextData(void* aStart
         }
       } else if (eCSSUnit_String == textAlignValue->GetUnit()) {
         NS_NOTYETIMPLEMENTED("align string");
       }
     } else if (eCSSUnit_Inherit == textAlignValue->GetUnit() ||
                eCSSUnit_Unset == textAlignValue->GetUnit()) {
       text->mTextAlignTrue = parentText->mTextAlignTrue;
     }
-    SetDiscrete(*textAlignValue, text->mTextAlign, canStoreInRuleTree,
+    SetDiscrete(*textAlignValue, text->mTextAlign, conditions,
                 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
                 parentText->mTextAlign,
                 NS_STYLE_TEXT_ALIGN_DEFAULT, 0, 0, 0, 0);
   }
 
   // text-align-last: enum, pair(enum), inherit, initial
   const nsCSSValue* textAlignLastValue = aRuleData->ValueForTextAlignLast();
   text->mTextAlignLastTrue = false;
@@ -4258,137 +4274,137 @@ nsRuleNode::ComputeTextData(void* aStart
         textAlignLastValue = &textAlignLastValuePair.mYValue;
       }
     }
   } else if (eCSSUnit_Inherit == textAlignLastValue->GetUnit() ||
              eCSSUnit_Unset == textAlignLastValue->GetUnit()) {
     text->mTextAlignLastTrue = parentText->mTextAlignLastTrue;
   }
   SetDiscrete(*textAlignLastValue, text->mTextAlignLast,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mTextAlignLast,
               NS_STYLE_TEXT_ALIGN_AUTO, 0, 0, 0, 0);
 
   // text-indent: length, percent, calc, inherit, initial
   SetCoord(*aRuleData->ValueForTextIndent(), text->mTextIndent, parentText->mTextIndent,
            SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
              SETCOORD_UNSET_INHERIT,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
 
   // text-transform: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForTextTransform(), text->mTextTransform, canStoreInRuleTree,
+  SetDiscrete(*aRuleData->ValueForTextTransform(), text->mTextTransform, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mTextTransform,
               NS_STYLE_TEXT_TRANSFORM_NONE, 0, 0, 0, 0);
 
   // white-space: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForWhiteSpace(), text->mWhiteSpace, canStoreInRuleTree,
+  SetDiscrete(*aRuleData->ValueForWhiteSpace(), text->mWhiteSpace, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mWhiteSpace,
               NS_STYLE_WHITESPACE_NORMAL, 0, 0, 0, 0);
 
   // word-break: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForWordBreak(), text->mWordBreak, canStoreInRuleTree,
+  SetDiscrete(*aRuleData->ValueForWordBreak(), text->mWordBreak, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mWordBreak,
               NS_STYLE_WORDBREAK_NORMAL, 0, 0, 0, 0);
 
   // word-spacing: normal, length, inherit
   nsStyleCoord tempCoord;
   const nsCSSValue* wordSpacingValue = aRuleData->ValueForWordSpacing();
   if (SetCoord(*wordSpacingValue, tempCoord,
                nsStyleCoord(parentText->mWordSpacing,
                             nsStyleCoord::CoordConstructor),
                SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
                  SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INHERIT,
-               aContext, mPresContext, canStoreInRuleTree)) {
+               aContext, mPresContext, conditions)) {
     if (tempCoord.GetUnit() == eStyleUnit_Coord) {
       text->mWordSpacing = tempCoord.GetCoordValue();
     } else if (tempCoord.GetUnit() == eStyleUnit_Normal) {
       text->mWordSpacing = 0;
     } else {
       NS_NOTREACHED("unexpected unit");
     }
   } else {
     NS_ASSERTION(wordSpacingValue->GetUnit() == eCSSUnit_Null,
                  "unexpected unit");
   }
 
   // word-wrap: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForWordWrap(), text->mWordWrap, canStoreInRuleTree,
+  SetDiscrete(*aRuleData->ValueForWordWrap(), text->mWordWrap, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mWordWrap,
               NS_STYLE_WORDWRAP_NORMAL, 0, 0, 0, 0);
 
   // hyphens: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForHyphens(), text->mHyphens, canStoreInRuleTree,
+  SetDiscrete(*aRuleData->ValueForHyphens(), text->mHyphens, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mHyphens,
               NS_STYLE_HYPHENS_MANUAL, 0, 0, 0, 0);
 
   // ruby-align: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForRubyAlign(),
-              text->mRubyAlign, canStoreInRuleTree,
+              text->mRubyAlign, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mRubyAlign,
               NS_STYLE_RUBY_ALIGN_SPACE_AROUND, 0, 0, 0, 0);
 
   // ruby-position: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForRubyPosition(),
-              text->mRubyPosition, canStoreInRuleTree,
+              text->mRubyPosition, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mRubyPosition,
               NS_STYLE_RUBY_POSITION_OVER, 0, 0, 0, 0);
 
   // text-size-adjust: none, auto, inherit, initial
   SetDiscrete(*aRuleData->ValueForTextSizeAdjust(), text->mTextSizeAdjust,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_NONE | SETDSC_AUTO | SETDSC_UNSET_INHERIT,
               parentText->mTextSizeAdjust,
               NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // initial value
               NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // auto value
               NS_STYLE_TEXT_SIZE_ADJUST_NONE, // none value
               0, 0);
 
   // text-combine-upright: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForTextCombineUpright(),
               text->mTextCombineUpright,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mTextCombineUpright,
               NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE, 0, 0, 0, 0);
 
   // -moz-text-discard: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForControlCharacterVisibility(),
               text->mControlCharacterVisibility,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mControlCharacterVisibility,
               NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN, 0, 0, 0, 0);
 
   COMPUTE_END_INHERITED(Text, text)
 }
 
 const void*
 nsRuleNode::ComputeTextResetData(void* aStartStruct,
                                  const nsRuleData* aRuleData,
                                  nsStyleContext* aContext,
                                  nsRuleNode* aHighestNode,
                                  const RuleDetail aRuleDetail,
-                                 const bool aCanStoreInRuleTree)
+                                 const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(TextReset, (), text, parentText)
 
   // vertical-align: enum, length, percent, calc, inherit
   const nsCSSValue* verticalAlignValue = aRuleData->ValueForVerticalAlign();
   if (!SetCoord(*verticalAlignValue, text->mVerticalAlign,
                 parentText->mVerticalAlign,
                 SETCOORD_LPH | SETCOORD_ENUMERATED | SETCOORD_STORE_CALC,
-                aContext, mPresContext, canStoreInRuleTree)) {
+                aContext, mPresContext, conditions)) {
     if (eCSSUnit_Initial == verticalAlignValue->GetUnit() ||
         eCSSUnit_Unset == verticalAlignValue->GetUnit()) {
       text->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE,
                                        eStyleUnit_Enumerated);
     }
   }
 
   // text-decoration-line: enum (bit field), inherit, initial
@@ -4403,29 +4419,29 @@ nsRuleNode::ComputeTextResetData(void* a
       if (underlineLinks) {
         text->mTextDecorationLine |= NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
       }
       else {
         text->mTextDecorationLine &= ~NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
       }
     }
   } else if (eCSSUnit_Inherit == decorationLineValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     text->mTextDecorationLine = parentText->mTextDecorationLine;
   } else if (eCSSUnit_Initial == decorationLineValue->GetUnit() ||
              eCSSUnit_Unset == decorationLineValue->GetUnit()) {
     text->mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
   }
 
   // text-decoration-color: color, string, enum, inherit, initial
   const nsCSSValue* decorationColorValue =
     aRuleData->ValueForTextDecorationColor();
   nscolor decorationColor;
   if (eCSSUnit_Inherit == decorationColorValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     if (parentContext) {
       bool isForeground;
       parentText->GetDecorationColor(decorationColor, isForeground);
       if (isForeground) {
         text->SetDecorationColor(parentContext->StyleColor()->mColor);
       } else {
         text->SetDecorationColor(decorationColor);
       }
@@ -4433,17 +4449,17 @@ nsRuleNode::ComputeTextResetData(void* a
       text->SetDecorationColorToForeground();
     }
   }
   else if (eCSSUnit_EnumColor == decorationColorValue->GetUnit() &&
            decorationColorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
     text->SetDecorationColorToForeground();
   }
   else if (SetColor(*decorationColorValue, 0, mPresContext, aContext,
-                    decorationColor, canStoreInRuleTree)) {
+                    decorationColor, conditions)) {
     text->SetDecorationColor(decorationColor);
   }
   else if (eCSSUnit_Initial == decorationColorValue->GetUnit() ||
            eCSSUnit_Unset == decorationColorValue->GetUnit() ||
            eCSSUnit_Enumerated == decorationColorValue->GetUnit()) {
     MOZ_ASSERT(eCSSUnit_Enumerated != decorationColorValue->GetUnit() ||
                decorationColorValue->GetIntValue() ==
                  NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,
@@ -4453,35 +4469,35 @@ nsRuleNode::ComputeTextResetData(void* a
 
   // text-decoration-style: enum, inherit, initial
   const nsCSSValue* decorationStyleValue =
     aRuleData->ValueForTextDecorationStyle();
   if (eCSSUnit_Enumerated == decorationStyleValue->GetUnit()) {
     text->SetDecorationStyle(decorationStyleValue->GetIntValue());
   } else if (eCSSUnit_Inherit == decorationStyleValue->GetUnit()) {
     text->SetDecorationStyle(parentText->GetDecorationStyle());
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
   } else if (eCSSUnit_Initial == decorationStyleValue->GetUnit() ||
              eCSSUnit_Unset == decorationStyleValue->GetUnit()) {
     text->SetDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID);
   }
 
   // text-overflow: enum, string, pair(enum|string), inherit, initial
   const nsCSSValue* textOverflowValue =
     aRuleData->ValueForTextOverflow();
   if (eCSSUnit_Initial == textOverflowValue->GetUnit() ||
       eCSSUnit_Unset == textOverflowValue->GetUnit()) {
     text->mTextOverflow = nsStyleTextOverflow();
   } else if (eCSSUnit_Inherit == textOverflowValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     text->mTextOverflow = parentText->mTextOverflow;
   } else if (eCSSUnit_Enumerated == textOverflowValue->GetUnit()) {
     // A single enumerated value.
     SetDiscrete(*textOverflowValue, text->mTextOverflow.mRight.mType,
-                canStoreInRuleTree,
+                conditions,
                 SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
                 NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
     text->mTextOverflow.mRight.mString.Truncate();
     text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
     text->mTextOverflow.mLeft.mString.Truncate();
     text->mTextOverflow.mLogicalDirections = true;
   } else if (eCSSUnit_String == textOverflowValue->GetUnit()) {
     // A single string value.
@@ -4494,68 +4510,68 @@ nsRuleNode::ComputeTextResetData(void* a
     // Two values were specified.
     text->mTextOverflow.mLogicalDirections = false;
     const nsCSSValuePair& textOverflowValuePair =
       textOverflowValue->GetPairValue();
 
     const nsCSSValue *textOverflowLeftValue = &textOverflowValuePair.mXValue;
     if (eCSSUnit_Enumerated == textOverflowLeftValue->GetUnit()) {
       SetDiscrete(*textOverflowLeftValue, text->mTextOverflow.mLeft.mType,
-                  canStoreInRuleTree,
+                  conditions,
                   SETDSC_ENUMERATED, parentText->mTextOverflow.mLeft.mType,
                   NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
       text->mTextOverflow.mLeft.mString.Truncate();
     } else if (eCSSUnit_String == textOverflowLeftValue->GetUnit()) {
       textOverflowLeftValue->GetStringValue(text->mTextOverflow.mLeft.mString);
       text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
     }
 
     const nsCSSValue *textOverflowRightValue = &textOverflowValuePair.mYValue;
     if (eCSSUnit_Enumerated == textOverflowRightValue->GetUnit()) {
       SetDiscrete(*textOverflowRightValue, text->mTextOverflow.mRight.mType,
-                  canStoreInRuleTree,
+                  conditions,
                   SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
                   NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
       text->mTextOverflow.mRight.mString.Truncate();
     } else if (eCSSUnit_String == textOverflowRightValue->GetUnit()) {
       textOverflowRightValue->GetStringValue(text->mTextOverflow.mRight.mString);
       text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
     }
   }
 
   // unicode-bidi: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForUnicodeBidi(), text->mUnicodeBidi, canStoreInRuleTree,
+  SetDiscrete(*aRuleData->ValueForUnicodeBidi(), text->mUnicodeBidi, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentText->mUnicodeBidi,
               NS_STYLE_UNICODE_BIDI_NORMAL, 0, 0, 0, 0);
 
   COMPUTE_END_RESET(TextReset, text)
 }
 
 const void*
 nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
                                      const nsRuleData* aRuleData,
                                      nsStyleContext* aContext,
                                      nsRuleNode* aHighestNode,
                                      const RuleDetail aRuleDetail,
-                                     const bool aCanStoreInRuleTree)
+                                     const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(UserInterface, (), ui, parentUI)
 
   // cursor: enum, url, inherit
   const nsCSSValue* cursorValue = aRuleData->ValueForCursor();
   nsCSSUnit cursorUnit = cursorValue->GetUnit();
   if (cursorUnit != eCSSUnit_Null) {
     delete [] ui->mCursorArray;
     ui->mCursorArray = nullptr;
     ui->mCursorArrayLength = 0;
 
     if (cursorUnit == eCSSUnit_Inherit ||
         cursorUnit == eCSSUnit_Unset) {
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       ui->mCursor = parentUI->mCursor;
       ui->CopyCursorArrayFrom(*parentUI);
     }
     else if (cursorUnit == eCSSUnit_Initial) {
       ui->mCursor = NS_STYLE_CURSOR_AUTO;
     }
     else {
       // The parser will never create a list that is *all* URL values --
@@ -4597,81 +4613,81 @@ nsRuleNode::ComputeUserInterfaceData(voi
       NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated,
                    "Unexpected fallback value at end of cursor list");
       ui->mCursor = list->mValue.GetIntValue();
     }
   }
 
   // user-input: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForUserInput(),
-              ui->mUserInput, canStoreInRuleTree,
+              ui->mUserInput, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentUI->mUserInput,
               NS_STYLE_USER_INPUT_AUTO, 0, 0, 0, 0);
 
   // user-modify: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForUserModify(),
-              ui->mUserModify, canStoreInRuleTree,
+              ui->mUserModify, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentUI->mUserModify,
               NS_STYLE_USER_MODIFY_READ_ONLY,
               0, 0, 0, 0);
 
   // user-focus: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForUserFocus(),
-              ui->mUserFocus, canStoreInRuleTree,
+              ui->mUserFocus, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentUI->mUserFocus,
               NS_STYLE_USER_FOCUS_NONE, 0, 0, 0, 0);
 
   // -moz-window-dragging: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForWindowDragging(),
-              ui->mWindowDragging, canStoreInRuleTree,
+              ui->mWindowDragging, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentUI->mWindowDragging,
               NS_STYLE_WINDOW_DRAGGING_NO_DRAG, 0, 0, 0, 0);
 
   COMPUTE_END_INHERITED(UserInterface, ui)
 }
 
 const void*
 nsRuleNode::ComputeUIResetData(void* aStartStruct,
                                const nsRuleData* aRuleData,
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
                                const RuleDetail aRuleDetail,
-                               const bool aCanStoreInRuleTree)
+                               const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(UIReset, (), ui, parentUI)
 
   // user-select: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForUserSelect(),
-              ui->mUserSelect, canStoreInRuleTree,
+              ui->mUserSelect, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentUI->mUserSelect,
               NS_STYLE_USER_SELECT_AUTO, 0, 0, 0, 0);
 
   // ime-mode: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForImeMode(),
-              ui->mIMEMode, canStoreInRuleTree,
+              ui->mIMEMode, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentUI->mIMEMode,
               NS_STYLE_IME_MODE_AUTO, 0, 0, 0, 0);
 
   // force-broken-image-icons: integer, inherit, initial
   SetDiscrete(*aRuleData->ValueForForceBrokenImageIcon(),
               ui->mForceBrokenImageIcon,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
               parentUI->mForceBrokenImageIcon,
               0, 0, 0, 0, 0);
 
   // -moz-window-shadow: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForWindowShadow(),
-              ui->mWindowShadow, canStoreInRuleTree,
+              ui->mWindowShadow, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentUI->mWindowShadow,
               NS_STYLE_WINDOW_SHADOW_DEFAULT, 0, 0, 0, 0);
 
   COMPUTE_END_RESET(UIReset, ui)
 }
 
 // Information about each transition or animation property that is
@@ -4726,17 +4742,17 @@ struct TransitionPropData {
 
 static uint32_t
 CountTransitionProps(const TransitionPropInfo* aInfo,
                      TransitionPropData* aData,
                      size_t aLength,
                      nsStyleDisplay* aDisplay,
                      const nsStyleDisplay* aParentDisplay,
                      const nsRuleData* aRuleData,
-                     bool& aCanStoreInRuleTree)
+                     RuleNodeCacheConditions& aConditions)
 {
   // The four transition properties or eight animation properties are
   // stored in nsCSSDisplay in a single array for all properties.  The
   // number of transitions is equal to the number of items in the
   // longest property's value.  Properties that have fewer values than
   // the longest are filled in by repeating the list.  However, this
   // repetition does not extend the computed value of that particular
   // property (for purposes of inheritance, or, in our code, for when
@@ -4785,17 +4801,17 @@ CountTransitionProps(const TransitionPro
     //      that property are specified by the parent, but only those
     //      that were explicitly specified
     //    - otherwise, count the number of values specified in displayData
 
 
     // calculate number of elements
     if (data.unit == eCSSUnit_Inherit) {
       data.num = aParentDisplay->*(info.sdCount);
-      aCanStoreInRuleTree = false;
+      aConditions.SetUncacheable();
     } else if (data.list) {
       data.num = ListLength(data.list);
     } else {
       data.num = aDisplay->*(info.sdCount);
     }
     if (data.num > numTransitions)
       numTransitions = data.num;
   }
@@ -4847,17 +4863,17 @@ ComputeTimingFunction(const nsCSSValue& 
 }
 
 const void*
 nsRuleNode::ComputeDisplayData(void* aStartStruct,
                                const nsRuleData* aRuleData,
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
                                const RuleDetail aRuleDetail,
-                               const bool aCanStoreInRuleTree)
+                               const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(Display, (), display, parentDisplay)
 
   // We may have ended up with aStartStruct's values of mDisplay and
   // mFloats, but those may not be correct if our style data overrides
   // its position or float properties.  Reset to mOriginalDisplay and
   // mOriginalFloats; it if turns out we still need the display/floats
   // adjustments we'll do them below.
@@ -4875,17 +4891,17 @@ nsRuleNode::ComputeDisplayData(void* aSt
 #define FOR_ALL_TRANSITION_PROPS(var_) \
                                       for (uint32_t var_ = 0; var_ < 4; ++var_)
 
   // CSS Transitions
   uint32_t numTransitions =
     CountTransitionProps(transitionPropInfo, transitionPropData,
                          ArrayLength(transitionPropData),
                          display, parentDisplay, aRuleData,
-                         canStoreInRuleTree);
+                         conditions);
 
   display->mTransitions.SetLength(numTransitions);
 
   FOR_ALL_TRANSITION_PROPS(p) {
     const TransitionPropInfo& i = transitionPropInfo[p];
     TransitionPropData& d = transitionPropData[p];
 
     display->*(i.sdCount) = d.num;
@@ -4898,18 +4914,18 @@ nsRuleNode::ComputeDisplayData(void* aSt
     if (i >= delay.num) {
       transition->SetDelay(display->mTransitions[i % delay.num].GetDelay());
     } else if (delay.unit == eCSSUnit_Inherit) {
       // FIXME (Bug 522599) (for all transition properties): write a test that
       // detects when this was wrong for i >= delay.num if parent had
       // count for this property not equal to length
       MOZ_ASSERT(i < parentDisplay->mTransitionDelayCount,
                  "delay.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       transition->SetDelay(parentDisplay->mTransitions[i].GetDelay());
     } else if (delay.unit == eCSSUnit_Initial ||
                delay.unit == eCSSUnit_Unset) {
       transition->SetDelay(0.0);
     } else if (delay.list) {
       switch (delay.list->mValue.GetUnit()) {
         case eCSSUnit_Seconds:
           transition->SetDelay(PR_MSEC_PER_SEC *
@@ -4924,18 +4940,18 @@ nsRuleNode::ComputeDisplayData(void* aSt
     }
 
     if (i >= duration.num) {
       transition->SetDuration(
         display->mTransitions[i % duration.num].GetDuration());
     } else if (duration.unit == eCSSUnit_Inherit) {
       MOZ_ASSERT(i < parentDisplay->mTransitionDurationCount,
                  "duration.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       transition->SetDuration(parentDisplay->mTransitions[i].GetDuration());
     } else if (duration.unit == eCSSUnit_Initial ||
                duration.unit == eCSSUnit_Unset) {
       transition->SetDuration(0.0);
     } else if (duration.list) {
       switch (duration.list->mValue.GetUnit()) {
         case eCSSUnit_Seconds:
           transition->SetDuration(PR_MSEC_PER_SEC *
@@ -4949,18 +4965,18 @@ nsRuleNode::ComputeDisplayData(void* aSt
       }
     }
 
     if (i >= property.num) {
       transition->CopyPropertyFrom(display->mTransitions[i % property.num]);
     } else if (property.unit == eCSSUnit_Inherit) {
       MOZ_ASSERT(i < parentDisplay->mTransitionPropertyCount,
                  "property.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       transition->CopyPropertyFrom(parentDisplay->mTransitions[i]);
     } else if (property.unit == eCSSUnit_Initial ||
                property.unit == eCSSUnit_Unset) {
       transition->SetProperty(eCSSPropertyExtra_all_properties);
     } else if (property.unit == eCSSUnit_None) {
       transition->SetProperty(eCSSPropertyExtra_no_properties);
     } else if (property.list) {
       const nsCSSValue &val = property.list->mValue;
@@ -4984,18 +5000,18 @@ nsRuleNode::ComputeDisplayData(void* aSt
     }
 
     if (i >= timingFunction.num) {
       transition->SetTimingFunction(
         display->mTransitions[i % timingFunction.num].GetTimingFunction());
     } else if (timingFunction.unit == eCSSUnit_Inherit) {
       MOZ_ASSERT(i < parentDisplay->mTransitionTimingFunctionCount,
                  "timingFunction.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       transition->SetTimingFunction(
         parentDisplay->mTransitions[i].GetTimingFunction());
     } else if (timingFunction.unit == eCSSUnit_Initial ||
                timingFunction.unit == eCSSUnit_Unset) {
       transition->SetTimingFunction(
         nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
     } else if (timingFunction.list) {
       ComputeTimingFunction(timingFunction.list->mValue,
@@ -5031,17 +5047,17 @@ nsRuleNode::ComputeDisplayData(void* aSt
     for (uint32_t var_ = 0; var_ < 8; ++var_)
 
   // CSS Animations.
 
   uint32_t numAnimations =
     CountTransitionProps(animationPropInfo, animationPropData,
                          ArrayLength(animationPropData),
                          display, parentDisplay, aRuleData,
-                         canStoreInRuleTree);
+                         conditions);
 
   display->mAnimations.SetLength(numAnimations);
 
   FOR_ALL_ANIMATION_PROPS(p) {
     const TransitionPropInfo& i = animationPropInfo[p];
     TransitionPropData& d = animationPropData[p];
 
     display->*(i.sdCount) = d.num;
@@ -5054,18 +5070,18 @@ nsRuleNode::ComputeDisplayData(void* aSt
     if (i >= animDelay.num) {
       animation->SetDelay(display->mAnimations[i % animDelay.num].GetDelay());
     } else if (animDelay.unit == eCSSUnit_Inherit) {
       // FIXME (Bug 522599) (for all animation properties): write a test that
       // detects when this was wrong for i >= animDelay.num if parent had
       // count for this property not equal to length
       MOZ_ASSERT(i < parentDisplay->mAnimationDelayCount,
                  "animDelay.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       animation->SetDelay(parentDisplay->mAnimations[i].GetDelay());
     } else if (animDelay.unit == eCSSUnit_Initial ||
                animDelay.unit == eCSSUnit_Unset) {
       animation->SetDelay(0.0);
     } else if (animDelay.list) {
       switch (animDelay.list->mValue.GetUnit()) {
         case eCSSUnit_Seconds:
           animation->SetDelay(PR_MSEC_PER_SEC *
@@ -5080,18 +5096,18 @@ nsRuleNode::ComputeDisplayData(void* aSt
     }
 
     if (i >= animDuration.num) {
       animation->SetDuration(
         display->mAnimations[i % animDuration.num].GetDuration());
     } else if (animDuration.unit == eCSSUnit_Inherit) {
       MOZ_ASSERT(i < parentDisplay->mAnimationDurationCount,
                  "animDuration.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       animation->SetDuration(parentDisplay->mAnimations[i].GetDuration());
     } else if (animDuration.unit == eCSSUnit_Initial ||
                animDuration.unit == eCSSUnit_Unset) {
       animation->SetDuration(0.0);
     } else if (animDuration.list) {
       switch (animDuration.list->mValue.GetUnit()) {
         case eCSSUnit_Seconds:
           animation->SetDuration(PR_MSEC_PER_SEC *
@@ -5105,18 +5121,18 @@ nsRuleNode::ComputeDisplayData(void* aSt
       }
     }
 
     if (i >= animName.num) {
       animation->SetName(display->mAnimations[i % animName.num].GetName());
     } else if (animName.unit == eCSSUnit_Inherit) {
       MOZ_ASSERT(i < parentDisplay->mAnimationNameCount,
                  "animName.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       animation->SetName(parentDisplay->mAnimations[i].GetName());
     } else if (animName.unit == eCSSUnit_Initial ||
                animName.unit == eCSSUnit_Unset) {
       animation->SetName(EmptyString());
     } else if (animName.list) {
       switch (animName.list->mValue.GetUnit()) {
         case eCSSUnit_Ident: {
           nsDependentString
@@ -5134,90 +5150,90 @@ nsRuleNode::ComputeDisplayData(void* aSt
     }
 
     if (i >= animTimingFunction.num) {
       animation->SetTimingFunction(
         display->mAnimations[i % animTimingFunction.num].GetTimingFunction());
     } else if (animTimingFunction.unit == eCSSUnit_Inherit) {
       MOZ_ASSERT(i < parentDisplay->mAnimationTimingFunctionCount,
                  "animTimingFunction.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       animation->SetTimingFunction(
         parentDisplay->mAnimations[i].GetTimingFunction());
     } else if (animTimingFunction.unit == eCSSUnit_Initial ||
                animTimingFunction.unit == eCSSUnit_Unset) {
       animation->SetTimingFunction(
         nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
     } else if (animTimingFunction.list) {
       ComputeTimingFunction(animTimingFunction.list->mValue,
                             animation->TimingFunctionSlot());
     }
 
     if (i >= animDirection.num) {
       animation->SetDirection(display->mAnimations[i % animDirection.num].GetDirection());
     } else if (animDirection.unit == eCSSUnit_Inherit) {
       MOZ_ASSERT(i < parentDisplay->mAnimationDirectionCount,
                  "animDirection.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       animation->SetDirection(parentDisplay->mAnimations[i].GetDirection());
     } else if (animDirection.unit == eCSSUnit_Initial ||
                animDirection.unit == eCSSUnit_Unset) {
       animation->SetDirection(NS_STYLE_ANIMATION_DIRECTION_NORMAL);
     } else if (animDirection.list) {
       MOZ_ASSERT(animDirection.list->mValue.GetUnit() == eCSSUnit_Enumerated,
                  "Invalid animation-direction unit");
 
       animation->SetDirection(animDirection.list->mValue.GetIntValue());
     }
 
     if (i >= animFillMode.num) {
       animation->SetFillMode(display->mAnimations[i % animFillMode.num].GetFillMode());
     } else if (animFillMode.unit == eCSSUnit_Inherit) {
       MOZ_ASSERT(i < parentDisplay->mAnimationFillModeCount,
                  "animFillMode.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       animation->SetFillMode(parentDisplay->mAnimations[i].GetFillMode());
     } else if (animFillMode.unit ==