Bug 804975 - Part 2: Add a RuleNodeCacheConditions class and use it instead of a boolean canStoreInRuleTree during style computation. r=dbaron
authorCameron McCormack <cam@mcc.id.au>
Tue, 23 Jun 2015 11:48:18 +1000
changeset 280792 b7a0c7012a37e6e2a32e71fbeaede77543acb5ef
parent 280791 1e215a36545b41fd51f0df6311ade2927ad1b62b
child 280793 547f41558cd55d91f106ace3e5f0e3758bc9a5cb
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs804975
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 804975 - Part 2: Add a RuleNodeCacheConditions class and use it instead of a boolean canStoreInRuleTree during style computation. r=dbaron
layout/base/nsDisplayList.cpp
layout/base/nsLayoutUtils.cpp
layout/style/RuleNodeCacheConditions.cpp
layout/style/RuleNodeCacheConditions.h
layout/style/StyleAnimationValue.cpp
layout/style/moz.build
layout/style/nsCSSDataBlock.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleData.cpp
layout/style/nsRuleData.h
layout/style/nsRuleNode.cpp
layout/style/nsRuleNode.h
layout/style/nsStyleTransformMatrix.cpp
layout/style/nsStyleTransformMatrix.h
--- 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();
--- 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;
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"
@@ -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/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,17 @@ 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;
+                aRuleData->mConditions.SetUncacheable();
             }
             nsCSSValue* target = aRuleData->ValueFor(iProp);
             if (target->GetUnit() == eCSSUnit_Null) {
                 const nsCSSValue *val = ValueAtIndex(i);
                 MapSinglePropertyInto(iProp, val, target, aRuleData);
             }
         }
     }
@@ -688,17 +688,17 @@ 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;
+    aRuleData->mConditions.SetUncacheable();
   }
 
   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,17 +490,17 @@ 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;
+  aConditions.SetUncacheable();
   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()) {
@@ -533,71 +534,71 @@ static nscoord CalcLengthWith(const nsCS
   }
   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 +637,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 +763,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 +807,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 +892,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 +979,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 +1006,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 +1086,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 +1172,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 +1198,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 +1238,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 +1308,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 +1333,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 +1356,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 +2183,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 +2315,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 +2377,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 +2577,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 +2650,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 +2710,41 @@ 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;                                  \
     }                                                                         \
     NS_ASSERTION(!aHighestNode->mStyleData.mResetData->                       \
                    mStyleStructs[eStyleStruct_##type_],                       \
                  "Going to leak style data");                                 \
     aHighestNode->mStyleData.mResetData->                                     \
       mStyleStructs[eStyleStruct_##type_] = data_;                            \
     /* Propagate the bit down. */                                             \
     PropagateDependentBit(eStyleStruct_##type_, aHighestNode, 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 +3070,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 +3125,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 +3148,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 +3183,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 +3222,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 +3254,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 +3401,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 +3422,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 +3469,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 +3521,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 +3621,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 +3683,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 +3707,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 +3729,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 +3770,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 +3843,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 +3886,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 +3908,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 +3999,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 +4028,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 +4051,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 +4110,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 +4194,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 +4238,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 +4262,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 +4407,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 +4437,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 +4457,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 +4498,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 +4601,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 +4730,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 +4789,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 +4851,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 +4879,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 +4902,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 +4928,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 +4953,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 +4988,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 +5035,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 +5058,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 +5084,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 +5109,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 +5138,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 == eCSSUnit_Initial ||
                animFillMode.unit == eCSSUnit_Unset) {
       animation->SetFillMode(NS_STYLE_ANIMATION_FILL_MODE_NONE);
     } else if (animFillMode.list) {
       MOZ_ASSERT(animFillMode.list->mValue.GetUnit() == eCSSUnit_Enumerated,
                  "Invalid animation-fill-mode unit");
 
       animation->SetFillMode(animFillMode.list->mValue.GetIntValue());
     }
 
     if (i >= animPlayState.num) {
       animation->SetPlayState(display->mAnimations[i % animPlayState.num].GetPlayState());
     } else if (animPlayState.unit == eCSSUnit_Inherit) {
       MOZ_ASSERT(i < parentDisplay->mAnimationPlayStateCount,
                  "animPlayState.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       animation->SetPlayState(parentDisplay->mAnimations[i].GetPlayState());
     } else if (animPlayState.unit == eCSSUnit_Initial ||
                animPlayState.unit == eCSSUnit_Unset) {
       animation->SetPlayState(NS_STYLE_ANIMATION_PLAY_STATE_RUNNING);
     } else if (animPlayState.list) {
       MOZ_ASSERT(animPlayState.list->mValue.GetUnit() == eCSSUnit_Enumerated,
                  "Invalid animation-play-state unit");
 
       animation->SetPlayState(animPlayState.list->mValue.GetIntValue());
     }
 
     if (i >= animIterationCount.num) {
       animation->SetIterationCount(display->mAnimations[i % animIterationCount.num].GetIterationCount());
     } else if (animIterationCount.unit == eCSSUnit_Inherit) {
       MOZ_ASSERT(i < parentDisplay->mAnimationIterationCountCount,
                  "animIterationCount.num computed incorrectly");
-      MOZ_ASSERT(!canStoreInRuleTree,
-                 "should have made canStoreInRuleTree false above");
+      MOZ_ASSERT(!conditions.Cacheable(),
+                 "should have made conditions.Cacheable() false above");
       animation->SetIterationCount(parentDisplay->mAnimations[i].GetIterationCount());
     } else if (animIterationCount.unit == eCSSUnit_Initial ||
                animIterationCount.unit == eCSSUnit_Unset) {
       animation->SetIterationCount(1.0f);
     } else if (animIterationCount.list) {
       switch (animIterationCount.list->mValue.GetUnit()) {
         case eCSSUnit_Enumerated:
           MOZ_ASSERT(animIterationCount.list->mValue.GetIntValue() ==
@@ -5244,83 +5248,83 @@ nsRuleNode::ComputeDisplayData(void* aSt
       if (d.list) {
         d.list = d.list->mNext ? d.list->mNext :
           aRuleData->ValueFor(info.property)->GetListValue();
       }
     }
   }
 
   // opacity: factor, inherit, initial
-  SetFactor(*aRuleData->ValueForOpacity(), display->mOpacity, canStoreInRuleTree,
+  SetFactor(*aRuleData->ValueForOpacity(), display->mOpacity, conditions,
             parentDisplay->mOpacity, 1.0f,
             SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
 
   // display: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForDisplay(), display->mDisplay, canStoreInRuleTree,
+  SetDiscrete(*aRuleData->ValueForDisplay(), display->mDisplay, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mDisplay,
               NS_STYLE_DISPLAY_INLINE, 0, 0, 0, 0);
 
   // contain: none, enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForContain(), display->mContain, canStoreInRuleTree,
+  SetDiscrete(*aRuleData->ValueForContain(), display->mContain, conditions,
               SETDSC_ENUMERATED | SETDSC_NONE | SETDSC_UNSET_INITIAL,
               parentDisplay->mContain,
               NS_STYLE_CONTAIN_NONE, 0, NS_STYLE_CONTAIN_NONE, 0, 0);
 
   // mix-blend-mode: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForMixBlendMode(), display->mMixBlendMode,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mMixBlendMode, NS_STYLE_BLEND_NORMAL,
               0, 0, 0, 0);
 
   // scroll-behavior: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForScrollBehavior(), display->mScrollBehavior,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mScrollBehavior, NS_STYLE_SCROLL_BEHAVIOR_AUTO,
               0, 0, 0, 0);
 
   // scroll-snap-type-x: none, enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForScrollSnapTypeX(), display->mScrollSnapTypeX,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mScrollSnapTypeX, NS_STYLE_SCROLL_SNAP_TYPE_NONE,
               0, 0, 0, 0);
 
   // scroll-snap-type-y: none, enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForScrollSnapTypeY(), display->mScrollSnapTypeY,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mScrollSnapTypeY, NS_STYLE_SCROLL_SNAP_TYPE_NONE,
               0, 0, 0, 0);
 
   // scroll-snap-points-x: none, inherit, initial
   const nsCSSValue& scrollSnapPointsX = *aRuleData->ValueForScrollSnapPointsX();
   switch (scrollSnapPointsX.GetUnit()) {
     case eCSSUnit_Null:
       break;
     case eCSSUnit_Initial:
     case eCSSUnit_Unset:
     case eCSSUnit_None:
       display->mScrollSnapPointsX.SetNoneValue();
       break;
     case eCSSUnit_Inherit:
       display->mScrollSnapPointsX = parentDisplay->mScrollSnapPointsX;
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       break;
     case eCSSUnit_Function: {
       nsCSSValue::Array* func = scrollSnapPointsX.GetArrayValue();
       NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_repeat,
                    "Expected repeat(), got another function name");
       nsStyleCoord coord;
       if (SetCoord(func->Item(1), coord, nsStyleCoord(),
                    SETCOORD_LP | SETCOORD_STORE_CALC |
                    SETCOORD_CALC_CLAMP_NONNEGATIVE,
-                   aContext, mPresContext, canStoreInRuleTree)) {
+                   aContext, mPresContext, conditions)) {
         NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
                      coord.GetUnit() == eStyleUnit_Percent ||
                      coord.GetUnit() == eStyleUnit_Calc,
                      "unexpected unit");
         display->mScrollSnapPointsX = coord;
       }
       break;
     }
@@ -5335,27 +5339,27 @@ nsRuleNode::ComputeDisplayData(void* aSt
       break;
     case eCSSUnit_Initial:
     case eCSSUnit_Unset:
     case eCSSUnit_None:
       display->mScrollSnapPointsY.SetNoneValue();
       break;
     case eCSSUnit_Inherit:
       display->mScrollSnapPointsY = parentDisplay->mScrollSnapPointsY;
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       break;
     case eCSSUnit_Function: {
       nsCSSValue::Array* func = scrollSnapPointsY.GetArrayValue();
       NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_repeat,
                    "Expected repeat(), got another function name");
       nsStyleCoord coord;
       if (SetCoord(func->Item(1), coord, nsStyleCoord(),
                    SETCOORD_LP | SETCOORD_STORE_CALC |
                    SETCOORD_CALC_CLAMP_NONNEGATIVE,
-                   aContext, mPresContext, canStoreInRuleTree)) {
+                   aContext, mPresContext, conditions)) {
         NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
                      coord.GetUnit() == eStyleUnit_Percent ||
                      coord.GetUnit() == eStyleUnit_Calc,
                      "unexpected unit");
         display->mScrollSnapPointsY = coord;
       }
       break;
     }
@@ -5369,21 +5373,21 @@ nsRuleNode::ComputeDisplayData(void* aSt
     case eCSSUnit_Null:
       break;
     case eCSSUnit_Initial:
     case eCSSUnit_Unset:
       display->mScrollSnapDestination.SetInitialZeroValues();
       break;
     case eCSSUnit_Inherit:
       display->mScrollSnapDestination = parentDisplay->mScrollSnapDestination;
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       break;
     default: {
         ComputePositionValue(aContext, snapDestination,
-                             display->mScrollSnapDestination, canStoreInRuleTree);
+                             display->mScrollSnapDestination, conditions);
       }
   }
 
   // scroll-snap-coordinate: none, inherit, initial
   typedef nsStyleBackground::Position Position;
 
   const nsCSSValue& snapCoordinate = *aRuleData->ValueForScrollSnapCoordinate();
   switch (snapCoordinate.GetUnit()) {
@@ -5392,52 +5396,52 @@ nsRuleNode::ComputeDisplayData(void* aSt
     case eCSSUnit_Initial:
     case eCSSUnit_Unset:
     case eCSSUnit_None:
       // Unset and Initial is none, indicated by an empty array
       display->mScrollSnapCoordinate.Clear();
       break;
     case eCSSUnit_Inherit:
       display->mScrollSnapCoordinate = parentDisplay->mScrollSnapCoordinate;
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       break;
     case eCSSUnit_List: {
       display->mScrollSnapCoordinate.Clear();
       const nsCSSValueList* item = snapCoordinate.GetListValue();
       do {
         NS_ASSERTION(item->mValue.GetUnit() != eCSSUnit_Null &&
                      item->mValue.GetUnit() != eCSSUnit_Inherit &&
                      item->mValue.GetUnit() != eCSSUnit_Initial &&
                      item->mValue.GetUnit() != eCSSUnit_Unset,
                      "unexpected unit");
         Position* pos = display->mScrollSnapCoordinate.AppendElement();
-        ComputePositionValue(aContext, item->mValue, *pos, canStoreInRuleTree);
+        ComputePositionValue(aContext, item->mValue, *pos, conditions);
         item = item->mNext;
       } while(item);
       break;
     }
     default:
       NS_NOTREACHED("unexpected unit");
   }
 
   // isolation: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForIsolation(), display->mIsolation,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mIsolation, NS_STYLE_ISOLATION_AUTO,
               0, 0, 0, 0);
 
   // Backup original display value for calculation of a hypothetical
   // box (CSS2 10.6.4/10.6.5), in addition to getting our style data right later.
   // See nsHTMLReflowState::CalculateHypotheticalBox
   display->mOriginalDisplay = display->mDisplay;
 
   // appearance: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForAppearance(),
-              display->mAppearance, canStoreInRuleTree,
+              display->mAppearance, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mAppearance,
               NS_THEME_NONE, 0, 0, 0, 0);
 
   // binding: url, none, inherit
   const nsCSSValue* bindingValue = aRuleData->ValueForBinding();
   if (eCSSUnit_URL == bindingValue->GetUnit()) {
     mozilla::css::URLValue* url = bindingValue->GetURLStructValue();
@@ -5450,28 +5454,28 @@ nsRuleNode::ComputeDisplayData(void* aSt
     }
   }
   else if (eCSSUnit_None == bindingValue->GetUnit() ||
            eCSSUnit_Initial == bindingValue->GetUnit() ||
            eCSSUnit_Unset == bindingValue->GetUnit()) {
     display->mBinding = nullptr;
   }
   else if (eCSSUnit_Inherit == bindingValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     display->mBinding = parentDisplay->mBinding;
   }
 
   // position: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForPosition(), display->mPosition, canStoreInRuleTree,
+  SetDiscrete(*aRuleData->ValueForPosition(), display->mPosition, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mPosition,
               NS_STYLE_POSITION_STATIC, 0, 0, 0, 0);
 
   // clear: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForClear(), display->mBreakType, canStoreInRuleTree,
+  SetDiscrete(*aRuleData->ValueForClear(), display->mBreakType, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mBreakType,
               NS_STYLE_CLEAR_NONE, 0, 0, 0, 0);
 
   // temp fix for bug 24000
   // Map 'auto' and 'avoid' to false, and 'always', 'left', and
   // 'right' to true.
   // "A conforming user agent may interpret the values 'left' and
@@ -5482,87 +5486,87 @@ nsRuleNode::ComputeDisplayData(void* aSt
       (NS_STYLE_PAGE_BREAK_AVOID != breakBeforeValue->GetIntValue() &&
        NS_STYLE_PAGE_BREAK_AUTO  != breakBeforeValue->GetIntValue());
   }
   else if (eCSSUnit_Initial == breakBeforeValue->GetUnit() ||
            eCSSUnit_Unset == breakBeforeValue->GetUnit()) {
     display->mBreakBefore = false;
   }
   else if (eCSSUnit_Inherit == breakBeforeValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     display->mBreakBefore = parentDisplay->mBreakBefore;
   }
 
   const nsCSSValue* breakAfterValue = aRuleData->ValueForPageBreakAfter();
   if (eCSSUnit_Enumerated == breakAfterValue->GetUnit()) {
     display->mBreakAfter =
       (NS_STYLE_PAGE_BREAK_AVOID != breakAfterValue->GetIntValue() &&
        NS_STYLE_PAGE_BREAK_AUTO  != breakAfterValue->GetIntValue());
   }
   else if (eCSSUnit_Initial == breakAfterValue->GetUnit() ||
            eCSSUnit_Unset == breakAfterValue->GetUnit()) {
     display->mBreakAfter = false;
   }
   else if (eCSSUnit_Inherit == breakAfterValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     display->mBreakAfter = parentDisplay->mBreakAfter;
   }
   // end temp fix
 
   // page-break-inside: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForPageBreakInside(),
-              display->mBreakInside, canStoreInRuleTree,
+              display->mBreakInside, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mBreakInside,
               NS_STYLE_PAGE_BREAK_AUTO, 0, 0, 0, 0);
 
   // touch-action: none, auto, enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForTouchAction(), display->mTouchAction,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_AUTO | SETDSC_NONE |
                 SETDSC_UNSET_INITIAL,
               parentDisplay->mTouchAction,
               NS_STYLE_TOUCH_ACTION_AUTO,
               NS_STYLE_TOUCH_ACTION_AUTO,
               NS_STYLE_TOUCH_ACTION_NONE, 0, 0);
 
   // float: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForFloat(),
-              display->mFloats, canStoreInRuleTree,
+              display->mFloats, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mFloats,
               NS_STYLE_FLOAT_NONE, 0, 0, 0, 0);
   // Save mFloats in mOriginalFloats in case we need it later
   display->mOriginalFloats = display->mFloats;
 
   // overflow-x: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForOverflowX(),
-              display->mOverflowX, canStoreInRuleTree,
+              display->mOverflowX, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mOverflowX,
               NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
 
   // overflow-y: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForOverflowY(),
-              display->mOverflowY, canStoreInRuleTree,
+              display->mOverflowY, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mOverflowY,
               NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
 
   // CSS3 overflow-x and overflow-y require some fixup as well in some
   // cases.  NS_STYLE_OVERFLOW_VISIBLE and NS_STYLE_OVERFLOW_CLIP are
   // meaningful only when used in both dimensions.
   if (display->mOverflowX != display->mOverflowY &&
       (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE ||
        display->mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
        display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE ||
        display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)) {
     // We can't store in the rule tree since a more specific rule might
     // change these conditions.
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
 
     // NS_STYLE_OVERFLOW_CLIP is a deprecated value, so if it's specified
     // in only one dimension, convert it to NS_STYLE_OVERFLOW_HIDDEN.
     if (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
       display->mOverflowX = NS_STYLE_OVERFLOW_HIDDEN;
     if (display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)
       display->mOverflowY = NS_STYLE_OVERFLOW_HIDDEN;
 
@@ -5570,31 +5574,31 @@ nsRuleNode::ComputeDisplayData(void* aSt
     // turns into 'auto'.
     if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
       display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
     if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
       display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
   }
 
   SetDiscrete(*aRuleData->ValueForOverflowClipBox(), display->mOverflowClipBox,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mOverflowClipBox,
               NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX, 0, 0, 0, 0);
 
-  SetDiscrete(*aRuleData->ValueForResize(), display->mResize, canStoreInRuleTree,
+  SetDiscrete(*aRuleData->ValueForResize(), display->mResize, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mResize,
               NS_STYLE_RESIZE_NONE, 0, 0, 0, 0);
 
   // clip property: length, auto, inherit
   const nsCSSValue* clipValue = aRuleData->ValueForClip();
   switch (clipValue->GetUnit()) {
   case eCSSUnit_Inherit:
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     display->mClipFlags = parentDisplay->mClipFlags;
     display->mClip = parentDisplay->mClip;
     break;
 
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
   case eCSSUnit_Auto:
     display->mClipFlags = NS_STYLE_CLIP_AUTO;
@@ -5610,51 +5614,51 @@ nsRuleNode::ComputeDisplayData(void* aSt
     display->mClipFlags = NS_STYLE_CLIP_RECT;
 
     if (clipRect.mTop.GetUnit() == eCSSUnit_Auto) {
       display->mClip.y = 0;
       display->mClipFlags |= NS_STYLE_CLIP_TOP_AUTO;
     }
     else if (clipRect.mTop.IsLengthUnit()) {
       display->mClip.y = CalcLength(clipRect.mTop, aContext,
-                                    mPresContext, canStoreInRuleTree);
+                                    mPresContext, conditions);
     }
 
     if (clipRect.mBottom.GetUnit() == eCSSUnit_Auto) {
       // Setting to NS_MAXSIZE for the 'auto' case ensures that
       // the clip rect is nonempty. It is important that mClip be
       // nonempty if the actual clip rect could be nonempty.
       display->mClip.height = NS_MAXSIZE;
       display->mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO;
     }
     else if (clipRect.mBottom.IsLengthUnit()) {
       display->mClip.height = CalcLength(clipRect.mBottom, aContext,
-                                         mPresContext, canStoreInRuleTree) -
+                                         mPresContext, conditions) -
                               display->mClip.y;
     }
 
     if (clipRect.mLeft.GetUnit() == eCSSUnit_Auto) {
       display->mClip.x = 0;
       display->mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO;
     }
     else if (clipRect.mLeft.IsLengthUnit()) {
       display->mClip.x = CalcLength(clipRect.mLeft, aContext,
-                                    mPresContext, canStoreInRuleTree);
+                                    mPresContext, conditions);
     }
 
     if (clipRect.mRight.GetUnit() == eCSSUnit_Auto) {
       // Setting to NS_MAXSIZE for the 'auto' case ensures that
       // the clip rect is nonempty. It is important that mClip be
       // nonempty if the actual clip rect could be nonempty.
       display->mClip.width = NS_MAXSIZE;
       display->mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO;
     }
     else if (clipRect.mRight.IsLengthUnit()) {
       display->mClip.width = CalcLength(clipRect.mRight, aContext,
-                                        mPresContext, canStoreInRuleTree) -
+                                        mPresContext, conditions) -
                              display->mClip.x;
     }
     break;
   }
 
   default:
     MOZ_ASSERT(false, "unrecognized clip unit");
   }
@@ -5671,29 +5675,29 @@ nsRuleNode::ComputeDisplayData(void* aSt
       // (XXX what we really should check here is not GetPseudo() but if there's
       //  a 'content' property value that implies anon content but we can't
       //  check that here since that's a different struct(?))
       // We might get display:contents to work for CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS
       // pseudos (:first-letter etc) in the future, but those have a lot of
       // special handling in frame construction so they are also unsupported
       // for now.
       display->mOriginalDisplay = display->mDisplay = NS_STYLE_DISPLAY_INLINE;
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
     }
 
     if (nsCSSPseudoElements::firstLetter == pseudo) {
       // a non-floating first-letter must be inline
       // XXX this fix can go away once bug 103189 is fixed correctly
       // Note that we reset mOriginalDisplay to enforce the invariant that it equals mDisplay if we're not positioned or floating.
       display->mOriginalDisplay = display->mDisplay = NS_STYLE_DISPLAY_INLINE;
 
       // We can't cache the data in the rule tree since if a more specific
       // rule has 'float: left' we'll end up with the wrong 'display'
       // property.
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
     }
 
     if (display->IsAbsolutelyPositionedStyle()) {
       // 1) if position is 'absolute' or 'fixed' then display must be
       // block-level and float must be 'none'
       EnsureBlockDisplay(display->mDisplay);
       display->mFloats = NS_STYLE_FLOAT_NONE;
 
@@ -5726,17 +5730,17 @@ nsRuleNode::ComputeDisplayData(void* aSt
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
   case eCSSUnit_None:
     display->mSpecifiedTransform = nullptr;
     break;
 
   case eCSSUnit_Inherit:
     display->mSpecifiedTransform = parentDisplay->mSpecifiedTransform;
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     break;
 
   case eCSSUnit_SharedList: {
     nsCSSValueSharedList* list = transformValue->GetSharedListValue();
     nsCSSValueList* head = list->mHead;
     MOZ_ASSERT(head, "transform list must have at least one item");
     // can get a _None in here from transform animation
     if (head->mValue.GetUnit() == eCSSUnit_None) {
@@ -5792,17 +5796,17 @@ nsRuleNode::ComputeDisplayData(void* aSt
       }
     }
     break;
   }
 
   case eCSSUnit_Inherit:
     display->mWillChange = parentDisplay->mWillChange;
     display->mWillChangeBitField = parentDisplay->mWillChangeBitField;
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     break;
 
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
   case eCSSUnit_Auto:
     display->mWillChange.Clear();
     display->mWillChangeBitField = 0;
     break;
@@ -5826,38 +5830,38 @@ nsRuleNode::ComputeDisplayData(void* aSt
         transformOriginValue->GetTripletValue().mZValue : *transformOriginValue;
 
     mozilla::DebugOnly<bool> cX =
        SetCoord(valX, display->mTransformOrigin[0],
                 parentDisplay->mTransformOrigin[0],
                 SETCOORD_LPH | SETCOORD_INITIAL_HALF |
                   SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
                   SETCOORD_UNSET_INITIAL,
-                aContext, mPresContext, canStoreInRuleTree);
+                aContext, mPresContext, conditions);
 
      mozilla::DebugOnly<bool> cY =
        SetCoord(valY, display->mTransformOrigin[1],
                 parentDisplay->mTransformOrigin[1],
                 SETCOORD_LPH | SETCOORD_INITIAL_HALF |
                   SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
                   SETCOORD_UNSET_INITIAL,
-                aContext, mPresContext, canStoreInRuleTree);
+                aContext, mPresContext, conditions);
 
      if (valZ.GetUnit() == eCSSUnit_Null) {
        // Null for the z component means a 0 translation, not
        // unspecified, as we have already checked the triplet
        // value for Null.
        display->mTransformOrigin[2].SetCoordValue(0);
      } else {
        mozilla::DebugOnly<bool> cZ =
          SetCoord(valZ, display->mTransformOrigin[2],
                   parentDisplay->mTransformOrigin[2],
                   SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
                     SETCOORD_UNSET_INITIAL,
-                  aContext, mPresContext, canStoreInRuleTree);
+                  aContext, mPresContext, conditions);
        MOZ_ASSERT(cY == cZ, "changed one but not the other");
      }
      MOZ_ASSERT(cX == cY, "changed one but not the other");
      NS_ASSERTION(cX, "Malformed -moz-transform-origin parse!");
   }
 
   const nsCSSValue* perspectiveOriginValue =
     aRuleData->ValueForPerspectiveOrigin();
@@ -5866,114 +5870,114 @@ nsRuleNode::ComputeDisplayData(void* aSt
       SetPairCoords(*perspectiveOriginValue,
                     display->mPerspectiveOrigin[0],
                     display->mPerspectiveOrigin[1],
                     parentDisplay->mPerspectiveOrigin[0],
                     parentDisplay->mPerspectiveOrigin[1],
                     SETCOORD_LPH | SETCOORD_INITIAL_HALF |
                       SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
                       SETCOORD_UNSET_INITIAL,
-                    aContext, mPresContext, canStoreInRuleTree);
+                    aContext, mPresContext, conditions);
     NS_ASSERTION(result, "Malformed -moz-perspective-origin parse!");
   }
 
   SetCoord(*aRuleData->ValueForPerspective(), 
            display->mChildPerspective, parentDisplay->mChildPerspective,
            SETCOORD_LAH | SETCOORD_INITIAL_NONE | SETCOORD_NONE |
              SETCOORD_UNSET_INITIAL,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
 
   SetDiscrete(*aRuleData->ValueForBackfaceVisibility(),
-              display->mBackfaceVisibility, canStoreInRuleTree,
+              display->mBackfaceVisibility, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mBackfaceVisibility,
               NS_STYLE_BACKFACE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
 
   // transform-style: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForTransformStyle(),
-              display->mTransformStyle, canStoreInRuleTree,
+              display->mTransformStyle, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mTransformStyle,
               NS_STYLE_TRANSFORM_STYLE_FLAT, 0, 0, 0, 0);
 
   // transform-box: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForTransformBox(),
-              display->mTransformBox, canStoreInRuleTree,
+              display->mTransformBox, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mTransformBox,
               NS_STYLE_TRANSFORM_BOX_BORDER_BOX, 0, 0, 0, 0);
 
   // orient: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForOrient(),
-              display->mOrient, canStoreInRuleTree,
+              display->mOrient, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mOrient,
               NS_STYLE_ORIENT_INLINE, 0, 0, 0, 0);
 
   COMPUTE_END_RESET(Display, display)
 }
 
 const void*
 nsRuleNode::ComputeVisibilityData(void* aStartStruct,
                                   const nsRuleData* aRuleData,
                                   nsStyleContext* aContext,
                                   nsRuleNode* aHighestNode,
                                   const RuleDetail aRuleDetail,
-                                  const bool aCanStoreInRuleTree)
+                                  const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(Visibility, (mPresContext),
                           visibility, parentVisibility)
 
   // IMPORTANT: No properties in this struct have lengths in them.  We
   // depend on this since CalcLengthWith can call StyleVisibility()
   // to get the language for resolving fonts!
 
   // direction: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForDirection(), visibility->mDirection,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentVisibility->mDirection,
               (GET_BIDI_OPTION_DIRECTION(mPresContext->GetBidi())
                == IBMBIDI_TEXTDIRECTION_RTL)
               ? NS_STYLE_DIRECTION_RTL : NS_STYLE_DIRECTION_LTR,
               0, 0, 0, 0);
 
   // visibility: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForVisibility(), visibility->mVisible,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentVisibility->mVisible,
               NS_STYLE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
 
   // pointer-events: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForPointerEvents(), visibility->mPointerEvents,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentVisibility->mPointerEvents,
               NS_STYLE_POINTER_EVENTS_AUTO, 0, 0, 0, 0);
 
   // writing-mode: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForWritingMode(), visibility->mWritingMode,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentVisibility->mWritingMode,
               NS_STYLE_WRITING_MODE_HORIZONTAL_TB, 0, 0, 0, 0);
 
   // text-orientation: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForTextOrientation(), visibility->mTextOrientation,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentVisibility->mTextOrientation,
               NS_STYLE_TEXT_ORIENTATION_MIXED, 0, 0, 0, 0);
 
   // image-orientation: enum, inherit, initial
   const nsCSSValue* orientation = aRuleData->ValueForImageOrientation();
   if (orientation->GetUnit() == eCSSUnit_Inherit ||
       orientation->GetUnit() == eCSSUnit_Unset) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     visibility->mImageOrientation = parentVisibility->mImageOrientation;
   } else if (orientation->GetUnit() == eCSSUnit_Initial) {
     visibility->mImageOrientation = nsStyleImageOrientation();
   } else if (orientation->IsAngularUnit()) {
     double angle = orientation->GetAngleValueInRadians();
     visibility->mImageOrientation =
       nsStyleImageOrientation::CreateAsAngleAndFlip(angle, false);
   } else if (orientation->GetUnit() == eCSSUnit_Array) {
@@ -6006,66 +6010,66 @@ nsRuleNode::ComputeVisibilityData(void* 
 }
 
 const void*
 nsRuleNode::ComputeColorData(void* aStartStruct,
                              const nsRuleData* aRuleData,
                              nsStyleContext* aContext,
                              nsRuleNode* aHighestNode,
                              const RuleDetail aRuleDetail,
-                             const bool aCanStoreInRuleTree)
+                             const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(Color, (mPresContext), color, parentColor)
 
   // color: color, string, inherit
   // Special case for currentColor.  According to CSS3, setting color to 'currentColor'
   // should behave as if it is inherited
   const nsCSSValue* colorValue = aRuleData->ValueForColor();
   if ((colorValue->GetUnit() == eCSSUnit_EnumColor &&
        colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) ||
       colorValue->GetUnit() == eCSSUnit_Unset) {
     color->mColor = parentColor->mColor;
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
   }
   else if (colorValue->GetUnit() == eCSSUnit_Initial) {
     color->mColor = mPresContext->DefaultColor();
   }
   else {
     SetColor(*colorValue, parentColor->mColor, mPresContext, aContext,
-             color->mColor, canStoreInRuleTree);
+             color->mColor, conditions);
   }
 
   COMPUTE_END_INHERITED(Color, color)
 }
 
 // information about how to compute values for background-* properties
 template <class SpecifiedValueItem, class ComputedValueItem>
 struct BackgroundItemComputer {
 };
 
 template <>
 struct BackgroundItemComputer<nsCSSValueList, uint8_t>
 {
   static void ComputeValue(nsStyleContext* aStyleContext,
                            const nsCSSValueList* aSpecifiedValue,
                            uint8_t& aComputedValue,
-                           bool& aCanStoreInRuleTree)
+                           RuleNodeCacheConditions& aConditions)
   {
-    SetDiscrete(aSpecifiedValue->mValue, aComputedValue, aCanStoreInRuleTree,
+    SetDiscrete(aSpecifiedValue->mValue, aComputedValue, aConditions,
                 SETDSC_ENUMERATED, uint8_t(0), 0, 0, 0, 0, 0);
   }
 };
 
 template <>
 struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Repeat>
 {
   static void ComputeValue(nsStyleContext* aStyleContext,
                            const nsCSSValuePairList* aSpecifiedValue,
                            nsStyleBackground::Repeat& aComputedValue,
-                           bool& aCanStoreInRuleTree)
+                           RuleNodeCacheConditions& aConditions)
   {
     NS_ASSERTION(aSpecifiedValue->mXValue.GetUnit() == eCSSUnit_Enumerated &&
                  (aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Enumerated ||
                   aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null),
                  "Invalid unit");
     
     bool hasContraction = true;
     uint8_t value = aSpecifiedValue->mXValue.GetIntValue();
@@ -6108,49 +6112,49 @@ struct BackgroundItemComputer<nsCSSValue
 };
 
 template <>
 struct BackgroundItemComputer<nsCSSValueList, nsStyleImage>
 {
   static void ComputeValue(nsStyleContext* aStyleContext,
                            const nsCSSValueList* aSpecifiedValue,
                            nsStyleImage& aComputedValue,
-                           bool& aCanStoreInRuleTree)
+                           RuleNodeCacheConditions& aConditions)
   {
     SetStyleImage(aStyleContext, aSpecifiedValue->mValue, aComputedValue,
-                  aCanStoreInRuleTree);
+                  aConditions);
   }
 };
 
 /* Helper function for ComputePositionValue.
  * This function computes a single PositionCoord from two nsCSSValue objects,
  * which represent an edge and an offset from that edge.
  */
 typedef nsStyleBackground::Position::PositionCoord PositionCoord;
 static void
 ComputePositionCoord(nsStyleContext* aStyleContext,
                      const nsCSSValue& aEdge,
                      const nsCSSValue& aOffset,
                      PositionCoord* aResult,
-                     bool& aCanStoreInRuleTree)
+                     RuleNodeCacheConditions& aConditions)
 {
   if (eCSSUnit_Percent == aOffset.GetUnit()) {
     aResult->mLength = 0;
     aResult->mPercent = aOffset.GetPercentValue();
     aResult->mHasPercent = true;
   } else if (aOffset.IsLengthUnit()) {
     aResult->mLength = CalcLength(aOffset, aStyleContext,
                                   aStyleContext->PresContext(),
-                                  aCanStoreInRuleTree);
+                                  aConditions);
     aResult->mPercent = 0.0f;
     aResult->mHasPercent = false;
   } else if (aOffset.IsCalcUnit()) {
     LengthPercentPairCalcOps ops(aStyleContext,
                                  aStyleContext->PresContext(),
-                                 aCanStoreInRuleTree);
+                                 aConditions);
     nsRuleNode::ComputedCalc vals = ComputeCalc(aOffset, ops);
     aResult->mLength = vals.mLength;
     aResult->mPercent = vals.mPercent;
     aResult->mHasPercent = ops.mHasPercent;
   } else {
     aResult->mLength = 0;
     aResult->mPercent = 0.0f;
     aResult->mHasPercent = false;
@@ -6175,17 +6179,17 @@ ComputePositionCoord(nsStyleContext* aSt
 }
 
 /* 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)
 {
   NS_ASSERTION(aValue.GetUnit() == eCSSUnit_Array,
                "unexpected unit for CSS <position> value");
 
   nsRefPtr<nsCSSValue::Array> positionArray = aValue.GetArrayValue();
   const nsCSSValue &xEdge   = positionArray->Item(0);
   const nsCSSValue &xOffset = positionArray->Item(1);
   const nsCSSValue &yEdge   = positionArray->Item(2);
@@ -6196,33 +6200,33 @@ ComputePositionValue(nsStyleContext* aSt
                (eCSSUnit_Enumerated == yEdge.GetUnit()  ||
                 eCSSUnit_Null       == yEdge.GetUnit()) &&
                eCSSUnit_Enumerated != xOffset.GetUnit()  &&
                eCSSUnit_Enumerated != yOffset.GetUnit(),
                "Invalid background position");
 
   ComputePositionCoord(aStyleContext, xEdge, xOffset,
                        &aComputedValue.mXPosition,
-                       aCanStoreInRuleTree);
+                       aConditions);
 
   ComputePositionCoord(aStyleContext, yEdge, yOffset,
                        &aComputedValue.mYPosition,
-                       aCanStoreInRuleTree);
+                       aConditions);
 }
 
 template <>
 struct BackgroundItemComputer<nsCSSValueList, nsStyleBackground::Position>
 {
   static void ComputeValue(nsStyleContext* aStyleContext,
                            const nsCSSValueList* aSpecifiedValue,
                            nsStyleBackground::Position& aComputedValue,
-                           bool& aCanStoreInRuleTree)
+                           RuleNodeCacheConditions& aConditions)
   {
     ComputePositionValue(aStyleContext, aSpecifiedValue->mValue,
-                         aComputedValue, aCanStoreInRuleTree);
+                         aComputedValue, aConditions);
   }
 };
 
 
 struct BackgroundSizeAxis {
   nsCSSValue nsCSSValuePairList::* specified;
   nsStyleBackground::Size::Dimension nsStyleBackground::Size::* result;
   uint8_t nsStyleBackground::Size::* type;
@@ -6238,17 +6242,17 @@ static const BackgroundSizeAxis gBGSizeA
 };
 
 template <>
 struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Size>
 {
   static void ComputeValue(nsStyleContext* aStyleContext,
                            const nsCSSValuePairList* aSpecifiedValue,
                            nsStyleBackground::Size& aComputedValue,
-                           bool& aCanStoreInRuleTree)
+                           RuleNodeCacheConditions& aConditions)
   {
     nsStyleBackground::Size &size = aComputedValue;
     for (const BackgroundSizeAxis *axis = gBGSizeAxes,
                         *axis_end = ArrayEnd(gBGSizeAxes);
          axis < axis_end; ++axis) {
       const nsCSSValue &specified = aSpecifiedValue->*(axis->specified);
       if (eCSSUnit_Auto == specified.GetUnit()) {
         size.*(axis->type) = nsStyleBackground::Size::eAuto;
@@ -6288,25 +6292,25 @@ struct BackgroundItemComputer<nsCSSValue
         (size.*(axis->result)).mLength = 0;
         (size.*(axis->result)).mPercent = specified.GetPercentValue();
         (size.*(axis->result)).mHasPercent = true;
         size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
       }
       else if (specified.IsLengthUnit()) {
         (size.*(axis->result)).mLength =
           CalcLength(specified, aStyleContext, aStyleContext->PresContext(),
-                     aCanStoreInRuleTree);
+                     aConditions);
         (size.*(axis->result)).mPercent = 0.0f;
         (size.*(axis->result)).mHasPercent = false;
         size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
       } else {
         MOZ_ASSERT(specified.IsCalcUnit(), "unexpected unit");
         LengthPercentPairCalcOps ops(aStyleContext,
                                      aStyleContext->PresContext(),
-                                     aCanStoreInRuleTree);
+                                     aConditions);
         nsRuleNode::ComputedCalc vals = ComputeCalc(specified, ops);
         (size.*(axis->result)).mLength = vals.mLength;
         (size.*(axis->result)).mPercent = vals.mPercent;
         (size.*(axis->result)).mHasPercent = ops.mHasPercent;
         size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
       }
     }
 
@@ -6328,25 +6332,25 @@ SetBackgroundList(nsStyleContext* aStyle
                   nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
                   const nsAutoTArray<nsStyleBackground::Layer, 1> &aParentLayers,
                   ComputedValueItem nsStyleBackground::Layer::* aResultLocation,
                   ComputedValueItem aInitialValue,
                   uint32_t aParentItemCount,
                   uint32_t& aItemCount,
                   uint32_t& aMaxItemCount,
                   bool& aRebuild,
-                  bool& aCanStoreInRuleTree)
+                  RuleNodeCacheConditions& aConditions)
 {
   switch (aValue.GetUnit()) {
   case eCSSUnit_Null:
     break;
 
   case eCSSUnit_Inherit:
     aRebuild = true;
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aLayers.EnsureLengthAtLeast(aParentItemCount);
     aItemCount = aParentItemCount;
     for (uint32_t i = 0; i < aParentItemCount; ++i) {
       aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
     }
     break;
 
   case eCSSUnit_Initial:
@@ -6367,17 +6371,17 @@ SetBackgroundList(nsStyleContext* aStyle
                    item->mValue.GetUnit() != eCSSUnit_Initial &&
                    item->mValue.GetUnit() != eCSSUnit_Unset,
                    "unexpected unit");
       ++aItemCount;
       aLayers.EnsureLengthAtLeast(aItemCount);
       BackgroundItemComputer<nsCSSValueList, ComputedValueItem>
         ::ComputeValue(aStyleContext, item,
                        aLayers[aItemCount-1].*aResultLocation,
-                       aCanStoreInRuleTree);
+                       aConditions);
       item = item->mNext;
     } while (item);
     break;
   }
 
   default:
     MOZ_ASSERT(false, "unexpected unit");
   }
@@ -6395,25 +6399,25 @@ SetBackgroundPairList(nsStyleContext* aS
                                                                  &aParentLayers,
                       ComputedValueItem nsStyleBackground::Layer::*
                                                                 aResultLocation,
                       ComputedValueItem aInitialValue,
                       uint32_t aParentItemCount,
                       uint32_t& aItemCount,
                       uint32_t& aMaxItemCount,
                       bool& aRebuild,
-                      bool& aCanStoreInRuleTree)
+                      RuleNodeCacheConditions& aConditions)
 {
   switch (aValue.GetUnit()) {
   case eCSSUnit_Null:
     break;
 
   case eCSSUnit_Inherit:
     aRebuild = true;
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aLayers.EnsureLengthAtLeast(aParentItemCount);
     aItemCount = aParentItemCount;
     for (uint32_t i = 0; i < aParentItemCount; ++i) {
       aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
     }
     break;
 
   case eCSSUnit_Initial:
@@ -6436,17 +6440,17 @@ SetBackgroundPairList(nsStyleContext* aS
                    item->mYValue.GetUnit() != eCSSUnit_Initial &&
                    item->mYValue.GetUnit() != eCSSUnit_Unset,
                    "unexpected unit");
       ++aItemCount;
       aLayers.EnsureLengthAtLeast(aItemCount);
       BackgroundItemComputer<nsCSSValuePairList, ComputedValueItem>
         ::ComputeValue(aStyleContext, item,
                        aLayers[aItemCount-1].*aResultLocation,
-                       aCanStoreInRuleTree);
+                       aConditions);
       item = item->mNext;
     } while (item);
     break;
   }
 
   default:
     MOZ_ASSERT(false, "unexpected unit");
   }
@@ -6471,104 +6475,104 @@ FillBackgroundList(nsAutoTArray< nsStyle
 }
 
 const void*
 nsRuleNode::ComputeBackgroundData(void* aStartStruct,
                                   const nsRuleData* aRuleData,
                                   nsStyleContext* aContext,
                                   nsRuleNode* aHighestNode,
                                   const RuleDetail aRuleDetail,
-                                  const bool aCanStoreInRuleTree)
+                                  const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(Background, (), bg, parentBG)
 
   // background-color: color, string, inherit
   const nsCSSValue* backColorValue = aRuleData->ValueForBackgroundColor();
   if (eCSSUnit_Initial == backColorValue->GetUnit() ||
       eCSSUnit_Unset == backColorValue->GetUnit()) {
     bg->mBackgroundColor = NS_RGBA(0, 0, 0, 0);
   } else if (!SetColor(*backColorValue, parentBG->mBackgroundColor,
                        mPresContext, aContext, bg->mBackgroundColor,
-                       canStoreInRuleTree)) {
+                       conditions)) {
     NS_ASSERTION(eCSSUnit_Null == backColorValue->GetUnit(),
                  "unexpected color unit");
   }
 
   uint32_t maxItemCount = 1;
   bool rebuild = false;
 
   // background-image: url (stored as image), none, inherit [list]
   nsStyleImage initialImage;
   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundImage(),
                     bg->mLayers,
                     parentBG->mLayers, &nsStyleBackground::Layer::mImage,
                     initialImage, parentBG->mImageCount, bg->mImageCount,
-                    maxItemCount, rebuild, canStoreInRuleTree);
+                    maxItemCount, rebuild, conditions);
 
   // background-repeat: enum, inherit, initial [pair list]
   nsStyleBackground::Repeat initialRepeat;
   initialRepeat.SetInitialValues();
   SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundRepeat(),
                         bg->mLayers,
                         parentBG->mLayers, &nsStyleBackground::Layer::mRepeat,
                         initialRepeat, parentBG->mRepeatCount,
                         bg->mRepeatCount, maxItemCount, rebuild, 
-                        canStoreInRuleTree);
+                        conditions);
 
   // background-attachment: enum, inherit, initial [list]
   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundAttachment(),
                     bg->mLayers, parentBG->mLayers,
                     &nsStyleBackground::Layer::mAttachment,
                     uint8_t(NS_STYLE_BG_ATTACHMENT_SCROLL),
                     parentBG->mAttachmentCount,
                     bg->mAttachmentCount, maxItemCount, rebuild,
-                    canStoreInRuleTree);
+                    conditions);
 
   // background-clip: enum, inherit, initial [list]
   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundClip(),
                     bg->mLayers,
                     parentBG->mLayers, &nsStyleBackground::Layer::mClip,
                     uint8_t(NS_STYLE_BG_CLIP_BORDER), parentBG->mClipCount,
-                    bg->mClipCount, maxItemCount, rebuild, canStoreInRuleTree);
+                    bg->mClipCount, maxItemCount, rebuild, conditions);
 
   // background-blend-mode: enum, inherit, initial [list]
   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundBlendMode(),
                     bg->mLayers,
                     parentBG->mLayers, &nsStyleBackground::Layer::mBlendMode,
                     uint8_t(NS_STYLE_BLEND_NORMAL), parentBG->mBlendModeCount,
                     bg->mBlendModeCount, maxItemCount, rebuild,
-                    canStoreInRuleTree);
+                    conditions);
 
   // background-origin: enum, inherit, initial [list]
   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundOrigin(),
                     bg->mLayers,
                     parentBG->mLayers, &nsStyleBackground::Layer::mOrigin,
                     uint8_t(NS_STYLE_BG_ORIGIN_PADDING), parentBG->mOriginCount,
                     bg->mOriginCount, maxItemCount, rebuild,
-                    canStoreInRuleTree);
+                    conditions);
 
   // background-position: enum, length, percent (flags), inherit [pair list]
   nsStyleBackground::Position initialPosition;
   initialPosition.SetInitialPercentValues(0.0f);
   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundPosition(),
                     bg->mLayers,
                     parentBG->mLayers, &nsStyleBackground::Layer::mPosition,
                     initialPosition, parentBG->mPositionCount,
                     bg->mPositionCount, maxItemCount, rebuild,
-                    canStoreInRuleTree);
+                    conditions);
 
   // background-size: enum, length, auto, inherit, initial [pair list]
   nsStyleBackground::Size initialSize;
   initialSize.SetInitialValues();
   SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundSize(),
                         bg->mLayers,
                         parentBG->mLayers, &nsStyleBackground::Layer::mSize,
                         initialSize, parentBG->mSizeCount,
                         bg->mSizeCount, maxItemCount, rebuild,
-                        canStoreInRuleTree);
+                        conditions);
 
   if (rebuild) {
     // Delete any extra items.  We need to keep layers in which any
     // property was specified.
     bg->mLayers.TruncateLength(maxItemCount);
 
     uint32_t fillCount = bg->mImageCount;
     FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mImage,
@@ -6597,31 +6601,31 @@ nsRuleNode::ComputeBackgroundData(void* 
 }
 
 const void*
 nsRuleNode::ComputeMarginData(void* aStartStruct,
                               const nsRuleData* aRuleData,
                               nsStyleContext* aContext,
                               nsRuleNode* aHighestNode,
                               const RuleDetail aRuleDetail,
-                              const bool aCanStoreInRuleTree)
+                              const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(Margin, (), margin, parentMargin)
 
   // margin: length, percent, calc, inherit
   const nsCSSProperty* subprops =
     nsCSSProps::SubpropertyEntryFor(eCSSProperty_margin);
   nsStyleCoord coord;
   NS_FOR_CSS_SIDES(side) {
     nsStyleCoord parentCoord = parentMargin->mMargin.Get(side);
     if (SetCoord(*aRuleData->ValueFor(subprops[side]),
                  coord, parentCoord,
                  SETCOORD_LPAH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
                    SETCOORD_UNSET_INITIAL,
-                 aContext, mPresContext, canStoreInRuleTree)) {
+                 aContext, mPresContext, conditions)) {
       margin->mMargin.Set(side, coord);
     }
   }
 
   margin->RecalcData();
   COMPUTE_END_RESET(Margin, margin)
 }
 
@@ -6703,23 +6707,23 @@ SetBorderImageSlice(const nsCSSValue& aV
 }
 
 const void*
 nsRuleNode::ComputeBorderData(void* aStartStruct,
                               const nsRuleData* aRuleData,
                               nsStyleContext* aContext,
                               nsRuleNode* aHighestNode,
                               const RuleDetail aRuleDetail,
-                              const bool aCanStoreInRuleTree)
+                              const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder)
 
   // box-decoration-break: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForBoxDecorationBreak(),
-              border->mBoxDecorationBreak, canStoreInRuleTree,
+              border->mBoxDecorationBreak, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentBorder->mBoxDecorationBreak,
               NS_STYLE_BOX_DECORATION_BREAK_SLICE, 0, 0, 0, 0);
 
   // box-shadow: none, list, inherit, initial
   const nsCSSValue* boxShadowValue = aRuleData->ValueForBoxShadow();
   switch (boxShadowValue->GetUnit()) {
   case eCSSUnit_Null:
@@ -6728,23 +6732,23 @@ nsRuleNode::ComputeBorderData(void* aSta
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
   case eCSSUnit_None:
     border->mBoxShadow = nullptr;
     break;
 
   case eCSSUnit_Inherit:
     border->mBoxShadow = parentBorder->mBoxShadow;
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     break;
 
   case eCSSUnit_List:
   case eCSSUnit_ListDep:
     border->mBoxShadow = GetShadowData(boxShadowValue->GetListValue(),
-                                       aContext, true, canStoreInRuleTree);
+                                       aContext, true, conditions);
     break;
 
   default:
     MOZ_ASSERT(false, "unrecognized shadow unit");
   }
 
   // border-width, border-*-width: length, enum, inherit
   nsStyleCoord coord;
@@ -6767,23 +6771,23 @@ nsRuleNode::ComputeBorderData(void* aSta
                      value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
                      "Unexpected enum value");
         border->SetBorderWidth(side,
                                (mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
       }
       // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
       else if (SetCoord(value, coord, nsStyleCoord(),
                         SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
-                        aContext, mPresContext, canStoreInRuleTree)) {
+                        aContext, mPresContext, conditions)) {
         NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
         // clamp negative calc() to 0.
         border->SetBorderWidth(side, std::max(coord.GetCoordValue(), 0));
       }
       else if (eCSSUnit_Inherit == value.GetUnit()) {
-        canStoreInRuleTree = false;
+        conditions.SetUncacheable();
         border->SetBorderWidth(side,
                                parentBorder->GetComputedBorder().Side(side));
       }
       else if (eCSSUnit_Initial == value.GetUnit() ||
                eCSSUnit_Unset == value.GetUnit()) {
         border->SetBorderWidth(side,
           (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
       }
@@ -6806,17 +6810,17 @@ nsRuleNode::ComputeBorderData(void* aSta
       if (eCSSUnit_Enumerated == unit) {
         border->SetBorderStyle(side, value.GetIntValue());
       }
       else if (eCSSUnit_Initial == unit ||
                eCSSUnit_Unset == unit) {
         border->SetBorderStyle(side, NS_STYLE_BORDER_STYLE_NONE);
       }
       else if (eCSSUnit_Inherit == unit) {
-        canStoreInRuleTree = false;
+        conditions.SetUncacheable();
         border->SetBorderStyle(side, parentBorder->GetBorderStyle(side));
       }
     }
   }
 
   // -moz-border-*-colors: color, string, enum, none, inherit/initial
   nscolor borderColor;
   nscolor unused = NS_RGB(0,0,0);
@@ -6836,17 +6840,17 @@ nsRuleNode::ComputeBorderData(void* aSta
 
     case eCSSUnit_Initial:
     case eCSSUnit_Unset:
     case eCSSUnit_None:
       border->ClearBorderColors(side);
       break;
 
     case eCSSUnit_Inherit: {
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       border->ClearBorderColors(side);
       if (parentContext) {
         nsBorderColors *parentColors;
         parentBorder->GetCompositeColors(side, &parentColors);
         if (parentColors) {
           border->EnsureBorderColors();
           border->mBorderColors[side] = parentColors->Clone();
         }
@@ -6858,17 +6862,17 @@ nsRuleNode::ComputeBorderData(void* aSta
     case eCSSUnit_ListDep: {
       // Some composite border color information has been specified for this
       // border side.
       border->EnsureBorderColors();
       border->ClearBorderColors(side);
       const nsCSSValueList* list = value.GetListValue();
       while (list) {
         if (SetColor(list->mValue, unused, mPresContext,
-                     aContext, borderColor, canStoreInRuleTree))
+                     aContext, borderColor, conditions))
           border->AppendBorderColor(side, borderColor);
         else {
           NS_NOTREACHED("unexpected item in -moz-border-*-colors list");
         }
         list = list->mNext;
       }
       break;
     }
@@ -6881,17 +6885,17 @@ nsRuleNode::ComputeBorderData(void* aSta
   // border-color, border-*-color: color, string, enum, inherit
   {
     const nsCSSProperty* subprops =
       nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color);
     bool foreground;
     NS_FOR_CSS_SIDES(side) {
       const nsCSSValue& value = *aRuleData->ValueFor(subprops[side]);
       if (eCSSUnit_Inherit == value.GetUnit()) {
-        canStoreInRuleTree = false;
+        conditions.SetUncacheable();
         if (parentContext) {
           parentBorder->GetBorderColor(side, borderColor, foreground);
           if (foreground) {
             // We want to inherit the color from the parent, not use the
             // color on the element where this chunk of style data will be
             // used.  We can ensure that the data for the parent are fully
             // computed (unlike for the element where this will be used, for
             // which the color could be specified on a more specific rule).
@@ -6899,17 +6903,17 @@ nsRuleNode::ComputeBorderData(void* aSta
           } else
             border->SetBorderColor(side, borderColor);
         } else {
           // We're the root
           border->SetBorderToForeground(side);
         }
       }
       else if (SetColor(value, unused, mPresContext, aContext, borderColor,
-                        canStoreInRuleTree)) {
+                        conditions)) {
         border->SetBorderColor(side, borderColor);
       }
       else if (eCSSUnit_Enumerated == value.GetUnit()) {
         switch (value.GetIntValue()) {
           case NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR:
             border->SetBorderToForeground(side);
             break;
           default:
@@ -6934,51 +6938,51 @@ nsRuleNode::ComputeBorderData(void* aSta
       const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
       nsStyleCoord parentX = parentBorder->mBorderRadius.Get(cx);
       nsStyleCoord parentY = parentBorder->mBorderRadius.Get(cy);
       nsStyleCoord coordX, coordY;
 
       if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
                         SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
                           SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
-                        aContext, mPresContext, canStoreInRuleTree)) {
+                        aContext, mPresContext, conditions)) {
         border->mBorderRadius.Set(cx, coordX);
         border->mBorderRadius.Set(cy, coordY);
       }
     }
   }
 
   // float-edge: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForFloatEdge(),
-              border->mFloatEdge, canStoreInRuleTree,
+              border->mFloatEdge, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentBorder->mFloatEdge,
               NS_STYLE_FLOAT_EDGE_CONTENT, 0, 0, 0, 0);
 
   // border-image-source
   const nsCSSValue* borderImageSource = aRuleData->ValueForBorderImageSource();
   if (borderImageSource->GetUnit() == eCSSUnit_Inherit) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     border->mBorderImageSource = parentBorder->mBorderImageSource;
   } else {
     SetStyleImage(aContext,
                   *borderImageSource,
                   border->mBorderImageSource,
-                  canStoreInRuleTree);
+                  conditions);
   }
 
   nsCSSValue borderImageSliceValue;
   nsCSSValue borderImageSliceFill;
   SetBorderImageSlice(*aRuleData->ValueForBorderImageSlice(),
                       borderImageSliceValue, borderImageSliceFill);
 
   // border-image-slice: fill
   SetDiscrete(borderImageSliceFill,
               border->mBorderImageFill,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentBorder->mBorderImageFill,
               NS_STYLE_BORDER_IMAGE_SLICE_NOFILL, 0, 0, 0, 0);
 
   nsCSSRect borderImageSlice;
   SetBorderImageRect(borderImageSliceValue, borderImageSlice);
 
   nsCSSRect borderImageWidth;
@@ -6991,156 +6995,156 @@ nsRuleNode::ComputeBorderData(void* aSta
 
   NS_FOR_CSS_SIDES (side) {
     // border-image-slice
     if (SetCoord(borderImageSlice.*(nsCSSRect::sides[side]), coord,
                  parentBorder->mBorderImageSlice.Get(side),
                  SETCOORD_FACTOR | SETCOORD_PERCENT |
                    SETCOORD_INHERIT | SETCOORD_INITIAL_HUNDRED_PCT |
                    SETCOORD_UNSET_INITIAL,
-                 aContext, mPresContext, canStoreInRuleTree)) {
+                 aContext, mPresContext, conditions)) {
       border->mBorderImageSlice.Set(side, coord);
     }
 
     // border-image-width
     // 'auto' here means "same as slice"
     if (SetCoord(borderImageWidth.*(nsCSSRect::sides[side]), coord,
                  parentBorder->mBorderImageWidth.Get(side),
                  SETCOORD_LPAH | SETCOORD_FACTOR | SETCOORD_INITIAL_FACTOR_ONE |
                    SETCOORD_UNSET_INITIAL,
-                 aContext, mPresContext, canStoreInRuleTree)) {
+                 aContext, mPresContext, conditions)) {
       border->mBorderImageWidth.Set(side, coord);
     }
 
     // border-image-outset
     if (SetCoord(borderImageOutset.*(nsCSSRect::sides[side]), coord,
                  parentBorder->mBorderImageOutset.Get(side),
                  SETCOORD_LENGTH | SETCOORD_FACTOR |
                    SETCOORD_INHERIT | SETCOORD_INITIAL_FACTOR_ZERO |
                    SETCOORD_UNSET_INITIAL,
-                 aContext, mPresContext, canStoreInRuleTree)) {
+                 aContext, mPresContext, conditions)) {
       border->mBorderImageOutset.Set(side, coord);
     }
   }
 
   // border-image-repeat
   nsCSSValuePair borderImageRepeat;
   SetBorderImagePair(*aRuleData->ValueForBorderImageRepeat(),
                      borderImageRepeat);
 
   SetDiscrete(borderImageRepeat.mXValue,
               border->mBorderImageRepeatH,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentBorder->mBorderImageRepeatH,
               NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
 
   SetDiscrete(borderImageRepeat.mYValue,
               border->mBorderImageRepeatV,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentBorder->mBorderImageRepeatV,
               NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
 
   border->TrackImage(aContext->PresContext());
 
   COMPUTE_END_RESET(Border, border)
 }
 
 const void*
 nsRuleNode::ComputePaddingData(void* aStartStruct,
                                const nsRuleData* aRuleData,
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
                                const RuleDetail aRuleDetail,
-                               const bool aCanStoreInRuleTree)
+                               const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(Padding, (), padding, parentPadding)
 
   // padding: length, percent, calc, inherit
   const nsCSSProperty* subprops =
     nsCSSProps::SubpropertyEntryFor(eCSSProperty_padding);
   nsStyleCoord coord;
   NS_FOR_CSS_SIDES(side) {
     nsStyleCoord parentCoord = parentPadding->mPadding.Get(side);
     if (SetCoord(*aRuleData->ValueFor(subprops[side]),
                  coord, parentCoord,
                  SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
                    SETCOORD_UNSET_INITIAL,
-                 aContext, mPresContext, canStoreInRuleTree)) {
+                 aContext, mPresContext, conditions)) {
       padding->mPadding.Set(side, coord);
     }
   }
 
   padding->RecalcData();
   COMPUTE_END_RESET(Padding, padding)
 }
 
 const void*
 nsRuleNode::ComputeOutlineData(void* aStartStruct,
                                const nsRuleData* aRuleData,
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
                                const RuleDetail aRuleDetail,
-                               const bool aCanStoreInRuleTree)
+                               const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(Outline, (mPresContext), outline, parentOutline)
 
   // outline-width: length, enum, inherit
   const nsCSSValue* outlineWidthValue = aRuleData->ValueForOutlineWidth();
   if (eCSSUnit_Initial == outlineWidthValue->GetUnit() ||
       eCSSUnit_Unset == outlineWidthValue->GetUnit()) {
     outline->mOutlineWidth =
       nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
   }
   else {
     SetCoord(*outlineWidthValue, outline->mOutlineWidth,
              parentOutline->mOutlineWidth,
              SETCOORD_LEH | SETCOORD_CALC_LENGTH_ONLY, aContext,
-             mPresContext, canStoreInRuleTree);
+             mPresContext, conditions);
   }
 
   // outline-offset: length, inherit
   nsStyleCoord tempCoord;
   const nsCSSValue* outlineOffsetValue = aRuleData->ValueForOutlineOffset();
   if (SetCoord(*outlineOffsetValue, tempCoord,
                nsStyleCoord(parentOutline->mOutlineOffset,
                             nsStyleCoord::CoordConstructor),
                SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
                  SETCOORD_UNSET_INITIAL,
-               aContext, mPresContext, canStoreInRuleTree)) {
+               aContext, mPresContext, conditions)) {
     outline->mOutlineOffset = tempCoord.GetCoordValue();
   } else {
     NS_ASSERTION(outlineOffsetValue->GetUnit() == eCSSUnit_Null,
                  "unexpected unit");
   }
 
   // outline-color: color, string, enum, inherit
   nscolor outlineColor;
   nscolor unused = NS_RGB(0,0,0);
   const nsCSSValue* outlineColorValue = aRuleData->ValueForOutlineColor();
   if (eCSSUnit_Inherit == outlineColorValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     if (parentContext) {
       if (parentOutline->GetOutlineColor(outlineColor))
         outline->SetOutlineColor(outlineColor);
       else {
         // We want to inherit the color from the parent, not use the
         // color on the element where this chunk of style data will be
         // used.  We can ensure that the data for the parent are fully
         // computed (unlike for the element where this will be used, for
         // which the color could be specified on a more specific rule).
         outline->SetOutlineColor(parentContext->StyleColor()->mColor);
       }
     } else {
       outline->SetOutlineInitialColor();
     }
   }
   else if (SetColor(*outlineColorValue, unused, mPresContext,
-                    aContext, outlineColor, canStoreInRuleTree))
+                    aContext, outlineColor, conditions))
     outline->SetOutlineColor(outlineColor);
   else if (eCSSUnit_Enumerated == outlineColorValue->GetUnit() ||
            eCSSUnit_Initial == outlineColorValue->GetUnit() ||
            eCSSUnit_Unset == outlineColorValue->GetUnit()) {
     outline->SetOutlineInitialColor();
   }
 
   // -moz-outline-radius: length, percent, inherit
@@ -7153,17 +7157,17 @@ nsRuleNode::ComputeOutlineData(void* aSt
       const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
       nsStyleCoord parentX = parentOutline->mOutlineRadius.Get(cx);
       nsStyleCoord parentY = parentOutline->mOutlineRadius.Get(cy);
       nsStyleCoord coordX, coordY;
 
       if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
                         SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
                           SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
-                        aContext, mPresContext, canStoreInRuleTree)) {
+                        aContext, mPresContext, conditions)) {
         outline->mOutlineRadius.Set(cx, coordX);
         outline->mOutlineRadius.Set(cy, coordY);
       }
     }
   }
 
   // outline-style: enum, inherit, initial
   // cannot use SetDiscrete because of SetOutlineStyle
@@ -7172,40 +7176,40 @@ nsRuleNode::ComputeOutlineData(void* aSt
   MOZ_ASSERT(eCSSUnit_None != unit && eCSSUnit_Auto != unit,
              "'none' and 'auto' should be handled as enumerated values");
   if (eCSSUnit_Enumerated == unit) {
     outline->SetOutlineStyle(outlineStyleValue->GetIntValue());
   } else if (eCSSUnit_Initial == unit ||
              eCSSUnit_Unset == unit) {
     outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_NONE);
   } else if (eCSSUnit_Inherit == unit) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     outline->SetOutlineStyle(parentOutline->GetOutlineStyle());
   }
 
   outline->RecalcData(mPresContext);
   COMPUTE_END_RESET(Outline, outline)
 }
 
 const void*
 nsRuleNode::ComputeListData(void* aStartStruct,
                             const nsRuleData* aRuleData,
                             nsStyleContext* aContext,
                             nsRuleNode* aHighestNode,
                             const RuleDetail aRuleDetail,
-                            const bool aCanStoreInRuleTree)
+                            const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(List, (mPresContext), list, parentList)
 
   // list-style-type: string, none, inherit, initial
   const nsCSSValue* typeValue = aRuleData->ValueForListStyleType();
   switch (typeValue->GetUnit()) {
     case eCSSUnit_Unset:
     case eCSSUnit_Inherit: {
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       nsString type;
       parentList->GetListStyleType(type);
       list->SetListStyleType(type, parentList->GetCounterStyle());
       break;
     }
     case eCSSUnit_Initial:
       list->SetListStyleType(NS_LITERAL_STRING("disc"), mPresContext);
       break;
@@ -7267,35 +7271,35 @@ nsRuleNode::ComputeListData(void* aStart
                                   imageValue->GetImageValue)
   }
   else if (eCSSUnit_None == imageValue->GetUnit() ||
            eCSSUnit_Initial == imageValue->GetUnit()) {
     list->SetListStyleImage(nullptr);
   }
   else if (eCSSUnit_Inherit == imageValue->GetUnit() ||
            eCSSUnit_Unset == imageValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     NS_SET_IMAGE_REQUEST(list->SetListStyleImage,
                          aContext,
                          parentList->GetListStyleImage())
   }
 
   // list-style-position: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForListStylePosition(),
-              list->mListStylePosition, canStoreInRuleTree,
+              list->mListStylePosition, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentList->mListStylePosition,
               NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, 0, 0, 0, 0);
 
   // image region property: length, auto, inherit
   const nsCSSValue* imageRegionValue = aRuleData->ValueForImageRegion();
   switch (imageRegionValue->GetUnit()) {
   case eCSSUnit_Inherit:
   case eCSSUnit_Unset:
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     list->mImageRegion = parentList->mImageRegion;
     break;
 
   case eCSSUnit_Initial:
   case eCSSUnit_Auto:
     list->mImageRegion.SetRect(0,0,0,0);
     break;
 
@@ -7304,128 +7308,128 @@ nsRuleNode::ComputeListData(void* aStart
 
   case eCSSUnit_Rect: {
     const nsCSSRect& rgnRect = imageRegionValue->GetRectValue();
 
     if (rgnRect.mTop.GetUnit() == eCSSUnit_Auto)
       list->mImageRegion.y = 0;
     else if (rgnRect.mTop.IsLengthUnit())
       list->mImageRegion.y =
-        CalcLength(rgnRect.mTop, aContext, mPresContext, canStoreInRuleTree);
+        CalcLength(rgnRect.mTop, aContext, mPresContext, conditions);
 
     if (rgnRect.mBottom.GetUnit() == eCSSUnit_Auto)
       list->mImageRegion.height = 0;
     else if (rgnRect.mBottom.IsLengthUnit())
       list->mImageRegion.height =
         CalcLength(rgnRect.mBottom, aContext, mPresContext,
-                   canStoreInRuleTree) - list->mImageRegion.y;
+                   conditions) - list->mImageRegion.y;
 
     if (rgnRect.mLeft.GetUnit() == eCSSUnit_Auto)
       list->mImageRegion.x = 0;
     else if (rgnRect.mLeft.IsLengthUnit())
       list->mImageRegion.x =
-        CalcLength(rgnRect.mLeft, aContext, mPresContext, canStoreInRuleTree);
+        CalcLength(rgnRect.mLeft, aContext, mPresContext, conditions);
 
     if (rgnRect.mRight.GetUnit() == eCSSUnit_Auto)
       list->mImageRegion.width = 0;
     else if (rgnRect.mRight.IsLengthUnit())
       list->mImageRegion.width =
         CalcLength(rgnRect.mRight, aContext, mPresContext,
-                   canStoreInRuleTree) - list->mImageRegion.x;
+                   conditions) - list->mImageRegion.x;
     break;
   }
 
   default:
     MOZ_ASSERT(false, "unrecognized image-region unit");
   }
 
   COMPUTE_END_INHERITED(List, list)
 }
 
 static void
 SetGridTrackBreadth(const nsCSSValue& aValue,
                     nsStyleCoord& aResult,
                     nsStyleContext* aStyleContext,
                     nsPresContext* aPresContext,
-                    bool& aCanStoreInRuleTree)
+                    RuleNodeCacheConditions& aConditions)
 {
   nsCSSUnit unit = aValue.GetUnit();
   if (unit == eCSSUnit_FlexFraction) {
     aResult.SetFlexFractionValue(aValue.GetFloatValue());
   } else if (unit == eCSSUnit_Auto) {
     aResult.SetAutoValue();
   } else {
     MOZ_ASSERT(unit != eCSSUnit_Inherit && unit != eCSSUnit_Unset,
                "Unexpected value that would use dummyParentCoord");
     const nsStyleCoord dummyParentCoord;
     SetCoord(aValue, aResult, dummyParentCoord,
              SETCOORD_LPE | SETCOORD_STORE_CALC,
-             aStyleContext, aPresContext, aCanStoreInRuleTree);
+             aStyleContext, aPresContext, aConditions);
   }
 }
 
 static void
 SetGridTrackSize(const nsCSSValue& aValue,
                  nsStyleCoord& aResultMin,
                  nsStyleCoord& aResultMax,
                  nsStyleContext* aStyleContext,
                  nsPresContext* aPresContext,
-                 bool& aCanStoreInRuleTree)
+                 RuleNodeCacheConditions& aConditions)
 {
   if (aValue.GetUnit() == eCSSUnit_Function) {
     // A minmax() function.
     nsCSSValue::Array* func = aValue.GetArrayValue();
     NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_minmax,
                  "Expected minmax(), got another function name");
     SetGridTrackBreadth(func->Item(1), aResultMin,
-                        aStyleContext, aPresContext, aCanStoreInRuleTree);
+                        aStyleContext, aPresContext, aConditions);
     SetGridTrackBreadth(func->Item(2), aResultMax,
-                        aStyleContext, aPresContext, aCanStoreInRuleTree);
+                        aStyleContext, aPresContext, aConditions);
   } else {
     // A single <track-breadth>,
     // specifies identical min and max sizing functions.
     SetGridTrackBreadth(aValue, aResultMin,
-                        aStyleContext, aPresContext, aCanStoreInRuleTree);
+                        aStyleContext, aPresContext, aConditions);
     aResultMax = aResultMin;
   }
 }
 
 static void
 SetGridAutoColumnsRows(const nsCSSValue& aValue,
                        nsStyleCoord& aResultMin,
                        nsStyleCoord& aResultMax,
                        const nsStyleCoord& aParentValueMin,
                        const nsStyleCoord& aParentValueMax,
                        nsStyleContext* aStyleContext,
                        nsPresContext* aPresContext,
-                       bool& aCanStoreInRuleTree)
+                       RuleNodeCacheConditions& aConditions)
 
 {
   switch (aValue.GetUnit()) {
   case eCSSUnit_Null:
     break;
 
   case eCSSUnit_Inherit:
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aResultMin = aParentValueMin;
     aResultMax = aParentValueMax;
     break;
 
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
     // The initial value is 'auto',
     // which computes to 'minmax(auto, auto)'.
     // (Explicitly-specified 'auto' values are handled in SetGridTrackSize.)
     aResultMin.SetAutoValue();
     aResultMax.SetAutoValue();
     break;
 
   default:
     SetGridTrackSize(aValue, aResultMin, aResultMax,
-                     aStyleContext, aPresContext, aCanStoreInRuleTree);
+                     aStyleContext, aPresContext, aConditions);
   }
 }
 
 static void
 AppendGridLineNames(const nsCSSValue& aValue,
                     nsStyleGridTemplate& aResult)
 {
   // Compute a <line-names> value
@@ -7442,25 +7446,25 @@ AppendGridLineNames(const nsCSSValue& aV
 }
 
 static void
 SetGridTrackList(const nsCSSValue& aValue,
                  nsStyleGridTemplate& aResult,
                  const nsStyleGridTemplate& aParentValue,
                  nsStyleContext* aStyleContext,
                  nsPresContext* aPresContext,
-                 bool& aCanStoreInRuleTree)
+                 RuleNodeCacheConditions& aConditions)
 
 {
   switch (aValue.GetUnit()) {
   case eCSSUnit_Null:
     break;
 
   case eCSSUnit_Inherit:
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aResult.mIsSubgrid = aParentValue.mIsSubgrid;
     aResult.mLineNameLists = aParentValue.mLineNameLists;
     aResult.mMinTrackSizingFunctions = aParentValue.mMinTrackSizingFunctions;
     aResult.mMaxTrackSizingFunctions = aParentValue.mMaxTrackSizingFunctions;
     break;
 
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
@@ -7497,17 +7501,17 @@ SetGridTrackList(const nsCSSValue& aValu
 
         if (!item) {
           break;
         }
 
         nsStyleCoord& min = *aResult.mMinTrackSizingFunctions.AppendElement();
         nsStyleCoord& max = *aResult.mMaxTrackSizingFunctions.AppendElement();
         SetGridTrackSize(item->mValue, min, max,
-                         aStyleContext, aPresContext, aCanStoreInRuleTree);
+                         aStyleContext, aPresContext, aConditions);
 
         item = item->mNext;
         MOZ_ASSERT(item, "Expected a eCSSUnit_List of odd length");
       }
       MOZ_ASSERT(!aResult.mMinTrackSizingFunctions.IsEmpty() &&
                  aResult.mMinTrackSizingFunctions.Length() ==
                  aResult.mMaxTrackSizingFunctions.Length() &&
                  aResult.mMinTrackSizingFunctions.Length() + 1 ==
@@ -7516,24 +7520,24 @@ SetGridTrackList(const nsCSSValue& aValu
     }
   }
 }
 
 static void
 SetGridTemplateAreas(const nsCSSValue& aValue,
                      nsRefPtr<css::GridTemplateAreasValue>* aResult,
                      css::GridTemplateAreasValue* aParentValue,
-                     bool& aCanStoreInRuleTree)
+                     RuleNodeCacheConditions& aConditions)
 {
   switch (aValue.GetUnit()) {
   case eCSSUnit_Null:
     break;
 
   case eCSSUnit_Inherit:
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     *aResult = aParentValue;
     break;
 
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
   case eCSSUnit_None:
     *aResult = nullptr;
     break;
@@ -7542,25 +7546,25 @@ SetGridTemplateAreas(const nsCSSValue& a
     *aResult = aValue.GetGridTemplateAreas();
   }
 }
 
 static void
 SetGridLine(const nsCSSValue& aValue,
             nsStyleGridLine& aResult,
             const nsStyleGridLine& aParentValue,
-            bool& aCanStoreInRuleTree)
+            RuleNodeCacheConditions& aConditions)
 
 {
   switch (aValue.GetUnit()) {
   case eCSSUnit_Null:
     break;
 
   case eCSSUnit_Inherit:
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aResult = aParentValue;
     break;
 
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
   case eCSSUnit_Auto:
     aResult.SetAuto();
     break;
@@ -7588,17 +7592,17 @@ SetGridLine(const nsCSSValue& aValue,
 }
 
 const void*
 nsRuleNode::ComputePositionData(void* aStartStruct,
                                 const nsRuleData* aRuleData,
                                 nsStyleContext* aContext,
                                 nsRuleNode* aHighestNode,
                                 const RuleDetail aRuleDetail,
-                                const bool aCanStoreInRuleTree)
+                                const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(Position, (), pos, parentPos)
 
   // box offsets: length, percent, calc, auto, inherit
   static const nsCSSProperty offsetProps[] = {
     eCSSProperty_top,
     eCSSProperty_right,
     eCSSProperty_bottom,
@@ -7606,77 +7610,77 @@ nsRuleNode::ComputePositionData(void* aS
   };
   nsStyleCoord  coord;
   NS_FOR_CSS_SIDES(side) {
     nsStyleCoord parentCoord = parentPos->mOffset.Get(side);
     if (SetCoord(*aRuleData->ValueFor(offsetProps[side]),
                  coord, parentCoord,
                  SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
                    SETCOORD_UNSET_INITIAL,
-                 aContext, mPresContext, canStoreInRuleTree)) {
+                 aContext, mPresContext, conditions)) {
       pos->mOffset.Set(side, coord);
     }
   }
 
   SetCoord(*aRuleData->ValueForWidth(), pos->mWidth, parentPos->mWidth,
            SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
              SETCOORD_UNSET_INITIAL,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
   SetCoord(*aRuleData->ValueForMinWidth(), pos->mMinWidth, parentPos->mMinWidth,
            SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
              SETCOORD_UNSET_INITIAL,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
   SetCoord(*aRuleData->ValueForMaxWidth(), pos->mMaxWidth, parentPos->mMaxWidth,
            SETCOORD_LPOEH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
              SETCOORD_UNSET_INITIAL,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
 
   // We can get enumerated values for {,min-,max-}height (-moz-min-content,
   // -moz-max-content, etc.) since we parse the logical properties with all the
   // values that width accepts.  If we get a value we don't support on these
   // properties, turn them into unset.
   const nsCSSValue* height = aRuleData->ValueForHeight();
   SetCoord(height->GetUnit() == eCSSUnit_Enumerated ?
              nsCSSValue(eCSSUnit_Unset) : *height,
            pos->mHeight, parentPos->mHeight,
            SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
              SETCOORD_UNSET_INITIAL,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
   const nsCSSValue* minHeight = aRuleData->ValueForMinHeight();
   SetCoord(minHeight->GetUnit() == eCSSUnit_Enumerated ?
              nsCSSValue(eCSSUnit_Unset) : *minHeight,
            pos->mMinHeight, parentPos->mMinHeight,
            SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
              SETCOORD_UNSET_INITIAL,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
   const nsCSSValue* maxHeight = aRuleData->ValueForMaxHeight();
   SetCoord(maxHeight->GetUnit() == eCSSUnit_Enumerated ?
              nsCSSValue(eCSSUnit_Unset) : *maxHeight,
            pos->mMaxHeight, parentPos->mMaxHeight,
            SETCOORD_LPOH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
              SETCOORD_UNSET_INITIAL,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
 
   // box-sizing: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForBoxSizing(),
-              pos->mBoxSizing, canStoreInRuleTree,
+              pos->mBoxSizing, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentPos->mBoxSizing,
               NS_STYLE_BOX_SIZING_CONTENT, 0, 0, 0, 0);
 
   // align-content: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForAlignContent(),
-              pos->mAlignContent, canStoreInRuleTree,
+              pos->mAlignContent, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentPos->mAlignContent,
               NS_STYLE_ALIGN_CONTENT_STRETCH, 0, 0, 0, 0);
 
   // align-items: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForAlignItems(),
-              pos->mAlignItems, canStoreInRuleTree,
+              pos->mAlignItems, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentPos->mAlignItems,
               NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE, 0, 0, 0, 0);
 
   // align-self: enum, inherit, initial
   // NOTE: align-self's initial value is the special keyword "auto", which is
   // supposed to compute to our parent's computed value of "align-items".  So
   // technically, "auto" itself is never a valid computed value for align-self,
@@ -7712,105 +7716,105 @@ nsRuleNode::ComputePositionData(void* aS
             grandparentContext->StylePosition();
           inheritedAlignSelf = grandparentPos->mAlignItems;
           aContext->AddStyleBit(NS_STYLE_USES_GRANDANCESTOR_STYLE);
         }
       }
     }
 
     pos->mAlignSelf = inheritedAlignSelf;
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
   } else {
     SetDiscrete(*aRuleData->ValueForAlignSelf(),
-                pos->mAlignSelf, canStoreInRuleTree,
+                pos->mAlignSelf, conditions,
                 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
                 parentPos->mAlignSelf, // (unused -- we handled inherit above)
                 NS_STYLE_ALIGN_SELF_AUTO, // initial == auto
                 0, 0, 0, 0);
   }
 
   // flex-basis: auto, length, percent, enum, calc, inherit, initial
   // (Note: The flags here should match those used for 'width' property above.)
   SetCoord(*aRuleData->ValueForFlexBasis(), pos->mFlexBasis, parentPos->mFlexBasis,
            SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
              SETCOORD_UNSET_INITIAL,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
 
   // flex-direction: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForFlexDirection(),
-              pos->mFlexDirection, canStoreInRuleTree,
+              pos->mFlexDirection, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentPos->mFlexDirection,
               NS_STYLE_FLEX_DIRECTION_ROW, 0, 0, 0, 0);
 
   // flex-grow: float, inherit, initial
   SetFactor(*aRuleData->ValueForFlexGrow(),
-            pos->mFlexGrow, canStoreInRuleTree,
+            pos->mFlexGrow, conditions,
             parentPos->mFlexGrow, 0.0f,
             SETFCT_UNSET_INITIAL);
 
   // flex-shrink: float, inherit, initial
   SetFactor(*aRuleData->ValueForFlexShrink(),
-            pos->mFlexShrink, canStoreInRuleTree,
+            pos->mFlexShrink, conditions,
             parentPos->mFlexShrink, 1.0f,
             SETFCT_UNSET_INITIAL);
 
   // flex-wrap: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForFlexWrap(),
-              pos->mFlexWrap, canStoreInRuleTree,
+              pos->mFlexWrap, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentPos->mFlexWrap,
               NS_STYLE_FLEX_WRAP_NOWRAP, 0, 0, 0, 0);
 
   // order: integer, inherit, initial
   SetDiscrete(*aRuleData->ValueForOrder(),
-              pos->mOrder, canStoreInRuleTree,
+              pos->mOrder, conditions,
               SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
               parentPos->mOrder,
               NS_STYLE_ORDER_INITIAL, 0, 0, 0, 0);
 
   // justify-content: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForJustifyContent(),
-              pos->mJustifyContent, canStoreInRuleTree,
+              pos->mJustifyContent, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentPos->mJustifyContent,
               NS_STYLE_JUSTIFY_CONTENT_FLEX_START, 0, 0, 0, 0);
 
   // object-fit: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForObjectFit(),
-              pos->mObjectFit, canStoreInRuleTree,
+              pos->mObjectFit, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentPos->mObjectFit,
               NS_STYLE_OBJECT_FIT_FILL, 0, 0, 0, 0);
 
   // object-position
   const nsCSSValue& objectPosition = *aRuleData->ValueForObjectPosition();
   switch (objectPosition.GetUnit()) {
     case eCSSUnit_Null:
       break;
     case eCSSUnit_Inherit:
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       pos->mObjectPosition = parentPos->mObjectPosition;
       break;
     case eCSSUnit_Initial:
     case eCSSUnit_Unset:
       pos->mObjectPosition.SetInitialPercentValues(0.5f);
       break;
     default:
       ComputePositionValue(aContext, objectPosition,
-                           pos->mObjectPosition, canStoreInRuleTree);
+                           pos->mObjectPosition, conditions);
   }
 
   // grid-auto-flow
   const nsCSSValue& gridAutoFlow = *aRuleData->ValueForGridAutoFlow();
   switch (gridAutoFlow.GetUnit()) {
     case eCSSUnit_Null:
       break;
     case eCSSUnit_Inherit:
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       pos->mGridAutoFlow = parentPos->mGridAutoFlow;
       break;
     case eCSSUnit_Initial:
     case eCSSUnit_Unset:
       pos->mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_ROW;
       break;
     default:
       NS_ASSERTION(gridAutoFlow.GetUnit() == eCSSUnit_Enumerated,
@@ -7819,94 +7823,94 @@ nsRuleNode::ComputePositionData(void* aS
   }
 
   // grid-auto-columns
   SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoColumns(),
                          pos->mGridAutoColumnsMin,
                          pos->mGridAutoColumnsMax,
                          parentPos->mGridAutoColumnsMin,
                          parentPos->mGridAutoColumnsMax,
-                         aContext, mPresContext, canStoreInRuleTree);
+                         aContext, mPresContext, conditions);
 
   // grid-auto-rows
   SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoRows(),
                          pos->mGridAutoRowsMin,
                          pos->mGridAutoRowsMax,
                          parentPos->mGridAutoRowsMin,
                          parentPos->mGridAutoRowsMax,
-                         aContext, mPresContext, canStoreInRuleTree);
+                         aContext, mPresContext, conditions);
 
   // grid-template-columns
   SetGridTrackList(*aRuleData->ValueForGridTemplateColumns(),
                    pos->mGridTemplateColumns, parentPos->mGridTemplateColumns,
-                   aContext, mPresContext, canStoreInRuleTree);
+                   aContext, mPresContext, conditions);
 
   // grid-template-rows
   SetGridTrackList(*aRuleData->ValueForGridTemplateRows(),
                    pos->mGridTemplateRows, parentPos->mGridTemplateRows,
-                   aContext, mPresContext, canStoreInRuleTree);
+                   aContext, mPresContext, conditions);
 
   // grid-tempate-areas
   SetGridTemplateAreas(*aRuleData->ValueForGridTemplateAreas(),
                        &pos->mGridTemplateAreas,
                        parentPos->mGridTemplateAreas,
-                       canStoreInRuleTree);
+                       conditions);
 
   // grid-column-start
   SetGridLine(*aRuleData->ValueForGridColumnStart(),
               pos->mGridColumnStart,
               parentPos->mGridColumnStart,
-              canStoreInRuleTree);
+              conditions);
 
   // grid-column-end
   SetGridLine(*aRuleData->ValueForGridColumnEnd(),
               pos->mGridColumnEnd,
               parentPos->mGridColumnEnd,
-              canStoreInRuleTree);
+              conditions);
 
   // grid-row-start
   SetGridLine(*aRuleData->ValueForGridRowStart(),
               pos->mGridRowStart,
               parentPos->mGridRowStart,
-              canStoreInRuleTree);
+              conditions);
 
   // grid-row-end
   SetGridLine(*aRuleData->ValueForGridRowEnd(),
               pos->mGridRowEnd,
               parentPos->mGridRowEnd,
-              canStoreInRuleTree);
+              conditions);
 
   // z-index
   const nsCSSValue* zIndexValue = aRuleData->ValueForZIndex();
   if (! SetCoord(*zIndexValue, pos->mZIndex, parentPos->mZIndex,
                  SETCOORD_IA | SETCOORD_INITIAL_AUTO | SETCOORD_UNSET_INITIAL,
-                 aContext, nullptr, canStoreInRuleTree)) {
+                 aContext, nullptr, conditions)) {
     if (eCSSUnit_Inherit == zIndexValue->GetUnit()) {
       // handle inherit, because it's ok to inherit 'auto' here
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       pos->mZIndex = parentPos->mZIndex;
     }
   }
 
   COMPUTE_END_RESET(Position, pos)
 }
 
 const void*
 nsRuleNode::ComputeTableData(void* aStartStruct,
                              const nsRuleData* aRuleData,
                              nsStyleContext* aContext,
                              nsRuleNode* aHighestNode,
                              const RuleDetail aRuleDetail,
-                             const bool aCanStoreInRuleTree)
+                             const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(Table, (), table, parentTable)
 
   // table-layout: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForTableLayout(),
-              table->mLayoutStrategy, canStoreInRuleTree,
+              table->mLayoutStrategy, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentTable->mLayoutStrategy,
               NS_STYLE_TABLE_LAYOUT_AUTO, 0, 0, 0, 0);
 
   // span: pixels (not a real CSS prop)
   const nsCSSValue* spanValue = aRuleData->ValueForSpan();
   if (eCSSUnit_Enumerated == spanValue->GetUnit() ||
       eCSSUnit_Integer == spanValue->GetUnit())
@@ -7916,23 +7920,23 @@ nsRuleNode::ComputeTableData(void* aStar
 }
 
 const void*
 nsRuleNode::ComputeTableBorderData(void* aStartStruct,
                                    const nsRuleData* aRuleData,
                                    nsStyleContext* aContext,
                                    nsRuleNode* aHighestNode,
                                    const RuleDetail aRuleDetail,
-                                   const bool aCanStoreInRuleTree)
+                                   const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(TableBorder, (), table, parentTable)
 
   // border-collapse: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForBorderCollapse(), table->mBorderCollapse,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentTable->mBorderCollapse,
               NS_STYLE_BORDER_SEPARATE, 0, 0, 0, 0);
 
   const nsCSSValue* borderSpacingValue = aRuleData->ValueForBorderSpacing();
   // border-spacing: pair(length), inherit
   if (borderSpacingValue->GetUnit() != eCSSUnit_Null) {
     nsStyleCoord parentCol(parentTable->mBorderSpacingCol,
@@ -7944,47 +7948,47 @@ nsRuleNode::ComputeTableBorderData(void*
 #ifdef DEBUG
     bool result =
 #endif
       SetPairCoords(*borderSpacingValue,
                     coordCol, coordRow, parentCol, parentRow,
                     SETCOORD_LH | SETCOORD_INITIAL_ZERO |
                       SETCOORD_CALC_LENGTH_ONLY |
                       SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INHERIT,
-                    aContext, mPresContext, canStoreInRuleTree);
+                    aContext, mPresContext, conditions);
     NS_ASSERTION(result, "malformed table border value");
     table->mBorderSpacingCol = coordCol.GetCoordValue();
     table->mBorderSpacingRow = coordRow.GetCoordValue();
   }
 
   // caption-side: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForCaptionSide(),
-              table->mCaptionSide, canStoreInRuleTree,
+              table->mCaptionSide, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentTable->mCaptionSide,
               NS_STYLE_CAPTION_SIDE_TOP, 0, 0, 0, 0);
 
   // empty-cells: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForEmptyCells(),
-              table->mEmptyCells, canStoreInRuleTree,
+              table->mEmptyCells, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentTable->mEmptyCells,
               NS_STYLE_TABLE_EMPTY_CELLS_SHOW,
               0, 0, 0, 0);
 
   COMPUTE_END_INHERITED(TableBorder, table)
 }
 
 const void*
 nsRuleNode::ComputeContentData(void* aStartStruct,
                                const nsRuleData* aRuleData,
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
                                const RuleDetail aRuleDetail,
-                               const bool aCanStoreInRuleTree)
+                               const RuleNodeCacheConditions aConditions)
 {
   uint32_t count;
   nsAutoString buffer;
 
   COMPUTE_START_RESET(Content, (), content, parentContent)
 
   // content: [string, url, counter, attr, enum]+, normal, none, inherit
   const nsCSSValue* contentValue = aRuleData->ValueForContent();
@@ -7996,17 +8000,17 @@ nsRuleNode::ComputeContentData(void* aSt
   case eCSSUnit_None:
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
     // "normal", "none", "initial" and "unset" all mean no content
     content->AllocateContents(0);
     break;
 
   case eCSSUnit_Inherit:
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     count = parentContent->ContentCount();
     if (NS_SUCCEEDED(content->AllocateContents(count))) {
       while (0 < count--) {
         content->ContentAt(count) = parentContent->ContentAt(count);
       }
     }
     break;
 
@@ -8098,17 +8102,17 @@ nsRuleNode::ComputeContentData(void* aSt
 
   case eCSSUnit_None:
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
     content->AllocateCounterIncrements(0);
     break;
 
   case eCSSUnit_Inherit:
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     count = parentContent->CounterIncrementCount();
     if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
       while (0 < count--) {
         const nsStyleCounterData *data =
           parentContent->GetCounterIncrementAt(count);
         content->SetCounterIncrementAt(count, data->mCounter, data->mValue);
       }
     }
@@ -8151,17 +8155,17 @@ nsRuleNode::ComputeContentData(void* aSt
 
   case eCSSUnit_None:
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
     content->AllocateCounterResets(0);
     break;
 
   case eCSSUnit_Inherit:
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     count = parentContent->CounterResetCount();
     if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
       while (0 < count--) {
         const nsStyleCounterData *data =
           parentContent->GetCounterResetAt(count);
         content->SetCounterResetAt(count, data->mCounter, data->mValue);
       }
     }
@@ -8195,17 +8199,17 @@ nsRuleNode::ComputeContentData(void* aSt
   default:
     MOZ_ASSERT(false, "unexpected value unit");
   }
 
   // marker-offset: length, auto, inherit
   SetCoord(*aRuleData->ValueForMarkerOffset(), content->mMarkerOffset, parentContent->mMarkerOffset,
            SETCOORD_LH | SETCOORD_AUTO | SETCOORD_INITIAL_AUTO |
              SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INITIAL,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
 
   // If we ended up with an image, track it.
   for (uint32_t i = 0; i < content->ContentCount(); ++i) {
     if ((content->ContentAt(i).mType == eStyleContentType_Image) &&
         content->ContentAt(i).mContent.mImage) {
       content->ContentAt(i).TrackImage(aContext->PresContext());
     }
   }
@@ -8214,28 +8218,28 @@ nsRuleNode::ComputeContentData(void* aSt
 }
 
 const void*
 nsRuleNode::ComputeQuotesData(void* aStartStruct,
                               const nsRuleData* aRuleData,
                               nsStyleContext* aContext,
                               nsRuleNode* aHighestNode,
                               const RuleDetail aRuleDetail,
-                              const bool aCanStoreInRuleTree)
+                              const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(Quotes, (), quotes, parentQuotes)
 
   // quotes: inherit, initial, none, [string string]+
   const nsCSSValue* quotesValue = aRuleData->ValueForQuotes();
   switch (quotesValue->GetUnit()) {
   case eCSSUnit_Null:
     break;
   case eCSSUnit_Inherit:
   case eCSSUnit_Unset:
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     quotes->CopyFrom(*parentQuotes);
     break;
   case eCSSUnit_Initial:
     quotes->SetInitial();
     break;
   case eCSSUnit_None:
     quotes->AllocateQuotes(0);
     break;
@@ -8269,64 +8273,64 @@ nsRuleNode::ComputeQuotesData(void* aSta
 }
 
 const void*
 nsRuleNode::ComputeXULData(void* aStartStruct,
                            const nsRuleData* aRuleData,
                            nsStyleContext* aContext,
                            nsRuleNode* aHighestNode,
                            const RuleDetail aRuleDetail,
-                           const bool aCanStoreInRuleTree)
+                           const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(XUL, (), xul, parentXUL)
 
   // box-align: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForBoxAlign(),
-              xul->mBoxAlign, canStoreInRuleTree,
+              xul->mBoxAlign, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentXUL->mBoxAlign,
               NS_STYLE_BOX_ALIGN_STRETCH, 0, 0, 0, 0);
 
   // box-direction: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForBoxDirection(),
-              xul->mBoxDirection, canStoreInRuleTree,
+              xul->mBoxDirection, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentXUL->mBoxDirection,
               NS_STYLE_BOX_DIRECTION_NORMAL, 0, 0, 0, 0);
 
   // box-flex: factor, inherit
   SetFactor(*aRuleData->ValueForBoxFlex(),
-            xul->mBoxFlex, canStoreInRuleTree,
+            xul->mBoxFlex, conditions,
             parentXUL->mBoxFlex, 0.0f,
             SETFCT_UNSET_INITIAL);
 
   // box-orient: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForBoxOrient(),
-              xul->mBoxOrient, canStoreInRuleTree,
+              xul->mBoxOrient, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentXUL->mBoxOrient,
               NS_STYLE_BOX_ORIENT_HORIZONTAL, 0, 0, 0, 0);
 
   // box-pack: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForBoxPack(),
-              xul->mBoxPack, canStoreInRuleTree,
+              xul->mBoxPack, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentXUL->mBoxPack,
               NS_STYLE_BOX_PACK_START, 0, 0, 0, 0);
 
   // box-ordinal-group: integer, inherit, initial
   SetDiscrete(*aRuleData->ValueForBoxOrdinalGroup(),
-              xul->mBoxOrdinal, canStoreInRuleTree,
+              xul->mBoxOrdinal, conditions,
               SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
               parentXUL->mBoxOrdinal, 1,
               0, 0, 0, 0);
 
   const nsCSSValue* stackSizingValue = aRuleData->ValueForStackSizing();
   if (eCSSUnit_Inherit == stackSizingValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     xul->mStretchStack = parentXUL->mStretchStack;
   } else if (eCSSUnit_Initial == stackSizingValue->GetUnit() ||
              eCSSUnit_Unset == stackSizingValue->GetUnit()) {
     xul->mStretchStack = true;
   } else if (eCSSUnit_Enumerated == stackSizingValue->GetUnit()) {
     xul->mStretchStack = stackSizingValue->GetIntValue() ==
       NS_STYLE_STACK_SIZING_STRETCH_TO_FIT;
   }
@@ -8335,34 +8339,34 @@ nsRuleNode::ComputeXULData(void* aStartS
 }
 
 const void*
 nsRuleNode::ComputeColumnData(void* aStartStruct,
                               const nsRuleData* aRuleData,
                               nsStyleContext* aContext,
                               nsRuleNode* aHighestNode,
                               const RuleDetail aRuleDetail,
-                              const bool aCanStoreInRuleTree)
+                              const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(Column, (mPresContext), column, parent)
 
   // column-width: length, auto, inherit
   SetCoord(*aRuleData->ValueForColumnWidth(),
            column->mColumnWidth, parent->mColumnWidth,
            SETCOORD_LAH | SETCOORD_INITIAL_AUTO |
              SETCOORD_CALC_LENGTH_ONLY | SETCOORD_CALC_CLAMP_NONNEGATIVE |
              SETCOORD_UNSET_INITIAL,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
 
   // column-gap: length, inherit, normal
   SetCoord(*aRuleData->ValueForColumnGap(),
            column->mColumnGap, parent->mColumnGap,
            SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
              SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INITIAL,
-           aContext, mPresContext, canStoreInRuleTree);
+           aContext, mPresContext, conditions);
   // clamp negative calc() to 0
   if (column->mColumnGap.GetUnit() == eStyleUnit_Coord) {
     column->mColumnGap.SetCoordValue(
       std::max(column->mColumnGap.GetCoordValue(), 0));
   }
 
   // column-count: auto, integer, inherit
   const nsCSSValue* columnCountValue = aRuleData->ValueForColumnCount();
@@ -8371,17 +8375,17 @@ nsRuleNode::ComputeColumnData(void* aSta
       eCSSUnit_Unset == columnCountValue->GetUnit()) {
     column->mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
   } else if (eCSSUnit_Integer == columnCountValue->GetUnit()) {
     column->mColumnCount = columnCountValue->GetIntValue();
     // Max kMaxColumnCount columns - wallpaper for bug 345583.
     column->mColumnCount = std::min(column->mColumnCount,
                                     nsStyleColumn::kMaxColumnCount);
   } else if (eCSSUnit_Inherit == columnCountValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     column->mColumnCount = parent->mColumnCount;
   }
 
   // column-rule-width: length, enum, inherit
   const nsCSSValue& widthValue = *aRuleData->ValueForColumnRuleWidth();
   if (eCSSUnit_Initial == widthValue.GetUnit() ||
       eCSSUnit_Unset == widthValue.GetUnit()) {
     column->SetColumnRuleWidth(
@@ -8392,21 +8396,21 @@ nsRuleNode::ComputeColumnData(void* aSta
                  widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
                  widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
                  "Unexpected enum value");
     column->SetColumnRuleWidth(
         (mPresContext->GetBorderWidthTable())[widthValue.GetIntValue()]);
   }
   else if (eCSSUnit_Inherit == widthValue.GetUnit()) {
     column->SetColumnRuleWidth(parent->GetComputedColumnRuleWidth());
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
   }
   else if (widthValue.IsLengthUnit() || widthValue.IsCalcUnit()) {
     nscoord len =
-      CalcLength(widthValue, aContext, mPresContext, canStoreInRuleTree);
+      CalcLength(widthValue, aContext, mPresContext, conditions);
     if (len < 0) {
       // FIXME: This is untested (by test_value_storage.html) for
       // column-rule-width since it gets covered up by the border
       // rounding code.
       NS_ASSERTION(widthValue.IsCalcUnit(),
                    "parser should have rejected negative length");
       len = 0;
     }
@@ -8420,24 +8424,24 @@ nsRuleNode::ComputeColumnData(void* aSta
   if (eCSSUnit_Enumerated == styleValue.GetUnit()) {
     column->mColumnRuleStyle = styleValue.GetIntValue();
   }
   else if (eCSSUnit_Initial == styleValue.GetUnit() ||
            eCSSUnit_Unset == styleValue.GetUnit()) {
     column->mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
   }
   else if (eCSSUnit_Inherit == styleValue.GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     column->mColumnRuleStyle = parent->mColumnRuleStyle;
   }
 
   // column-rule-color: color, inherit
   const nsCSSValue& colorValue = *aRuleData->ValueForColumnRuleColor();
   if (eCSSUnit_Inherit == colorValue.GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     column->mColumnRuleColorIsForeground = false;
     if (parent->mColumnRuleColorIsForeground) {
       if (parentContext) {
         column->mColumnRuleColor = parentContext->StyleColor()->mColor;
       } else {
         nsStyleColor defaultColumnRuleColor(mPresContext);
         column->mColumnRuleColor = defaultColumnRuleColor.mColor;
       }
@@ -8446,51 +8450,51 @@ nsRuleNode::ComputeColumnData(void* aSta
     }
   }
   else if (eCSSUnit_Initial == colorValue.GetUnit() ||
            eCSSUnit_Unset == colorValue.GetUnit() ||
            eCSSUnit_Enumerated == colorValue.GetUnit()) {
     column->mColumnRuleColorIsForeground = true;
   }
   else if (SetColor(colorValue, 0, mPresContext, aContext,
-                    column->mColumnRuleColor, canStoreInRuleTree)) {
+                    column->mColumnRuleColor, conditions)) {
     column->mColumnRuleColorIsForeground = false;
   }
 
   // column-fill: enum
   SetDiscrete(*aRuleData->ValueForColumnFill(),
-                column->mColumnFill, canStoreInRuleTree,
+                column->mColumnFill, conditions,
                 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
                 parent->mColumnFill,
                 NS_STYLE_COLUMN_FILL_BALANCE,
                 0, 0, 0, 0);
 
   COMPUTE_END_RESET(Column, column)
 }
 
 static void
 SetSVGPaint(const nsCSSValue& aValue, const nsStyleSVGPaint& parentPaint,
             nsPresContext* aPresContext, nsStyleContext *aContext,
             nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
-            bool& aCanStoreInRuleTree)
+            RuleNodeCacheConditions& aConditions)
 {
   nscolor color;
 
   if (aValue.GetUnit() == eCSSUnit_Inherit ||
       aValue.GetUnit() == eCSSUnit_Unset) {
     aResult = parentPaint;
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
   } else if (aValue.GetUnit() == eCSSUnit_None) {
     aResult.SetType(eStyleSVGPaintType_None);
   } else if (aValue.GetUnit() == eCSSUnit_Initial) {
     aResult.SetType(aInitialPaintType);
     aResult.mPaint.mColor = NS_RGB(0, 0, 0);
     aResult.mFallbackColor = NS_RGB(0, 0, 0);
   } else if (SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aContext,
-                      color, aCanStoreInRuleTree)) {
+                      color, aConditions)) {
     aResult.SetType(eStyleSVGPaintType_Color);
     aResult.mPaint.mColor = color;
   } else if (aValue.GetUnit() == eCSSUnit_Pair) {
     const nsCSSValuePair& pair = aValue.GetPairValue();
 
     if (pair.mXValue.GetUnit() == eCSSUnit_URL) {
       aResult.SetType(eStyleSVGPaintType_Server);
       aResult.mPaint.mPaintServer = pair.mXValue.GetURLValue();
@@ -8513,28 +8517,28 @@ SetSVGPaint(const nsCSSValue& aValue, co
     }
 
     if (pair.mYValue.GetUnit() == eCSSUnit_None) {
       aResult.mFallbackColor = NS_RGBA(0, 0, 0, 0);
     } else {
       MOZ_ASSERT(pair.mYValue.GetUnit() != eCSSUnit_Inherit,
                  "cannot inherit fallback colour");
       SetColor(pair.mYValue, NS_RGB(0, 0, 0), aPresContext, aContext,
-               aResult.mFallbackColor, aCanStoreInRuleTree);
+               aResult.mFallbackColor, aConditions);
     }
   } else {
     MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Null,
                "malformed paint server value");
   }
 }
 
 static void
 SetSVGOpacity(const nsCSSValue& aValue,
               float& aOpacityField, nsStyleSVGOpacitySource& aOpacityTypeField,
-              bool& aCanStoreInRuleTree,
+              RuleNodeCacheConditions& aConditions,
               float aParentOpacity, nsStyleSVGOpacitySource aParentOpacityType)
 {
   if (eCSSUnit_Enumerated == aValue.GetUnit()) {
     switch (aValue.GetIntValue()) {
     case NS_STYLE_CONTEXT_FILL_OPACITY:
       aOpacityTypeField = eStyleSVGOpacitySource_ContextFillOpacity;
       break;
     case NS_STYLE_CONTEXT_STROKE_OPACITY:
@@ -8542,120 +8546,120 @@ SetSVGOpacity(const nsCSSValue& aValue,
       break;
     default:
       NS_NOTREACHED("SetSVGOpacity: Unknown keyword");
     }
     // Fall back on fully opaque
     aOpacityField = 1.0f;
   } else if (eCSSUnit_Inherit == aValue.GetUnit() ||
              eCSSUnit_Unset == aValue.GetUnit()) {
-    aCanStoreInRuleTree = false;
+    aConditions.SetUncacheable();
     aOpacityField = aParentOpacity;
     aOpacityTypeField = aParentOpacityType;
   } else if (eCSSUnit_Null != aValue.GetUnit()) {
-    SetFactor(aValue, aOpacityField, aCanStoreInRuleTree,
+    SetFactor(aValue, aOpacityField, aConditions,
               aParentOpacity, 1.0f, SETFCT_OPACITY);
     aOpacityTypeField = eStyleSVGOpacitySource_Normal;
   }
 }
 
 const void*
 nsRuleNode::ComputeSVGData(void* aStartStruct,
                            const nsRuleData* aRuleData,
                            nsStyleContext* aContext,
                            nsRuleNode* aHighestNode,
                            const RuleDetail aRuleDetail,
-                           const bool aCanStoreInRuleTree)
+                           const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(SVG, (), svg, parentSVG)
 
   // clip-rule: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForClipRule(),
-              svg->mClipRule, canStoreInRuleTree,
+              svg->mClipRule, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mClipRule,
               NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
 
   // color-interpolation: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForColorInterpolation(),
-              svg->mColorInterpolation, canStoreInRuleTree,
+              svg->mColorInterpolation, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mColorInterpolation,
               NS_STYLE_COLOR_INTERPOLATION_SRGB, 0, 0, 0, 0);
 
   // color-interpolation-filters: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForColorInterpolationFilters(),
-              svg->mColorInterpolationFilters, canStoreInRuleTree,
+              svg->mColorInterpolationFilters, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mColorInterpolationFilters,
               NS_STYLE_COLOR_INTERPOLATION_LINEARRGB, 0, 0, 0, 0);
 
   // fill:
   SetSVGPaint(*aRuleData->ValueForFill(),
               parentSVG->mFill, mPresContext, aContext,
-              svg->mFill, eStyleSVGPaintType_Color, canStoreInRuleTree);
+              svg->mFill, eStyleSVGPaintType_Color, conditions);
 
   // fill-opacity: factor, inherit, initial,
   // context-fill-opacity, context-stroke-opacity
   nsStyleSVGOpacitySource contextFillOpacity = svg->mFillOpacitySource;
   SetSVGOpacity(*aRuleData->ValueForFillOpacity(),
-                svg->mFillOpacity, contextFillOpacity, canStoreInRuleTree,
+                svg->mFillOpacity, contextFillOpacity, conditions,
                 parentSVG->mFillOpacity, parentSVG->mFillOpacitySource);
   svg->mFillOpacitySource = contextFillOpacity;
 
   // fill-rule: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForFillRule(),
-              svg->mFillRule, canStoreInRuleTree,
+              svg->mFillRule, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mFillRule,
               NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
 
   // image-rendering: enum, inherit
   SetDiscrete(*aRuleData->ValueForImageRendering(),
-              svg->mImageRendering, canStoreInRuleTree,
+              svg->mImageRendering, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mImageRendering,
               NS_STYLE_IMAGE_RENDERING_AUTO, 0, 0, 0, 0);
 
   // marker-end: url, none, inherit
   const nsCSSValue* markerEndValue = aRuleData->ValueForMarkerEnd();
   if (eCSSUnit_URL == markerEndValue->GetUnit()) {
     svg->mMarkerEnd = markerEndValue->GetURLValue();
   } else if (eCSSUnit_None == markerEndValue->GetUnit() ||
              eCSSUnit_Initial == markerEndValue->GetUnit()) {
     svg->mMarkerEnd = nullptr;
   } else if (eCSSUnit_Inherit == markerEndValue->GetUnit() ||
              eCSSUnit_Unset == markerEndValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     svg->mMarkerEnd = parentSVG->mMarkerEnd;
   }
 
   // marker-mid: url, none, inherit
   const nsCSSValue* markerMidValue = aRuleData->ValueForMarkerMid();
   if (eCSSUnit_URL == markerMidValue->GetUnit()) {
     svg->mMarkerMid = markerMidValue->GetURLValue();
   } else if (eCSSUnit_None == markerMidValue->GetUnit() ||
              eCSSUnit_Initial == markerMidValue->GetUnit()) {
     svg->mMarkerMid = nullptr;
   } else if (eCSSUnit_Inherit == markerMidValue->GetUnit() ||
              eCSSUnit_Unset == markerMidValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     svg->mMarkerMid = parentSVG->mMarkerMid;
   }
 
   // marker-start: url, none, inherit
   const nsCSSValue* markerStartValue = aRuleData->ValueForMarkerStart();
   if (eCSSUnit_URL == markerStartValue->GetUnit()) {
     svg->mMarkerStart = markerStartValue->GetURLValue();
   } else if (eCSSUnit_None == markerStartValue->GetUnit() ||
              eCSSUnit_Initial == markerStartValue->GetUnit()) {
     svg->mMarkerStart = nullptr;
   } else if (eCSSUnit_Inherit == markerStartValue->GetUnit() ||
              eCSSUnit_Unset == markerStartValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     svg->mMarkerStart = parentSVG->mMarkerStart;
   }
 
   // paint-order: enum (bit field), inherit, initial
   const nsCSSValue* paintOrderValue = aRuleData->ValueForPaintOrder();
   switch (paintOrderValue->GetUnit()) {
     case eCSSUnit_Null:
       break;
@@ -8664,49 +8668,49 @@ nsRuleNode::ComputeSVGData(void* aStartS
       static_assert
         (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <= 8,
          "SVGStyleStruct::mPaintOrder not big enough");
       svg->mPaintOrder = static_cast<uint8_t>(paintOrderValue->GetIntValue());
       break;
 
     case eCSSUnit_Inherit:
     case eCSSUnit_Unset:
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       svg->mPaintOrder = parentSVG->mPaintOrder;
       break;
 
     case eCSSUnit_Initial:
       svg->mPaintOrder = NS_STYLE_PAINT_ORDER_NORMAL;
       break;
 
     default:
       NS_NOTREACHED("unexpected unit");
   }
 
   // shape-rendering: enum, inherit
   SetDiscrete(*aRuleData->ValueForShapeRendering(),
-              svg->mShapeRendering, canStoreInRuleTree,
+              svg->mShapeRendering, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mShapeRendering,
               NS_STYLE_SHAPE_RENDERING_AUTO, 0, 0, 0, 0);
 
   // stroke:
   SetSVGPaint(*aRuleData->ValueForStroke(),
               parentSVG->mStroke, mPresContext, aContext,
-              svg->mStroke, eStyleSVGPaintType_None, canStoreInRuleTree);
+              svg->mStroke, eStyleSVGPaintType_None, conditions);
 
   // stroke-dasharray: <dasharray>, none, inherit, context-value
   const nsCSSValue* strokeDasharrayValue = aRuleData->ValueForStrokeDasharray();
   switch (strokeDasharrayValue->GetUnit()) {
   case eCSSUnit_Null:
     break;
 
   case eCSSUnit_Inherit:
   case eCSSUnit_Unset:
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     svg->mStrokeDasharrayFromObject = parentSVG->mStrokeDasharrayFromObject;
     // only do the copy if weren't already set up by the copy constructor
     // FIXME Bug 389408: This is broken when aStartStruct is non-null!
     if (!svg->mStrokeDasharray) {
       svg->mStrokeDasharrayLength = parentSVG->mStrokeDasharrayLength;
       if (svg->mStrokeDasharrayLength) {
         svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
         if (svg->mStrokeDasharray)
@@ -8753,17 +8757,17 @@ nsRuleNode::ComputeSVGData(void* aStartS
     svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
 
     if (svg->mStrokeDasharray) {
       uint32_t i = 0;
       while (nullptr != value) {
         SetCoord(value->mValue,
                  svg->mStrokeDasharray[i++], nsStyleCoord(),
                  SETCOORD_LP | SETCOORD_FACTOR,
-                 aContext, mPresContext, canStoreInRuleTree);
+                 aContext, mPresContext, conditions);
         value = value->mNext;
       }
     } else {
       svg->mStrokeDasharrayLength = 0;
     }
     break;
   }
 
@@ -8779,44 +8783,44 @@ nsRuleNode::ComputeSVGData(void* aStartS
     strokeDashoffsetValue->GetIntValue() == NS_STYLE_STROKE_PROP_CONTEXT_VALUE;
   if (svg->mStrokeDashoffsetFromObject) {
     svg->mStrokeDashoffset.SetCoordValue(0);
   } else {
     SetCoord(*aRuleData->ValueForStrokeDashoffset(),
              svg->mStrokeDashoffset, parentSVG->mStrokeDashoffset,
              SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_INITIAL_ZERO |
                SETCOORD_UNSET_INHERIT,
-             aContext, mPresContext, canStoreInRuleTree);
+             aContext, mPresContext, conditions);
   }
 
   // stroke-linecap: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForStrokeLinecap(),
-              svg->mStrokeLinecap, canStoreInRuleTree,
+              svg->mStrokeLinecap, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mStrokeLinecap,
               NS_STYLE_STROKE_LINECAP_BUTT, 0, 0, 0, 0);
 
   // stroke-linejoin: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForStrokeLinejoin(),
-              svg->mStrokeLinejoin, canStoreInRuleTree,
+              svg->mStrokeLinejoin, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mStrokeLinejoin,
               NS_STYLE_STROKE_LINEJOIN_MITER, 0, 0, 0, 0);
 
   // stroke-miterlimit: <miterlimit>, inherit
   SetFactor(*aRuleData->ValueForStrokeMiterlimit(),
             svg->mStrokeMiterlimit,
-            canStoreInRuleTree,
+            conditions,
             parentSVG->mStrokeMiterlimit, 4.0f,
             SETFCT_UNSET_INHERIT);
 
   // stroke-opacity:
   nsStyleSVGOpacitySource contextStrokeOpacity = svg->mStrokeOpacitySource;
   SetSVGOpacity(*aRuleData->ValueForStrokeOpacity(),
-                svg->mStrokeOpacity, contextStrokeOpacity, canStoreInRuleTree,
+                svg->mStrokeOpacity, contextStrokeOpacity, conditions,
                 parentSVG->mStrokeOpacity, parentSVG->mStrokeOpacitySource);
   svg->mStrokeOpacitySource = contextStrokeOpacity;
 
   // stroke-width:
   const nsCSSValue* strokeWidthValue = aRuleData->ValueForStrokeWidth();
   switch (strokeWidthValue->GetUnit()) {
   case eCSSUnit_Enumerated:
     MOZ_ASSERT(strokeWidthValue->GetIntValue() ==
@@ -8831,42 +8835,42 @@ nsRuleNode::ComputeSVGData(void* aStartS
     svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
     break;
 
   default:
     svg->mStrokeWidthFromObject = false;
     SetCoord(*strokeWidthValue,
              svg->mStrokeWidth, parentSVG->mStrokeWidth,
              SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_UNSET_INHERIT,
-             aContext, mPresContext, canStoreInRuleTree);
+             aContext, mPresContext, conditions);
   }
 
   // text-anchor: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForTextAnchor(),
-              svg->mTextAnchor, canStoreInRuleTree,
+              svg->mTextAnchor, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mTextAnchor,
               NS_STYLE_TEXT_ANCHOR_START, 0, 0, 0, 0);
 
   // text-rendering: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForTextRendering(),
-              svg->mTextRendering, canStoreInRuleTree,
+              svg->mTextRendering, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mTextRendering,
               NS_STYLE_TEXT_RENDERING_AUTO, 0, 0, 0, 0);
 
   COMPUTE_END_INHERITED(SVG, svg)
 }
 
 void
 nsRuleNode::SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath,
                                        const nsCSSValue* aValue,
                                        nsStyleContext* aStyleContext,
                                        nsPresContext* aPresContext,
-                                       bool& aCanStoreInRuleTree)
+                                       RuleNodeCacheConditions& aConditions)
 {
   MOZ_ASSERT(aValue->GetUnit() != eCSSUnit_ListDep ||
              aValue->GetUnit() != eCSSUnit_List,
              "expected a basic shape or reference box");
 
   const nsCSSValueList* cur = aValue->GetListValue();
 
   uint8_t sizingBox = NS_STYLE_CLIP_SHAPE_SIZING_NOBOX;
@@ -8894,23 +8898,23 @@ nsRuleNode::SetStyleClipPathToCSSValue(n
         const nsCSSValuePairList* curPair =
           shapeFunction->Item(j).GetPairListValue();
         nsTArray<nsStyleCoord>& coordinates = basicShape->Coordinates();
         while (curPair) {
           nsStyleCoord xCoord, yCoord;
           DebugOnly<bool> didSetCoordX = SetCoord(curPair->mXValue, xCoord,
                                                   nsStyleCoord(), mask,
                                                   aStyleContext, aPresContext,
-                                                  aCanStoreInRuleTree);
+                                                  aConditions);
           coordinates.AppendElement(xCoord);
           MOZ_ASSERT(didSetCoordX, "unexpected x coordinate unit");
           DebugOnly<bool> didSetCoordY = SetCoord(curPair->mYValue, yCoord,
                                                   nsStyleCoord(), mask,
                                                   aStyleContext, aPresContext,
-                                                  aCanStoreInRuleTree);
+                                                  aConditions);
           coordinates.AppendElement(yCoord);
           MOZ_ASSERT(didSetCoordY, "unexpected y coordinate unit");
           curPair = curPair->mNext;
         }
       } else if (functionName == eCSSKeyword_circle ||
                  functionName == eCSSKeyword_ellipse) {
         nsStyleBasicShape::Type type = functionName == eCSSKeyword_circle ?
                                        nsStyleBasicShape::eCircle :
@@ -8929,28 +8933,28 @@ nsRuleNode::SetStyleClipPathToCSSValue(n
         for (size_t j = 1; j < count; ++j) {
           const nsCSSValue& val = shapeFunction->Item(j);
           nsStyleCoord radius;
           if (val.GetUnit() != eCSSUnit_Null) {
             DebugOnly<bool> didSetRadius = SetCoord(val, radius,
                                                     nsStyleCoord(), mask,
                                                     aStyleContext,
                                                     aPresContext,
-                                                    aCanStoreInRuleTree);
+                                                    aConditions);
             MOZ_ASSERT(didSetRadius, "unexpected radius unit");
           } else {
             radius.SetIntValue(NS_RADIUS_CLOSEST_SIDE, eStyleUnit_Enumerated);
           }
           basicShape->Coordinates().AppendElement(radius);
         }
         const nsCSSValue& positionVal = shapeFunction->Item(count);
         if (positionVal.GetUnit() == eCSSUnit_Array) {
           ComputePositionValue(aStyleContext, positionVal,
                                basicShape->GetPosition(),
-                               aCanStoreInRuleTree);
+                               aConditions);
         } else {
             MOZ_ASSERT(positionVal.GetUnit() == eCSSUnit_Null,
                        "expected no value");
         }
       } else if (functionName == eCSSKeyword_inset) {
         MOZ_ASSERT(!basicShape, "did not expect value");
         basicShape = new nsStyleBasicShape(nsStyleBasicShape::eInset);
         MOZ_ASSERT(shapeFunction->Count() == 6,
@@ -8970,17 +8974,17 @@ nsRuleNode::SetStyleClipPathToCSSValue(n
             } else {
               MOZ_ASSERT(j != 1, "first argument not specified");
               inset = coords[0];
             }
           } else {
             DebugOnly<bool> didSetInset = SetCoord(val, inset,
                                                    nsStyleCoord(), mask,
                                                    aStyleContext, aPresContext,
-                                                   aCanStoreInRuleTree);
+                                                   aConditions);
             MOZ_ASSERT(didSetInset, "unexpected inset unit");
           }
           coords.AppendElement(inset);
         }
 
         nsStyleCorners& insetRadius = basicShape->GetRadius();
         if (shapeFunction->Item(5).GetUnit() == eCSSUnit_Array) {
           nsCSSValue::Array* radiiArray = shapeFunction->Item(5).GetArrayValue();
@@ -8989,17 +8993,17 @@ nsRuleNode::SetStyleClipPathToCSSValue(n
             int cy = NS_FULL_TO_HALF_CORNER(corner, true);
             const nsCSSValue& radius = radiiArray->Item(corner);
             nsStyleCoord coordX, coordY;
             DebugOnly<bool> didSetRadii = SetPairCoords(radius, coordX, coordY,
                                                         nsStyleCoord(),
                                                         nsStyleCoord(), mask,
                                                         aStyleContext,
                                                         aPresContext,
-                                                        aCanStoreInRuleTree);
+                                                        aConditions);
             MOZ_ASSERT(didSetRadii, "unexpected radius unit");
             insetRadius.Set(cx, coordX);
             insetRadius.Set(cy, coordY);
           }
         } else {
           MOZ_ASSERT(shapeFunction->Item(5).GetUnit() == eCSSUnit_Null,
                      "unexpected value");
           // Initialize border-radius
@@ -9036,17 +9040,17 @@ nsRuleNode::SetStyleClipPathToCSSValue(n
 }
 
 // Returns true if the nsStyleFilter was successfully set using the nsCSSValue.
 bool
 nsRuleNode::SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
                                      const nsCSSValue& aValue,
                                      nsStyleContext* aStyleContext,
                                      nsPresContext* aPresContext,
-                                     bool& aCanStoreInRuleTree)
+                                     RuleNodeCacheConditions& aConditions)
 {
   nsCSSUnit unit = aValue.GetUnit();
   if (unit == eCSSUnit_URL) {
     nsIURI* url = aValue.GetURLValue();
     if (!url)
       return false;
     aStyleFilter->SetURL(url);
     return true;
@@ -9064,17 +9068,17 @@ nsRuleNode::SetStyleFilterToCSSValue(nsS
                             nsCSSProps::kFilterFunctionKTable,
                             type);
   MOZ_ASSERT(foundKeyword, "unknown filter type");
   if (type == NS_STYLE_FILTER_DROP_SHADOW) {
     nsRefPtr<nsCSSShadowArray> shadowArray = GetShadowData(
       filterFunction->Item(1).GetListValue(),
       aStyleContext,
       false,
-      aCanStoreInRuleTree);
+      aConditions);
     aStyleFilter->SetDropShadow(shadowArray);
     return true;
   }
 
   int32_t mask = SETCOORD_PERCENT | SETCOORD_FACTOR;
   if (type == NS_STYLE_FILTER_BLUR) {
     mask = SETCOORD_LENGTH |
            SETCOORD_CALC_LENGTH_ONLY |
@@ -9086,146 +9090,146 @@ nsRuleNode::SetStyleFilterToCSSValue(nsS
   MOZ_ASSERT(filterFunction->Count() == 2,
              "all filter functions should have exactly one argument");
 
   nsCSSValue& arg = filterFunction->Item(1);
   nsStyleCoord filterParameter;
   DebugOnly<bool> didSetCoord = SetCoord(arg, filterParameter,
                                          nsStyleCoord(), mask,
                                          aStyleContext, aPresContext,
-                                         aCanStoreInRuleTree);
+                                         aConditions);
   aStyleFilter->SetFilterParameter(filterParameter, type);
   MOZ_ASSERT(didSetCoord, "unexpected unit");
   return true;
 }
 
 const void*
 nsRuleNode::ComputeSVGResetData(void* aStartStruct,
                                 const nsRuleData* aRuleData,
                                 nsStyleContext* aContext,
                                 nsRuleNode* aHighestNode,
                                 const RuleDetail aRuleDetail,
-                                const bool aCanStoreInRuleTree)
+                                const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(SVGReset, (), svgReset, parentSVGReset)
 
   // stop-color:
   const nsCSSValue* stopColorValue = aRuleData->ValueForStopColor();
   if (eCSSUnit_Initial == stopColorValue->GetUnit() ||
       eCSSUnit_Unset == stopColorValue->GetUnit()) {
     svgReset->mStopColor = NS_RGB(0, 0, 0);
   } else {
     SetColor(*stopColorValue, parentSVGReset->mStopColor,
-             mPresContext, aContext, svgReset->mStopColor, canStoreInRuleTree);
+             mPresContext, aContext, svgReset->mStopColor, conditions);
   }
 
   // flood-color:
   const nsCSSValue* floodColorValue = aRuleData->ValueForFloodColor();
   if (eCSSUnit_Initial == floodColorValue->GetUnit() ||
       eCSSUnit_Unset == floodColorValue->GetUnit()) {
     svgReset->mFloodColor = NS_RGB(0, 0, 0);
   } else {
     SetColor(*floodColorValue, parentSVGReset->mFloodColor,
-             mPresContext, aContext, svgReset->mFloodColor, canStoreInRuleTree);
+             mPresContext, aContext, svgReset->mFloodColor, conditions);
   }
 
   // lighting-color:
   const nsCSSValue* lightingColorValue = aRuleData->ValueForLightingColor();
   if (eCSSUnit_Initial == lightingColorValue->GetUnit() ||
       eCSSUnit_Unset == lightingColorValue->GetUnit()) {
     svgReset->mLightingColor = NS_RGB(255, 255, 255);
   } else {
     SetColor(*lightingColorValue, parentSVGReset->mLightingColor,
              mPresContext, aContext, svgReset->mLightingColor,
-             canStoreInRuleTree);
+             conditions);
   }
 
   // clip-path: url, <basic-shape> || <geometry-box>, none, inherit
   const nsCSSValue* clipPathValue = aRuleData->ValueForClipPath();
   switch (clipPathValue->GetUnit()) {
     case eCSSUnit_Null:
       break;
     case eCSSUnit_None:
     case eCSSUnit_Initial:
     case eCSSUnit_Unset:
       svgReset->mClipPath = nsStyleClipPath();
       break;
     case eCSSUnit_Inherit:
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       svgReset->mClipPath = parentSVGReset->mClipPath;
       break;
     case eCSSUnit_URL: {
       svgReset->mClipPath = nsStyleClipPath();
       nsIURI* url = clipPathValue->GetURLValue();
       if (url) {
         svgReset->mClipPath.SetURL(url);
       }
       break;
     }
     case eCSSUnit_List:
     case eCSSUnit_ListDep: {
       svgReset->mClipPath = nsStyleClipPath();
       SetStyleClipPathToCSSValue(&svgReset->mClipPath, clipPathValue, aContext,
-                                 mPresContext, canStoreInRuleTree);
+                                 mPresContext, conditions);
       break;
     }
     default:
       NS_NOTREACHED("unexpected unit");
   }
 
   // stop-opacity:
   SetFactor(*aRuleData->ValueForStopOpacity(),
-            svgReset->mStopOpacity, canStoreInRuleTree,
+            svgReset->mStopOpacity, conditions,
             parentSVGReset->mStopOpacity, 1.0f,
             SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
 
   // flood-opacity:
   SetFactor(*aRuleData->ValueForFloodOpacity(),
-            svgReset->mFloodOpacity, canStoreInRuleTree,
+            svgReset->mFloodOpacity, conditions,
             parentSVGReset->mFloodOpacity, 1.0f,
             SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
 
   // dominant-baseline: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForDominantBaseline(),
               svgReset->mDominantBaseline,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentSVGReset->mDominantBaseline,
               NS_STYLE_DOMINANT_BASELINE_AUTO, 0, 0, 0, 0);
 
   // vector-effect: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForVectorEffect(),
               svgReset->mVectorEffect,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentSVGReset->mVectorEffect,
               NS_STYLE_VECTOR_EFFECT_NONE, 0, 0, 0, 0);
 
   // filter: url, none, inherit
   const nsCSSValue* filterValue = aRuleData->ValueForFilter();
   switch (filterValue->GetUnit()) {
     case eCSSUnit_Null:
       break;
     case eCSSUnit_None:
     case eCSSUnit_Initial:
     case eCSSUnit_Unset:
       svgReset->mFilters.Clear();
       break;
     case eCSSUnit_Inherit:
-      canStoreInRuleTree = false;
+      conditions.SetUncacheable();
       svgReset->mFilters = parentSVGReset->mFilters;
       break;
     case eCSSUnit_List:
     case eCSSUnit_ListDep: {
       svgReset->mFilters.Clear();
       const nsCSSValueList* cur = filterValue->GetListValue();
       while (cur) {
         nsStyleFilter styleFilter;
         if (!SetStyleFilterToCSSValue(&styleFilter, cur->mValue, aContext,
-                                      mPresContext, canStoreInRuleTree)) {
+                                      mPresContext, conditions)) {
           svgReset->mFilters.Clear();
           break;
         }
         MOZ_ASSERT(styleFilter.GetType() != NS_STYLE_FILTER_NONE,
                    "filter should be set");
         svgReset->mFilters.AppendElement(styleFilter);
         cur = cur->mNext;
       }
@@ -9239,49 +9243,49 @@ nsRuleNode::ComputeSVGResetData(void* aS
   const nsCSSValue* maskValue = aRuleData->ValueForMask();
   if (eCSSUnit_URL == maskValue->GetUnit()) {
     svgReset->mMask = maskValue->GetURLValue();
   } else if (eCSSUnit_None == maskValue->GetUnit() ||
              eCSSUnit_Initial == maskValue->GetUnit() ||
              eCSSUnit_Unset == maskValue->GetUnit()) {
     svgReset->mMask = nullptr;
   } else if (eCSSUnit_Inherit == maskValue->GetUnit()) {
-    canStoreInRuleTree = false;
+    conditions.SetUncacheable();
     svgReset->mMask = parentSVGReset->mMask;
   }
 
   // mask-type: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForMaskType(),
               svgReset->mMaskType,
-              canStoreInRuleTree,
+              conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentSVGReset->mMaskType,
               NS_STYLE_MASK_TYPE_LUMINANCE, 0, 0, 0, 0);
 
   COMPUTE_END_RESET(SVGReset, svgReset)
 }
 
 const void*
 nsRuleNode::ComputeVariablesData(void* aStartStruct,
                                  const nsRuleData* aRuleData,
                                  nsStyleContext* aContext,
                                  nsRuleNode* aHighestNode,
                                  const RuleDetail aRuleDetail,
-                                 const bool aCanStoreInRuleTree)
+                                 const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(Variables, (), variables, parentVariables)
 
   MOZ_ASSERT(aRuleData->mVariables,
              "shouldn't be in ComputeVariablesData if there were no variable "
              "declarations specified");
 
   CSSVariableResolver resolver(&variables->mVariables);
   resolver.Resolve(&parentVariables->mVariables,
                    aRuleData->mVariables);
-  canStoreInRuleTree = false;
+  conditions.SetUncacheable();
 
   COMPUTE_END_INHERITED(Variables, variables)
 }
 
 const void*
 nsRuleNode::GetStyleData(nsStyleStructID aSID,
                          nsStyleContext* aContext,
                          bool aComputeData)
@@ -9739,14 +9743,14 @@ nsRuleNode::ComputeColor(const nsCSSValu
 {
   MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Inherit,
              "aValue shouldn't have eCSSUnit_Inherit");
   MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Initial,
              "aValue shouldn't have eCSSUnit_Initial");
   MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Unset,
              "aValue shouldn't have eCSSUnit_Unset");
 
-  bool canStoreInRuleTree;
+  RuleNodeCacheConditions conditions;
   bool ok = SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aStyleContext,
-                     aResult, canStoreInRuleTree);
+                     aResult, conditions);
   MOZ_ASSERT(ok || !(aPresContext && aStyleContext));
   return ok;
 }
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -7,28 +7,29 @@
  * a node in the lexicographic tree of rules that match an element,
  * responsible for converting the rules' information into computed style
  */
 
 #ifndef nsRuleNode_h___
 #define nsRuleNode_h___
 
 #include "mozilla/RangedArray.h"
+#include "mozilla/RuleNodeCacheConditions.h"
 #include "nsPresContext.h"
 #include "nsStyleStruct.h"
 
-class nsStyleContext;
-struct nsRuleData;
-class nsIStyleRule;
-struct nsCSSValueList;
 class nsCSSPropertySet;
 class nsCSSValue;
-
+class nsIStyleRule;
+class nsStyleContext;
 class nsStyleCoord;
+struct nsCSSRect;
+struct nsCSSValueList;
 struct nsCSSValuePairList;
+struct nsRuleData;
 
 struct nsInheritedStyleData
 {
   mozilla::RangedArray<void*,
                        nsStyleStructID_Inherited_Start,
                        nsStyleStructID_Inherited_Count> mStyleStructs;
 
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
@@ -430,225 +431,225 @@ protected:
   const void*
     WalkRuleTree(const nsStyleStructID aSID, nsStyleContext* aContext);
 
   const void*
     ComputeDisplayData(void* aStartStruct,
                        const nsRuleData* aRuleData,
                        nsStyleContext* aContext, nsRuleNode* aHighestNode,
                        RuleDetail aRuleDetail,
-                       const bool aCanStoreInRuleTree);
+                       const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeVisibilityData(void* aStartStruct,
                           const nsRuleData* aRuleData,
                           nsStyleContext* aContext, nsRuleNode* aHighestNode,
                           RuleDetail aRuleDetail,
-                          const bool aCanStoreInRuleTree);
+                          const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeFontData(void* aStartStruct,
                     const nsRuleData* aRuleData,
                     nsStyleContext* aContext, nsRuleNode* aHighestNode,
                     RuleDetail aRuleDetail,
-                    const bool aCanStoreInRuleTree);
+                    const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeColorData(void* aStartStruct,
                      const nsRuleData* aRuleData,
                      nsStyleContext* aContext, nsRuleNode* aHighestNode,
                      RuleDetail aRuleDetail,
-                     const bool aCanStoreInRuleTree);
+                     const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeBackgroundData(void* aStartStruct,
                           const nsRuleData* aRuleData,
                           nsStyleContext* aContext, nsRuleNode* aHighestNode,
                           RuleDetail aRuleDetail,
-                          const bool aCanStoreInRuleTree);
+                          const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeMarginData(void* aStartStruct,
                       const nsRuleData* aRuleData,
                       nsStyleContext* aContext, nsRuleNode* aHighestNode,
                       RuleDetail aRuleDetail,
-                      const bool aCanStoreInRuleTree);
+                      const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeBorderData(void* aStartStruct,
                       const nsRuleData* aRuleData,
                       nsStyleContext* aContext, nsRuleNode* aHighestNode,
                       RuleDetail aRuleDetail,
-                      const bool aCanStoreInRuleTree);
+                      const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputePaddingData(void* aStartStruct,
                        const nsRuleData* aRuleData,
                        nsStyleContext* aContext, nsRuleNode* aHighestNode,
                        RuleDetail aRuleDetail,
-                       const bool aCanStoreInRuleTree);
+                       const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeOutlineData(void* aStartStruct,
                        const nsRuleData* aRuleData,
                        nsStyleContext* aContext, nsRuleNode* aHighestNode,
                        RuleDetail aRuleDetail,
-                       const bool aCanStoreInRuleTree);
+                       const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeListData(void* aStartStruct,
                     const nsRuleData* aRuleData,
                     nsStyleContext* aContext, nsRuleNode* aHighestNode,
                     RuleDetail aRuleDetail,
-                    const bool aCanStoreInRuleTree);
+                    const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputePositionData(void* aStartStruct,
                         const nsRuleData* aRuleData,
                         nsStyleContext* aContext, nsRuleNode* aHighestNode,
                         RuleDetail aRuleDetail,
-                        const bool aCanStoreInRuleTree);
+                        const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeTableData(void* aStartStruct,
                      const nsRuleData* aRuleData,
                      nsStyleContext* aContext, nsRuleNode* aHighestNode,
                      RuleDetail aRuleDetail,
-                     const bool aCanStoreInRuleTree);
+                     const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeTableBorderData(void* aStartStruct,
                            const nsRuleData* aRuleData,
                            nsStyleContext* aContext, nsRuleNode* aHighestNode,
                            RuleDetail aRuleDetail,
-                           const bool aCanStoreInRuleTree);
+                           const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeContentData(void* aStartStruct,
                        const nsRuleData* aRuleData,
                        nsStyleContext* aContext, nsRuleNode* aHighestNode,
                        RuleDetail aRuleDetail,
-                       const bool aCanStoreInRuleTree);
+                       const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeQuotesData(void* aStartStruct,
                       const nsRuleData* aRuleData,
                       nsStyleContext* aContext, nsRuleNode* aHighestNode,
                       RuleDetail aRuleDetail,
-                      const bool aCanStoreInRuleTree);
+                      const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeTextData(void* aStartStruct,
                     const nsRuleData* aRuleData,
                     nsStyleContext* aContext, nsRuleNode* aHighestNode,
                     RuleDetail aRuleDetail,
-                    const bool aCanStoreInRuleTree);
+                    const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeTextResetData(void* aStartStruct,
                          const nsRuleData* aRuleData,
                          nsStyleContext* aContext, nsRuleNode* aHighestNode,
                          RuleDetail aRuleDetail,
-                         const bool aCanStoreInRuleTree);
+                         const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeUserInterfaceData(void* aStartStruct,
                              const nsRuleData* aRuleData,
                              nsStyleContext* aContext,
                              nsRuleNode* aHighestNode,
                              RuleDetail aRuleDetail,
-                             const bool aCanStoreInRuleTree);
+                             const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeUIResetData(void* aStartStruct,
                        const nsRuleData* aRuleData,
                        nsStyleContext* aContext, nsRuleNode* aHighestNode,
                        RuleDetail aRuleDetail,
-                       const bool aCanStoreInRuleTree);
+                       const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeXULData(void* aStartStruct,
                    const nsRuleData* aRuleData,
                    nsStyleContext* aContext, nsRuleNode* aHighestNode,
                    RuleDetail aRuleDetail,
-                   const bool aCanStoreInRuleTree);
+                   const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeColumnData(void* aStartStruct,
                       const nsRuleData* aRuleData,
                       nsStyleContext* aContext, nsRuleNode* aHighestNode,
                       RuleDetail aRuleDetail,
-                      const bool aCanStoreInRuleTree);
+                      const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeSVGData(void* aStartStruct,
                    const nsRuleData* aRuleData,
                    nsStyleContext* aContext, nsRuleNode* aHighestNode,
                    RuleDetail aRuleDetail,
-                   const bool aCanStoreInRuleTree);
+                   const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeSVGResetData(void* aStartStruct,
                         const nsRuleData* aRuleData,
                         nsStyleContext* aContext, nsRuleNode* aHighestNode,
                         RuleDetail aRuleDetail,
-                        const bool aCanStoreInRuleTree);
+                        const mozilla::RuleNodeCacheConditions aConditions);
 
   const void*
     ComputeVariablesData(void* aStartStruct,
                          const nsRuleData* aRuleData,
                          nsStyleContext* aContext, nsRuleNode* aHighestNode,
                          RuleDetail aRuleDetail,
-                         const bool aCanStoreInRuleTree);
+                         const mozilla::RuleNodeCacheConditions aConditions);
 
   // helpers for |ComputeFontData| that need access to |mNoneBits|:
   static void SetFontSize(nsPresContext* aPresContext,
                           const nsRuleData* aRuleData,
                           const nsStyleFont* aFont,
                           const nsStyleFont* aParentFont,
                           nscoord* aSize,
                           const nsFont& aSystemFont,
                           nscoord aParentSize,
                           nscoord aScriptLevelAdjustedParentSize,
                           bool aUsedStartStruct,
                           bool aAtRoot,
-                          bool& aCanStoreInRuleTree);
+                          mozilla::RuleNodeCacheConditions& aConditions);
 
   static void SetFont(nsPresContext* aPresContext,
                       nsStyleContext* aContext,
                       uint8_t aGenericFontID,
                       const nsRuleData* aRuleData,
                       const nsStyleFont* aParentFont,
                       nsStyleFont* aFont,
                       bool aStartStruct,
-                      bool& aCanStoreInRuleTree);
+                      mozilla::RuleNodeCacheConditions& aConditions);
 
   static void SetGenericFont(nsPresContext* aPresContext,
                              nsStyleContext* aContext,
                              uint8_t aGenericFontID,
                              nsStyleFont* aFont);
 
   inline RuleDetail CheckSpecifiedProperties(const nsStyleStructID aSID,
                                              const nsRuleData* aRuleData);
 
   already_AddRefed<nsCSSShadowArray>
               GetShadowData(const nsCSSValueList* aList,
                             nsStyleContext* aContext,
                             bool aIsBoxShadow,
-                            bool& aCanStoreInRuleTree);
+                            mozilla::RuleNodeCacheConditions& aConditions);
   bool SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
                                 const nsCSSValue& aValue,
                                 nsStyleContext* aStyleContext,
                                 nsPresContext* aPresContext,
-                                bool& aCanStoreInRuleTree);
+                                mozilla::RuleNodeCacheConditions& aConditions);
   void SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath,
                                   const nsCSSValue* aValue,
                                   nsStyleContext* aStyleContext,
                                   nsPresContext* aPresContext,
-                                  bool& aCanStoreInRuleTree);
+                                  mozilla::RuleNodeCacheConditions& aConditions);
 
 private:
   nsRuleNode(nsPresContext* aPresContext, nsRuleNode* aParent,
              nsIStyleRule* aRule, uint8_t aLevel, bool aIsImportant);
   ~nsRuleNode();
 
 public:
   // This is infallible; it will never return nullptr.
@@ -759,30 +760,30 @@ public:
 
   // Expose this so media queries can use it
   static nscoord CalcLengthWithInitialFont(nsPresContext* aPresContext,
                                            const nsCSSValue& aValue);
   // Expose this so nsTransformFunctions can use it.
   static nscoord CalcLength(const nsCSSValue& aValue,
                             nsStyleContext* aStyleContext,
                             nsPresContext* aPresContext,
-                            bool& aCanStoreInRuleTree);
+                            mozilla::RuleNodeCacheConditions& aConditions);
 
   struct ComputedCalc {
     nscoord mLength;
     float mPercent;
 
     ComputedCalc(nscoord aLength, float aPercent)
       : mLength(aLength), mPercent(aPercent) {}
   };
   static ComputedCalc
   SpecifiedCalcToComputedCalc(const nsCSSValue& aValue,
                               nsStyleContext* aStyleContext,
                               nsPresContext* aPresContext,
-                              bool& aCanStoreInRuleTree);
+                              mozilla::RuleNodeCacheConditions& aConditions);
 
   // Compute the value of an nsStyleCoord that IsCalcUnit().
   // (Values that don't require aPercentageBasis should be handled
   // inside nsRuleNode rather than through this API.)
   static nscoord ComputeComputedCalc(const nsStyleCoord& aCoord,
                                      nscoord aPercentageBasis);
 
   // Compute the value of an nsStyleCoord that is either a coord, a
--- a/layout/style/nsStyleTransformMatrix.cpp
+++ b/layout/style/nsStyleTransformMatrix.cpp
@@ -143,17 +143,17 @@ static double FlushToZero(double aVal)
   else
     return aVal;
 }
 
 float
 ProcessTranslatePart(const nsCSSValue& aValue,
                      nsStyleContext* aContext,
                      nsPresContext* aPresContext,
-                     bool& aCanStoreInRuleTree,
+                     RuleNodeCacheConditions& aConditions,
                      TransformReferenceBox* aRefBox,
                      TransformReferenceBox::DimensionGetter aDimensionGetter)
 {
   nscoord offset = 0;
   float percent = 0.0f;
 
   if (aValue.GetUnit() == eCSSUnit_Percent) {
     percent = aValue.GetPercentValue();
@@ -167,22 +167,22 @@ ProcessTranslatePart(const nsCSSValue& a
     //
     // Raw numbers are treated as being pixels.
     //
     // Don't convert to aValue to AppUnits here to avoid precision issues.
     return aValue.GetFloatValue();
   } else if (aValue.IsCalcUnit()) {
     nsRuleNode::ComputedCalc result =
       nsRuleNode::SpecifiedCalcToComputedCalc(aValue, aContext, aPresContext,
-                                              aCanStoreInRuleTree);
+                                              aConditions);
     percent = result.mPercent;
     offset = result.mLength;
   } else {
     offset = nsRuleNode::CalcLength(aValue, aContext, aPresContext,
-                                    aCanStoreInRuleTree);
+                                    aConditions);
   }
 
   float translation = NSAppUnitsToFloatPixels(offset,
                                               nsPresContext::AppUnitsPerCSSPixel());
   // We want to avoid calling aDimensionGetter if there's no percentage to be
   // resolved (for performance reasons - see TransformReferenceBox).
   if (percent != 0.0f && aRefBox) {
     translation += percent *
@@ -199,17 +199,17 @@ ProcessTranslatePart(const nsCSSValue& a
  */
 
 /* Helper function to process a matrix entry. */
 static void
 ProcessMatrix(gfx3DMatrix& aMatrix,
               const nsCSSValue::Array* aData,
               nsStyleContext* aContext,
               nsPresContext* aPresContext,
-              bool& aCanStoreInRuleTree,
+              RuleNodeCacheConditions& aConditions,
               TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 7, "Invalid array!");
 
   gfxMatrix result;
 
   /* Take the first four elements out of the array as floats and store
    * them.
@@ -218,31 +218,31 @@ ProcessMatrix(gfx3DMatrix& aMatrix,
   result._12 = aData->Item(2).GetFloatValue();
   result._21 = aData->Item(3).GetFloatValue();
   result._22 = aData->Item(4).GetFloatValue();
 
   /* The last two elements have their length parts stored in aDelta
    * and their percent parts stored in aX[0] and aY[1].
    */
   result._31 = ProcessTranslatePart(aData->Item(5),
-                                   aContext, aPresContext, aCanStoreInRuleTree,
+                                   aContext, aPresContext, aConditions,
                                    &aRefBox, &TransformReferenceBox::Width);
   result._32 = ProcessTranslatePart(aData->Item(6),
-                                   aContext, aPresContext, aCanStoreInRuleTree,
+                                   aContext, aPresContext, aConditions,
                                    &aRefBox, &TransformReferenceBox::Height);
 
   aMatrix.PreMultiply(result);
 }
 
 static void 
 ProcessMatrix3D(gfx3DMatrix& aMatrix,
                 const nsCSSValue::Array* aData,
                 nsStyleContext* aContext,
                 nsPresContext* aPresContext,
-                bool& aCanStoreInRuleTree,
+                RuleNodeCacheConditions& aConditions,
                 TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 17, "Invalid array!");
 
   gfx3DMatrix temp;
 
   temp._11 = aData->Item(1).GetFloatValue();
   temp._12 = aData->Item(2).GetFloatValue();
@@ -254,162 +254,162 @@ ProcessMatrix3D(gfx3DMatrix& aMatrix,
   temp._24 = aData->Item(8).GetFloatValue();
   temp._31 = aData->Item(9).GetFloatValue();
   temp._32 = aData->Item(10).GetFloatValue();
   temp._33 = aData->Item(11).GetFloatValue();
   temp._34 = aData->Item(12).GetFloatValue();
   temp._44 = aData->Item(16).GetFloatValue();
 
   temp._41 = ProcessTranslatePart(aData->Item(13),
-                                  aContext, aPresContext, aCanStoreInRuleTree,
+                                  aContext, aPresContext, aConditions,
                                   &aRefBox, &TransformReferenceBox::Width);
   temp._42 = ProcessTranslatePart(aData->Item(14),
-                                  aContext, aPresContext, aCanStoreInRuleTree,
+                                  aContext, aPresContext, aConditions,
                                   &aRefBox, &TransformReferenceBox::Height);
   temp._43 = ProcessTranslatePart(aData->Item(15),
-                                  aContext, aPresContext, aCanStoreInRuleTree,
+                                  aContext, aPresContext, aConditions,
                                   nullptr);
 
   aMatrix.PreMultiply(temp);
 }
 
 /* Helper function to process two matrices that we need to interpolate between */
 void
 ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
                          const nsCSSValue::Array* aData,
                          nsStyleContext* aContext,
                          nsPresContext* aPresContext,
-                         bool& aCanStoreInRuleTree,
+                         RuleNodeCacheConditions& aConditions,
                          TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
 
   gfx3DMatrix matrix1, matrix2;
   if (aData->Item(1).GetUnit() == eCSSUnit_List) {
     matrix1 = nsStyleTransformMatrix::ReadTransforms(aData->Item(1).GetListValue(),
                              aContext, aPresContext,
-                             aCanStoreInRuleTree,
+                             aConditions,
                              aRefBox, nsPresContext::AppUnitsPerCSSPixel());
   }
   if (aData->Item(2).GetUnit() == eCSSUnit_List) {
     matrix2 = ReadTransforms(aData->Item(2).GetListValue(),
                              aContext, aPresContext,
-                             aCanStoreInRuleTree,
+                             aConditions,
                              aRefBox, nsPresContext::AppUnitsPerCSSPixel());
   }
   double progress = aData->Item(3).GetPercentValue();
 
   aMatrix =
     StyleAnimationValue::InterpolateTransformMatrix(matrix1, matrix2, progress)
     * aMatrix;
 }
 
 /* Helper function to process a translatex function. */
 static void
 ProcessTranslateX(gfx3DMatrix& aMatrix,
                   const nsCSSValue::Array* aData,
                   nsStyleContext* aContext,
                   nsPresContext* aPresContext,
-                  bool& aCanStoreInRuleTree,
+                  RuleNodeCacheConditions& aConditions,
                   TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
   Point3D temp;
 
   temp.x = ProcessTranslatePart(aData->Item(1),
-                                aContext, aPresContext, aCanStoreInRuleTree,
+                                aContext, aPresContext, aConditions,
                                 &aRefBox, &TransformReferenceBox::Width);
   aMatrix.Translate(temp);
 }
 
 /* Helper function to process a translatey function. */
 static void
 ProcessTranslateY(gfx3DMatrix& aMatrix,
                   const nsCSSValue::Array* aData,
                   nsStyleContext* aContext,
                   nsPresContext* aPresContext,
-                  bool& aCanStoreInRuleTree,
+                  RuleNodeCacheConditions& aConditions,
                   TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
   Point3D temp;
 
   temp.y = ProcessTranslatePart(aData->Item(1),
-                                aContext, aPresContext, aCanStoreInRuleTree,
+                                aContext, aPresContext, aConditions,
                                 &aRefBox, &TransformReferenceBox::Height);
   aMatrix.Translate(temp);
 }
 
 static void 
 ProcessTranslateZ(gfx3DMatrix& aMatrix,
                   const nsCSSValue::Array* aData,
                   nsStyleContext* aContext,
                   nsPresContext* aPresContext,
-                  bool& aCanStoreInRuleTree)
+                  RuleNodeCacheConditions& aConditions)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
   Point3D temp;
 
   temp.z = ProcessTranslatePart(aData->Item(1), aContext,
-                                aPresContext, aCanStoreInRuleTree,
+                                aPresContext, aConditions,
                                 nullptr);
   aMatrix.Translate(temp);
 }
 
 /* Helper function to process a translate function. */
 static void
 ProcessTranslate(gfx3DMatrix& aMatrix,
                  const nsCSSValue::Array* aData,
                  nsStyleContext* aContext,
                  nsPresContext* aPresContext,
-                 bool& aCanStoreInRuleTree,
+                 RuleNodeCacheConditions& aConditions,
                  TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");
 
   Point3D temp;
 
   temp.x = ProcessTranslatePart(aData->Item(1),
-                                aContext, aPresContext, aCanStoreInRuleTree,
+                                aContext, aPresContext, aConditions,
                                 &aRefBox, &TransformReferenceBox::Width);
 
   /* If we read in a Y component, set it appropriately */
   if (aData->Count() == 3) {
     temp.y = ProcessTranslatePart(aData->Item(2),
-                                  aContext, aPresContext, aCanStoreInRuleTree,
+                                  aContext, aPresContext, aConditions,
                                   &aRefBox, &TransformReferenceBox::Height);
   }
   aMatrix.Translate(temp);
 }
 
 static void
 ProcessTranslate3D(gfx3DMatrix& aMatrix,
                    const nsCSSValue::Array* aData,
                    nsStyleContext* aContext,
                    nsPresContext* aPresContext,
-                   bool& aCanStoreInRuleTree,
+                   RuleNodeCacheConditions& aConditions,
                    TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
 
   Point3D temp;
 
   temp.x = ProcessTranslatePart(aData->Item(1),
-                                aContext, aPresContext, aCanStoreInRuleTree,
+                                aContext, aPresContext, aConditions,
                                 &aRefBox, &TransformReferenceBox::Width);
 
   temp.y = ProcessTranslatePart(aData->Item(2),
-                                aContext, aPresContext, aCanStoreInRuleTree,
+                                aContext, aPresContext, aConditions,
                                 &aRefBox, &TransformReferenceBox::Height);
 
   temp.z = ProcessTranslatePart(aData->Item(3),
-                                aContext, aPresContext, aCanStoreInRuleTree,
+                                aContext, aPresContext, aConditions,
                                 nullptr);
 
   aMatrix.Translate(temp);
 }
 
 /* Helper function to set up a scale matrix. */
 static void
 ProcessScaleHelper(gfx3DMatrix& aMatrix,
@@ -587,66 +587,66 @@ ProcessRotate3D(gfx3DMatrix& aMatrix, co
   aMatrix = temp * aMatrix;
 }
 
 static void 
 ProcessPerspective(gfx3DMatrix& aMatrix, 
                    const nsCSSValue::Array* aData,
                    nsStyleContext *aContext,
                    nsPresContext *aPresContext,
-                   bool &aCanStoreInRuleTree)
+                   RuleNodeCacheConditions& aConditions)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
   float depth = ProcessTranslatePart(aData->Item(1), aContext,
-                                     aPresContext, aCanStoreInRuleTree,
+                                     aPresContext, aConditions,
                                      nullptr);
   aMatrix.Perspective(depth);
 }
 
 
 /**
  * SetToTransformFunction is essentially a giant switch statement that fans
  * out to many smaller helper functions.
  */
 static void
 MatrixForTransformFunction(gfx3DMatrix& aMatrix,
                            const nsCSSValue::Array * aData,
                            nsStyleContext* aContext,
                            nsPresContext* aPresContext,
-                           bool& aCanStoreInRuleTree,
+                           RuleNodeCacheConditions& aConditions,
                            TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData, "Why did you want to get data from a null array?");
   // It's OK if aContext and aPresContext are null if the caller already
   // knows that all length units have been converted to pixels (as
   // StyleAnimationValue does).
 
 
   /* Get the keyword for the transform. */
   switch (TransformFunctionOf(aData)) {
   case eCSSKeyword_translatex:
     ProcessTranslateX(aMatrix, aData, aContext, aPresContext,
-                      aCanStoreInRuleTree, aRefBox);
+                      aConditions, aRefBox);
     break;
   case eCSSKeyword_translatey:
     ProcessTranslateY(aMatrix, aData, aContext, aPresContext,
-                      aCanStoreInRuleTree, aRefBox);
+                      aConditions, aRefBox);
     break;
   case eCSSKeyword_translatez:
     ProcessTranslateZ(aMatrix, aData, aContext, aPresContext,
-                      aCanStoreInRuleTree);
+                      aConditions);
     break;
   case eCSSKeyword_translate:
     ProcessTranslate(aMatrix, aData, aContext, aPresContext,
-                     aCanStoreInRuleTree, aRefBox);
+                     aConditions, aRefBox);
     break;
   case eCSSKeyword_translate3d:
     ProcessTranslate3D(aMatrix, aData, aContext, aPresContext,
-                       aCanStoreInRuleTree, aRefBox);
+                       aConditions, aRefBox);
     break;
   case eCSSKeyword_scalex:
     ProcessScaleX(aMatrix, aData);
     break;
   case eCSSKeyword_scaley:
     ProcessScaleY(aMatrix, aData);
     break;
   case eCSSKeyword_scalez:
@@ -677,29 +677,29 @@ MatrixForTransformFunction(gfx3DMatrix& 
   case eCSSKeyword_rotate:
     ProcessRotateZ(aMatrix, aData);
     break;
   case eCSSKeyword_rotate3d:
     ProcessRotate3D(aMatrix, aData);
     break;
   case eCSSKeyword_matrix:
     ProcessMatrix(aMatrix, aData, aContext, aPresContext,
-                  aCanStoreInRuleTree, aRefBox);
+                  aConditions, aRefBox);
     break;
   case eCSSKeyword_matrix3d:
     ProcessMatrix3D(aMatrix, aData, aContext, aPresContext,
-                    aCanStoreInRuleTree, aRefBox);
+                    aConditions, aRefBox);
     break;
   case eCSSKeyword_interpolatematrix:
     ProcessInterpolateMatrix(aMatrix, aData, aContext, aPresContext,
-                             aCanStoreInRuleTree, aRefBox);
+                             aConditions, aRefBox);
     break;
   case eCSSKeyword_perspective:
     ProcessPerspective(aMatrix, aData, aContext, aPresContext, 
-                       aCanStoreInRuleTree);
+                       aConditions);
     break;
   default:
     NS_NOTREACHED("Unknown transform function!");
   }
 }
 
 /**
  * Return the transform function, as an nsCSSKeyword, for the given
@@ -711,17 +711,17 @@ TransformFunctionOf(const nsCSSValue::Ar
   MOZ_ASSERT(aData->Item(0).GetUnit() == eCSSUnit_Enumerated);
   return aData->Item(0).GetKeywordValue();
 }
 
 gfx3DMatrix
 ReadTransforms(const nsCSSValueList* aList,
                nsStyleContext* aContext,
                nsPresContext* aPresContext,
-               bool &aCanStoreInRuleTree,
+               RuleNodeCacheConditions& aConditions,
                TransformReferenceBox& aRefBox,
                float aAppUnitsPerMatrixUnit)
 {
   gfx3DMatrix result;
 
   for (const nsCSSValueList* curr = aList; curr != nullptr; curr = curr->mNext) {
     const nsCSSValue &currElem = curr->mValue;
     if (currElem.GetUnit() != eCSSUnit_Function) {
@@ -731,17 +731,17 @@ ReadTransforms(const nsCSSValueList* aLi
                    "lone None");
       continue;
     }
     NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1,
                  "Incoming function is too short!");
 
     /* Read in a single transform matrix. */
     MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext,
-                               aPresContext, aCanStoreInRuleTree, aRefBox);
+                               aPresContext, aConditions, aRefBox);
   }
 
   float scale = float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;
   result.Scale(1/scale, 1/scale, 1/scale);
   result.ScalePost(scale, scale, scale);
   
   return result;
 }
--- a/layout/style/nsStyleTransformMatrix.h
+++ b/layout/style/nsStyleTransformMatrix.h
@@ -12,16 +12,19 @@
 
 #include "nsCSSValue.h"
 #include "gfx3DMatrix.h"
 
 class nsIFrame;
 class nsStyleContext;
 class nsPresContext;
 struct nsRect;
+namespace mozilla {
+class RuleNodeCacheConditions;
+}
 
 /**
  * A helper to generate gfxMatrixes from css transform functions.
  */
 namespace nsStyleTransformMatrix {
 
   /**
    * This class provides on-demand access to the 'reference box' for CSS
@@ -123,46 +126,46 @@ namespace nsStyleTransformMatrix {
    * Return the transform function, as an nsCSSKeyword, for the given
    * nsCSSValue::Array from a transform list.
    */
   nsCSSKeyword TransformFunctionOf(const nsCSSValue::Array* aData);
 
   float ProcessTranslatePart(const nsCSSValue& aValue,
                              nsStyleContext* aContext,
                              nsPresContext* aPresContext,
-                             bool& aCanStoreInRuleTree,
+                             mozilla::RuleNodeCacheConditions& aConditions,
                              TransformReferenceBox* aRefBox,
                              TransformReferenceBox::DimensionGetter aDimensionGetter = nullptr);
 
   void
   ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
                             const nsCSSValue::Array* aData,
                             nsStyleContext* aContext,
                             nsPresContext* aPresContext,
-                            bool& aCanStoreInRuleTree,
+                            mozilla::RuleNodeCacheConditions& aConditions,
                             TransformReferenceBox& aBounds);
 
   /**
    * Given an nsCSSValueList containing -moz-transform functions,
    * returns a matrix containing the value of those functions.
    *
    * @param aData The nsCSSValueList containing the transform functions
    * @param aContext The style context, used for unit conversion.
    * @param aPresContext The presentation context, used for unit conversion.
-   * @param aCanStoreInRuleTree Set to false if the result cannot be cached
-   *                            in the rule tree, otherwise untouched.
+   * @param aConditions Set to uncachable (by calling SetUncacheable()) if the
+   *   result cannot be cached in the rule tree, otherwise untouched.
    * @param aBounds The frame's bounding rectangle.
    * @param aAppUnitsPerMatrixUnit The number of app units per device pixel.
    *
    * aContext and aPresContext may be null if all of the (non-percent)
    * length values in aData are already known to have been converted to
    * eCSSUnit_Pixel (as they are in an StyleAnimationValue)
    */
   gfx3DMatrix ReadTransforms(const nsCSSValueList* aList,
                              nsStyleContext* aContext,
                              nsPresContext* aPresContext,
-                             bool &aCanStoreInRuleTree,
+                             mozilla::RuleNodeCacheConditions& aConditions,
                              TransformReferenceBox& aBounds,
                              float aAppUnitsPerMatrixUnit);
 
 } // namespace nsStyleTransformMatrix
 
 #endif