Bug 760331: Coalesce data for inline style across nodes. r=bz
authorKyle Huey <khuey@kylehuey.com>
Sun, 30 Sep 2012 09:40:24 -0700
changeset 114994 72e482dbd38460db058c95827a3e4e6857986fa4
parent 114993 08cb400c9a490d67b7fa553164250850d1eed2bb
child 114995 96f3db193c755b22956b50155b1ad36250df34db
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs760331, 686975
milestone18.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 760331: Coalesce data for inline style across nodes. r=bz This patch enables sharing of an nsAttrValue's MiscContainer between nodes for style rules. MiscContainers of type eCSSStyleRule are now refcounted (with some clever struct packing to ensure that the amount of memory allocated for MiscContainer remains unchanged on 32 and 64 bit). This infrastructure can be used to share most MiscContainer types in the future if we find advantages to sharing other types than just eCSSStyleRuley. A cache mapping strings to MiscContainers has been added to nsHTMLCSSStyleSheet. MiscContainers can be shared between nsAttrValues when one nsAttrValue is SetTo another nsAttrValue or when there is a cache hit in this cache. This patch also adds the ability to tell a style rule that it belongs to an nsHTMLCSSStyleSheet, with appropriate accessor functions to separate that from the existing case of belonging to an nsCSSStyleSheet. The primary use case is to reduce memory use for pages that have lots of inline style attributes with the same value. This can happen easily with large pages that are automatically generated. An (admittedly pathological) testcase in Bug 686975 sees over 250 MB of memory savings with this change. Reusing the same MiscContainer for multiple nodes saves the overhead of maintaining separate copies of the string containing the serialized value of the style attribute and of creating separate style rules for each node. Eliminating duplicate style rules enables further savings in layout through style context sharing. The testcase sees the amount of memory used by style contexts go from over 250 MB to 10 KB. Because the cache is based on the text value of the style attribute, it will not handle attributes that have different text values but are parsed into identical style rules. We also do not attempt to share MiscContainers when the node's base URI differs from the document URI. The effect of these limitations is expected to be low.
content/base/src/Makefile.in
content/base/src/nsAttrValue.cpp
content/base/src/nsAttrValue.h
content/base/src/nsAttrValueInlines.h
content/base/src/nsContentUtils.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsStyledElement.cpp
content/html/content/src/nsFormSubmission.cpp
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsHTMLBRElement.cpp
content/html/content/src/nsHTMLBodyElement.cpp
content/html/content/src/nsHTMLButtonElement.cpp
content/html/content/src/nsHTMLCanvasElement.cpp
content/html/content/src/nsHTMLFontElement.cpp
content/html/content/src/nsHTMLHRElement.cpp
content/html/content/src/nsHTMLIFrameElement.cpp
content/html/content/src/nsHTMLInputElement.cpp
content/html/content/src/nsHTMLLIElement.cpp
content/html/content/src/nsHTMLMediaElement.cpp
content/html/content/src/nsHTMLMenuElement.cpp
content/html/content/src/nsHTMLMenuItemElement.cpp
content/html/content/src/nsHTMLMeterElement.cpp
content/html/content/src/nsHTMLOListElement.cpp
content/html/content/src/nsHTMLObjectElement.cpp
content/html/content/src/nsHTMLPreElement.cpp
content/html/content/src/nsHTMLProgressElement.cpp
content/html/content/src/nsHTMLSharedElement.cpp
content/html/content/src/nsHTMLTableCaptionElement.cpp
content/html/content/src/nsHTMLTableCellElement.cpp
content/html/content/src/nsHTMLTableColElement.cpp
content/html/content/src/nsHTMLTableElement.cpp
content/html/content/src/nsHTMLTableRowElement.cpp
content/html/content/src/nsHTMLTableSectionElement.cpp
content/html/content/src/nsHTMLTextAreaElement.cpp
content/html/content/src/nsTextEditorState.cpp
content/smil/nsSMILAnimationFunction.cpp
content/smil/nsSMILTimedElement.cpp
content/svg/content/src/DOMSVGTransform.cpp
content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
content/svg/content/src/nsSVGAngle.cpp
content/svg/content/src/nsSVGLength2.cpp
content/svg/content/src/nsSVGViewBox.cpp
content/xul/content/src/nsXULElement.cpp
dom/base/nsFocusManager.cpp
dom/bindings/Makefile.in
dom/media/MediaManager.cpp
layout/forms/nsLegendFrame.cpp
layout/forms/nsTextControlFrame.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsBulletFrame.cpp
layout/generic/nsFrameSetFrame.cpp
layout/generic/nsSubDocumentFrame.cpp
layout/style/Rule.h
layout/style/StyleRule.cpp
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsCSSRules.cpp
layout/style/nsHTMLCSSStyleSheet.cpp
layout/style/nsHTMLCSSStyleSheet.h
layout/tables/nsTableCellFrame.cpp
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -30,16 +30,17 @@ EXPORTS		= \
 		nsStubDocumentObserver.h \
 		nsStubImageDecoderObserver.h \
 		nsStubMutationObserver.h \
 		nsTextFragment.h \
 		mozAutoDocUpdate.h \
 		nsFrameMessageManager.h \
 		nsAttrAndChildArray.h \
 		nsAttrValue.h \
+		nsAttrValueInlines.h \
 		nsCrossSiteListenerProxy.h \
 		nsDOMAttributeMap.h \
 		nsGenericElement.h \
 		nsMappedAttributeElement.h \
 		nsStyledElement.h \
     nsSandboxFlags.h \
 		$(NULL)
 
--- a/content/base/src/nsAttrValue.cpp
+++ b/content/base/src/nsAttrValue.cpp
@@ -4,30 +4,120 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * A struct that represents the value (type and actual data) of an
  * attribute.
  */
 
 #include "nsAttrValue.h"
+#include "nsAttrValueInlines.h"
 #include "nsIAtom.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/css/StyleRule.h"
 #include "mozilla/css/Declaration.h"
 #include "nsContentUtils.h"
 #include "nsReadableUtils.h"
 #include "prprf.h"
 #include "mozilla/HashFunctions.h"
+#include "nsHTMLCSSStyleSheet.h"
+#include "nsCSSParser.h"
+#include "nsStyledElement.h"
 
 using namespace mozilla;
 
 #define MISC_STR_PTR(_cont) \
   reinterpret_cast<void*>((_cont)->mStringBits & NS_ATTRVALUE_POINTERVALUE_MASK)
 
+bool
+MiscContainer::GetString(nsDependentString& aString) const
+{
+  void* ptr = MISC_STR_PTR(this);
+
+  if (!ptr) {
+    return false;
+  }
+
+  if (static_cast<nsAttrValue::ValueBaseType>(mStringBits &
+                                              NS_ATTRVALUE_BASETYPE_MASK) ==
+      nsAttrValue::eStringBase) {
+    nsStringBuffer* buffer = static_cast<nsStringBuffer*>(ptr);
+    if (!buffer) {
+      return false;
+    }
+
+    aString.Rebind(reinterpret_cast<PRUnichar*>(buffer->Data()),
+                   buffer->StorageSize() / sizeof(PRUnichar) - 1);
+    return true;
+  }
+
+  nsIAtom* atom = static_cast<nsIAtom*>(ptr);
+  if (!atom) {
+    return false;
+  }
+
+  aString.Rebind(atom->GetUTF16String(), atom->GetLength());
+  return true;
+}
+
+void
+MiscContainer::Cache()
+{
+  // Not implemented for anything else yet.
+  MOZ_ASSERT(mType == nsAttrValue::eCSSStyleRule);
+  MOZ_ASSERT(IsRefCounted());
+  MOZ_ASSERT(mValue.mRefCount > 0);
+  MOZ_ASSERT(!mValue.mCached);
+
+  css::StyleRule* rule = mValue.mCSSStyleRule;
+  nsHTMLCSSStyleSheet* sheet = rule->GetHTMLCSSStyleSheet();
+  if (!sheet) {
+    return;
+  }
+
+  nsDependentString str;
+  bool gotString = GetString(str);
+  if (!gotString) {
+    return;
+  }
+
+  sheet->CacheStyleAttr(str, this);
+  mValue.mCached = 1;
+
+  // This has to be immutable once it goes into the cache.
+  css::Declaration* decl = rule->GetDeclaration();
+  if (decl) {
+    decl->SetImmutable();
+  }
+}
+
+void
+MiscContainer::Evict()
+{
+  // Not implemented for anything else yet.
+  MOZ_ASSERT(mType == nsAttrValue::eCSSStyleRule);
+  MOZ_ASSERT(IsRefCounted());
+  MOZ_ASSERT(mValue.mRefCount == 0);
+
+  if (!mValue.mCached) {
+    return;
+  }
+
+  css::StyleRule* rule = mValue.mCSSStyleRule;
+  nsHTMLCSSStyleSheet* sheet = rule->GetHTMLCSSStyleSheet();
+  MOZ_ASSERT(sheet);
+
+  nsDependentString str;
+  DebugOnly<bool> gotString = GetString(str);
+  MOZ_ASSERT(gotString);
+
+  sheet->EvictStyleAttr(str, this);
+  mValue.mCached = 0;
+}
+
 nsTArray<const nsAttrValue::EnumTable*>* nsAttrValue::sEnumTableArray = nullptr;
 
 nsAttrValue::nsAttrValue()
     : mBits(0)
 {
 }
 
 nsAttrValue::nsAttrValue(const nsAttrValue& aOther)
@@ -114,18 +204,23 @@ nsAttrValue::Reset()
       if (str) {
         str->Release();
       }
 
       break;
     }
     case eOtherBase:
     {
-      EnsureEmptyMiscContainer();
-      delete GetMiscContainer();
+      MiscContainer* cont = GetMiscContainer();
+      if (cont->IsRefCounted() && cont->mValue.mRefCount > 1) {
+        NS_RELEASE(cont);
+        break;
+      }
+
+      delete ClearMiscContainer();
 
       break;
     }
     case eAtomBase:
     {
       nsIAtom* atom = GetAtomValue();
       NS_RELEASE(atom);
 
@@ -174,83 +269,87 @@ nsAttrValue::SetTo(const nsAttrValue& aO
     {
       ResetIfSet();
       mBits = aOther.mBits;
       return;      
     }
   }
 
   MiscContainer* otherCont = aOther.GetMiscContainer();
-  if (!EnsureEmptyMiscContainer()) {
+  if (otherCont->IsRefCounted()) {
+    delete ClearMiscContainer();
+    NS_ADDREF(otherCont);
+    SetPtrValueAndType(otherCont, eOtherBase);
     return;
   }
 
-  MiscContainer* cont = GetMiscContainer();
+  MiscContainer* cont = EnsureEmptyMiscContainer();
   switch (otherCont->mType) {
     case eInteger:
     {
-      cont->mInteger = otherCont->mInteger;
+      cont->mValue.mInteger = otherCont->mValue.mInteger;
       break;
     }
     case eEnum:
     {
-      cont->mEnumValue = otherCont->mEnumValue;
+      cont->mValue.mEnumValue = otherCont->mValue.mEnumValue;
       break;
     }
     case ePercent:
     {
-      cont->mPercent = otherCont->mPercent;
+      cont->mValue.mPercent = otherCont->mValue.mPercent;
       break;
     }
     case eColor:
     {
-      cont->mColor = otherCont->mColor;
+      cont->mValue.mColor = otherCont->mValue.mColor;
       break;
     }
     case eCSSStyleRule:
     {
-      NS_ADDREF(cont->mCSSStyleRule = otherCont->mCSSStyleRule);
+      MOZ_NOT_REACHED("These should be refcounted!");
       break;
     }
     case eURL:
     {
-      NS_ADDREF(cont->mURL = otherCont->mURL);
+      NS_ADDREF(cont->mValue.mURL = otherCont->mValue.mURL);
       break;
     }
     case eImage:
     {
-      NS_ADDREF(cont->mImage = otherCont->mImage);
+      NS_ADDREF(cont->mValue.mImage = otherCont->mValue.mImage);
       break;
     }
     case eAtomArray:
     {
       if (!EnsureEmptyAtomArray() ||
-          !GetAtomArrayValue()->AppendElements(*otherCont->mAtomArray)) {
+          !GetAtomArrayValue()->AppendElements(*otherCont->mValue.mAtomArray)) {
         Reset();
         return;
       }
       break;
     }
     case eDoubleValue:
     {
       cont->mDoubleValue = otherCont->mDoubleValue;
       break;
     }
     case eIntMarginValue:
     {
-      if (otherCont->mIntMargin)
-        cont->mIntMargin = new nsIntMargin(*otherCont->mIntMargin);
+      if (otherCont->mValue.mIntMargin)
+        cont->mValue.mIntMargin =
+          new nsIntMargin(*otherCont->mValue.mIntMargin);
       break;
     }
     default:
     {
       if (IsSVGType(otherCont->mType)) {
         // All SVG types are just pointers to classes and will therefore have
         // the same size so it doesn't really matter which one we assign
-        cont->mSVGAngle = otherCont->mSVGAngle;
+        cont->mValue.mSVGAngle = otherCont->mValue.mSVGAngle;
       } else {
         NS_NOTREACHED("unknown type stored in MiscContainer");
       }
       break;
     }
   }
 
   void* otherPtr = MISC_STR_PTR(otherCont);
@@ -300,54 +399,49 @@ nsAttrValue::SetTo(int32_t aInt, const n
 {
   ResetIfSet();
   SetIntValueAndType(aInt, eInteger, aSerialized);
 }
 
 void
 nsAttrValue::SetTo(double aValue, const nsAString* aSerialized)
 {
-  if (EnsureEmptyMiscContainer()) {
-    MiscContainer* cont = GetMiscContainer();
-    cont->mDoubleValue = aValue;
-    cont->mType = eDoubleValue;
-    SetMiscAtomOrString(aSerialized);
-  }
+  MiscContainer* cont = EnsureEmptyMiscContainer();
+  cont->mDoubleValue = aValue;
+  cont->mType = eDoubleValue;
+  SetMiscAtomOrString(aSerialized);
 }
 
 void
 nsAttrValue::SetTo(css::StyleRule* aValue, const nsAString* aSerialized)
 {
-  if (EnsureEmptyMiscContainer()) {
-    MiscContainer* cont = GetMiscContainer();
-    NS_ADDREF(cont->mCSSStyleRule = aValue);
-    cont->mType = eCSSStyleRule;
-    SetMiscAtomOrString(aSerialized);
-  }
+  MiscContainer* cont = EnsureEmptyMiscContainer();
+  MOZ_ASSERT(cont->mValue.mRefCount == 0);
+  NS_ADDREF(cont->mValue.mCSSStyleRule = aValue);
+  cont->mType = eCSSStyleRule;
+  NS_ADDREF(cont);
+  SetMiscAtomOrString(aSerialized);
+  MOZ_ASSERT(cont->mValue.mRefCount == 1);
 }
 
 void
 nsAttrValue::SetTo(css::URLValue* aValue, const nsAString* aSerialized)
 {
-  if (EnsureEmptyMiscContainer()) {
-    MiscContainer* cont = GetMiscContainer();
-    NS_ADDREF(cont->mURL = aValue);
-    cont->mType = eURL;
-    SetMiscAtomOrString(aSerialized);
-  }
+  MiscContainer* cont = EnsureEmptyMiscContainer();
+  NS_ADDREF(cont->mValue.mURL = aValue);
+  cont->mType = eURL;
+  SetMiscAtomOrString(aSerialized);
 }
 
 void
 nsAttrValue::SetTo(const nsIntMargin& aValue)
 {
-  if (EnsureEmptyMiscContainer()) {
-    MiscContainer* cont = GetMiscContainer();
-    cont->mIntMargin = new nsIntMargin(aValue);
-    cont->mType = eIntMarginValue;
-  }
+  MiscContainer* cont = EnsureEmptyMiscContainer();
+  cont->mValue.mIntMargin = new nsIntMargin(aValue);
+  cont->mType = eIntMarginValue;
 }
 
 void
 nsAttrValue::SetToSerialized(const nsAttrValue& aOther)
 {
   if (aOther.Type() != nsAttrValue::eString &&
       aOther.Type() != nsAttrValue::eAtom) {
     nsAutoString val;
@@ -476,30 +570,21 @@ nsAttrValue::SwapValueWith(nsAttrValue& 
 }
 
 void
 nsAttrValue::ToString(nsAString& aResult) const
 {
   MiscContainer* cont = nullptr;
   if (BaseType() == eOtherBase) {
     cont = GetMiscContainer();
-    void* ptr = MISC_STR_PTR(cont);
-    if (ptr) {
-      if (static_cast<ValueBaseType>(cont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) ==
-          eStringBase) {
-        nsStringBuffer* str = static_cast<nsStringBuffer*>(ptr);
-        if (str) {
-          str->ToString(str->StorageSize()/sizeof(PRUnichar) - 1, aResult);
-          return;
-        }
-      } else {
-        nsIAtom *atom = static_cast<nsIAtom*>(ptr);
-        atom->ToString(aResult);
-        return;
-      }
+
+    nsDependentString str;
+    if (cont->GetString(str)) {
+      aResult = str;
+      return;
     }
   }
 
   switch(Type()) {
     case eString:
     {
       nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr());
       if (str) {
@@ -536,104 +621,110 @@ nsAttrValue::ToString(nsAString& aResult
     case eEnum:
     {
       GetEnumString(aResult, false);
       break;
     }
     case ePercent:
     {
       nsAutoString intStr;
-      intStr.AppendInt(cont ? cont->mPercent : GetIntInternal());
+      intStr.AppendInt(cont ? cont->mValue.mPercent : GetIntInternal());
       aResult = intStr + NS_LITERAL_STRING("%");
 
       break;
     }
     case eCSSStyleRule:
     {
       aResult.Truncate();
       MiscContainer *container = GetMiscContainer();
-      css::Declaration *decl = container->mCSSStyleRule->GetDeclaration();
+      css::Declaration *decl =
+        container->mValue.mCSSStyleRule->GetDeclaration();
       if (decl) {
         decl->ToString(aResult);
       }
       const_cast<nsAttrValue*>(this)->SetMiscAtomOrString(&aResult);
 
       break;
     }
     case eDoubleValue:
     {
       aResult.Truncate();
       aResult.AppendFloat(GetDoubleValue());
       break;
     }
     case eSVGAngle:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGAngle, aResult);
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGAngle,
+                                    aResult);
       break;
     }
     case eSVGIntegerPair:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGIntegerPair,
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGIntegerPair,
                                     aResult);
       break;
     }
     case eSVGLength:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGLength, aResult);
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGLength,
+                                    aResult);
       break;
     }
     case eSVGLengthList:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGLengthList,
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGLengthList,
                                     aResult);
       break;
     }
     case eSVGNumberList:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGNumberList,
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGNumberList,
                                     aResult);
       break;
     }
     case eSVGNumberPair:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGNumberPair,
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGNumberPair,
                                     aResult);
       break;
     }
     case eSVGPathData:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGPathData, aResult);
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPathData,
+                                    aResult);
       break;
     }
     case eSVGPointList:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGPointList, aResult);
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPointList,
+                                    aResult);
       break;
     }
     case eSVGPreserveAspectRatio:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGPreserveAspectRatio,
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPreserveAspectRatio,
                                     aResult);
       break;
     }
     case eSVGStringList:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGStringList,
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGStringList,
                                     aResult);
       break;
     }
     case eSVGTransformList:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGTransformList,
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGTransformList,
                                     aResult);
       break;
     }
     case eSVGViewBox:
     {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGViewBox, aResult);
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGViewBox,
+                                    aResult);
       break;
     }
     default:
     {
       aResult.Truncate();
       break;
     }
   }
@@ -674,28 +765,28 @@ bool
 nsAttrValue::GetColorValue(nscolor& aColor) const
 {
   if (Type() != eColor) {
     // Unparseable value, treat as unset.
     NS_ASSERTION(Type() == eString, "unexpected type for color-valued attr");
     return false;
   }
 
-  aColor = GetMiscContainer()->mColor;
+  aColor = GetMiscContainer()->mValue.mColor;
   return true;
 }
 
 void
 nsAttrValue::GetEnumString(nsAString& aResult, bool aRealTag) const
 {
   NS_PRECONDITION(Type() == eEnum, "wrong type");
 
   uint32_t allEnumBits =
     (BaseType() == eIntegerBase) ? static_cast<uint32_t>(GetIntInternal())
-                                   : GetMiscContainer()->mEnumValue;
+                                   : GetMiscContainer()->mValue.mEnumValue;
   int16_t val = allEnumBits >> NS_ATTRVALUE_ENUMTABLEINDEX_BITS;
   const EnumTable* table = sEnumTableArray->
     ElementAt(allEnumBits & NS_ATTRVALUE_ENUMTABLEINDEX_MASK);
 
   while (table->tag) {
     if (table->value == val) {
       aResult.AssignASCII(table->tag);
       if (!aRealTag && allEnumBits & NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER) {
@@ -772,68 +863,68 @@ nsAttrValue::HashValue() const
   if (static_cast<ValueBaseType>(cont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK)
       == eAtomBase) {
     return cont->mStringBits - 0;
   }
 
   switch (cont->mType) {
     case eInteger:
     {
-      return cont->mInteger;
+      return cont->mValue.mInteger;
     }
     case eEnum:
     {
-      return cont->mEnumValue;
+      return cont->mValue.mEnumValue;
     }
     case ePercent:
     {
-      return cont->mPercent;
+      return cont->mValue.mPercent;
     }
     case eColor:
     {
-      return cont->mColor;
+      return cont->mValue.mColor;
     }
     case eCSSStyleRule:
     {
-      return NS_PTR_TO_INT32(cont->mCSSStyleRule);
+      return NS_PTR_TO_INT32(cont->mValue.mCSSStyleRule);
     }
     // Intentionally identical, so that loading the image does not change the
     // hash code.
     case eURL:
     case eImage:
     {
       nsString str;
       ToString(str);
       return HashString(str);
     }
     case eAtomArray:
     {
       uint32_t hash = 0;
-      uint32_t count = cont->mAtomArray->Length();
-      for (nsCOMPtr<nsIAtom> *cur = cont->mAtomArray->Elements(),
+      uint32_t count = cont->mValue.mAtomArray->Length();
+      for (nsCOMPtr<nsIAtom> *cur = cont->mValue.mAtomArray->Elements(),
                              *end = cur + count;
            cur != end; ++cur) {
         hash = AddToHash(hash, cur->get());
       }
       return hash;
     }
     case eDoubleValue:
     {
       // XXX this is crappy, but oh well
       return cont->mDoubleValue;
     }
     case eIntMarginValue:
     {
-      return NS_PTR_TO_INT32(cont->mIntMargin);
+      return NS_PTR_TO_INT32(cont->mValue.mIntMargin);
     }
     default:
     {
       if (IsSVGType(cont->mType)) {
         // All SVG types are just pointers to classes so we can treat them alike
-        return NS_PTR_TO_INT32(cont->mSVGAngle);
+        return NS_PTR_TO_INT32(cont->mValue.mSVGAngle);
       }
       NS_NOTREACHED("unknown type stored in MiscContainer");
       return 0;
     }
   }
 }
 
 bool
@@ -856,82 +947,86 @@ nsAttrValue::Equals(const nsAttrValue& a
     case eIntegerBase:
     {
       return mBits == aOther.mBits;
     }
   }
 
   MiscContainer* thisCont = GetMiscContainer();
   MiscContainer* otherCont = aOther.GetMiscContainer();
+  if (thisCont == otherCont) {
+    return true;
+  }
+
   if (thisCont->mType != otherCont->mType) {
     return false;
   }
 
   bool needsStringComparison = false;
 
   switch (thisCont->mType) {
     case eInteger:
     {
-      if (thisCont->mInteger == otherCont->mInteger) {
+      if (thisCont->mValue.mInteger == otherCont->mValue.mInteger) {
         needsStringComparison = true;
       }
       break;
     }
     case eEnum:
     {
-      if (thisCont->mEnumValue == otherCont->mEnumValue) {
+      if (thisCont->mValue.mEnumValue == otherCont->mValue.mEnumValue) {
         needsStringComparison = true;
       }
       break;
     }
     case ePercent:
     {
-      if (thisCont->mPercent == otherCont->mPercent) {
+      if (thisCont->mValue.mPercent == otherCont->mValue.mPercent) {
         needsStringComparison = true;
       }
       break;
     }
     case eColor:
     {
-      if (thisCont->mColor == otherCont->mColor) {
+      if (thisCont->mValue.mColor == otherCont->mValue.mColor) {
         needsStringComparison = true;
       }
       break;
     }
     case eCSSStyleRule:
     {
-      return thisCont->mCSSStyleRule == otherCont->mCSSStyleRule;
+      return thisCont->mValue.mCSSStyleRule == otherCont->mValue.mCSSStyleRule;
     }
     case eURL:
     {
-      return thisCont->mURL == otherCont->mURL;
+      return thisCont->mValue.mURL == otherCont->mValue.mURL;
     }
     case eImage:
     {
-      return thisCont->mImage == otherCont->mImage;
+      return thisCont->mValue.mImage == otherCont->mValue.mImage;
     }
     case eAtomArray:
     {
       // For classlists we could be insensitive to order, however
       // classlists are never mapped attributes so they are never compared.
 
-      if (!(*thisCont->mAtomArray == *otherCont->mAtomArray)) {
+      if (!(*thisCont->mValue.mAtomArray == *otherCont->mValue.mAtomArray)) {
         return false;
       }
 
       needsStringComparison = true;
       break;
     }
     case eDoubleValue:
     {
       return thisCont->mDoubleValue == otherCont->mDoubleValue;
     }
     case eIntMarginValue:
     {
-      return thisCont->mIntMargin == otherCont->mIntMargin;
+      return thisCont->mValue.mIntMargin == otherCont->mValue.mIntMargin;
     }
     default:
     {
       if (IsSVGType(thisCont->mType)) {
         // Currently this method is never called for nsAttrValue objects that
         // point to SVG data types.
         // If that changes then we probably want to add methods to the
         // corresponding SVG types to compare their base values.
@@ -1238,43 +1333,41 @@ nsAttrValue::ParseStringOrAtom(const nsA
 }
 
 void
 nsAttrValue::SetIntValueAndType(int32_t aValue, ValueType aType,
                                 const nsAString* aStringValue)
 {
   if (aStringValue || aValue > NS_ATTRVALUE_INTEGERTYPE_MAXVALUE ||
       aValue < NS_ATTRVALUE_INTEGERTYPE_MINVALUE) {
-    if (EnsureEmptyMiscContainer()) {
-      MiscContainer* cont = GetMiscContainer();
-      switch (aType) {
-        case eInteger:
-        {
-          cont->mInteger = aValue;
-          break;
-        }
-        case ePercent:
-        {
-          cont->mPercent = aValue;
-          break;
-        }
-        case eEnum:
-        {
-          cont->mEnumValue = aValue;
-          break;
-        }
-        default:
-        {
-          NS_NOTREACHED("unknown integer type");
-          break;
-        }
+    MiscContainer* cont = EnsureEmptyMiscContainer();
+    switch (aType) {
+      case eInteger:
+      {
+        cont->mValue.mInteger = aValue;
+        break;
+      }
+      case ePercent:
+      {
+        cont->mValue.mPercent = aValue;
+        break;
       }
-      cont->mType = aType;
-      SetMiscAtomOrString(aStringValue);
+      case eEnum:
+      {
+        cont->mValue.mEnumValue = aValue;
+        break;
+      }
+      default:
+      {
+        NS_NOTREACHED("unknown integer type");
+        break;
+      }
     }
+    cont->mType = aType;
+    SetMiscAtomOrString(aStringValue);
   } else {
     NS_ASSERTION(!mBits, "Reset before calling SetIntValueAndType!");
     mBits = (aValue * NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER) | aType;
   }
 }
 
 int16_t
 nsAttrValue::GetEnumTableIndex(const EnumTable* aTable)
@@ -1433,23 +1526,18 @@ nsAttrValue::ParsePositiveIntValue(const
 void
 nsAttrValue::SetColorValue(nscolor aColor, const nsAString& aString)
 {
   nsStringBuffer* buf = GetStringBuffer(aString);
   if (!buf) {
     return;
   }
 
-  if (!EnsureEmptyMiscContainer()) {
-    buf->Release();
-    return;
-  }
-
-  MiscContainer* cont = GetMiscContainer();
-  cont->mColor = aColor;
+  MiscContainer* cont = EnsureEmptyMiscContainer();
+  cont->mValue.mColor = aColor;
   cont->mType = eColor;
 
   // Save the literal string we were passed for round-tripping.
   cont->mStringBits = reinterpret_cast<PtrBits>(buf) | eStringBase;
 }
 
 bool
 nsAttrValue::ParseColor(const nsAString& aString)
@@ -1500,47 +1588,40 @@ bool nsAttrValue::ParseDoubleValue(const
 {
   ResetIfSet();
 
   nsresult ec;
   double val = PromiseFlatString(aString).ToDouble(&ec);
   if (NS_FAILED(ec)) {
     return false;
   }
-  if (EnsureEmptyMiscContainer()) {
-    MiscContainer* cont = GetMiscContainer();
-    cont->mDoubleValue = val;
-    cont->mType = eDoubleValue;
-    nsAutoString serializedFloat;
-    serializedFloat.AppendFloat(val);
-    SetMiscAtomOrString(serializedFloat.Equals(aString) ? nullptr : &aString);
-    return true;
-  }
 
-  return false;
+  MiscContainer* cont = EnsureEmptyMiscContainer();
+  cont->mDoubleValue = val;
+  cont->mType = eDoubleValue;
+  nsAutoString serializedFloat;
+  serializedFloat.AppendFloat(val);
+  SetMiscAtomOrString(serializedFloat.Equals(aString) ? nullptr : &aString);
+  return true;
 }
 
 bool
 nsAttrValue::ParseIntMarginValue(const nsAString& aString)
 {
   ResetIfSet();
 
   nsIntMargin margins;
   if (!nsContentUtils::ParseIntMarginValue(aString, margins))
     return false;
 
-  if (EnsureEmptyMiscContainer()) {
-    MiscContainer* cont = GetMiscContainer();
-    cont->mIntMargin = new nsIntMargin(margins);
-    cont->mType = eIntMarginValue;
-    SetMiscAtomOrString(&aString);
-    return true;
-  }
-
-  return false;
+  MiscContainer* cont = EnsureEmptyMiscContainer();
+  cont->mValue.mIntMargin = new nsIntMargin(margins);
+  cont->mType = eIntMarginValue;
+  SetMiscAtomOrString(&aString);
+  return true;
 }
 
 void
 nsAttrValue::LoadImage(nsIDocument* aDocument)
 {
   NS_ASSERTION(Type() == eURL, "wrong type");
 
 #ifdef DEBUG
@@ -1548,27 +1629,75 @@ nsAttrValue::LoadImage(nsIDocument* aDoc
     nsString val;
     ToString(val);
     NS_ASSERTION(!val.IsEmpty(),
                  "How did we end up with an empty string for eURL");
   }
 #endif
 
   MiscContainer* cont = GetMiscContainer();
-  mozilla::css::URLValue* url = cont->mURL;
+  mozilla::css::URLValue* url = cont->mValue.mURL;
   mozilla::css::ImageValue* image = 
     new css::ImageValue(url->GetURI(), url->mString, url->mReferrer,
                         url->mOriginPrincipal, aDocument);
 
   NS_ADDREF(image);
-  cont->mImage = image;
+  cont->mValue.mImage = image;
   NS_RELEASE(url);
   cont->mType = eImage;
 }
 
+bool
+nsAttrValue::ParseStyleAttribute(const nsAString& aString,
+                                 nsStyledElementNotElementCSSInlineStyle* aElement)
+{
+  nsIDocument* ownerDoc = aElement->OwnerDoc();
+  nsHTMLCSSStyleSheet* sheet = ownerDoc->GetInlineStyleSheet();
+  nsCOMPtr<nsIURI> baseURI = aElement->GetBaseURI();
+  nsIURI* docURI = ownerDoc->GetDocumentURI();
+
+  NS_ASSERTION(aElement->NodePrincipal() == ownerDoc->NodePrincipal(),
+               "This is unexpected");
+
+  // If the (immutable) document URI does not match the element's base URI
+  // (the common case is that they do match) do not cache the rule.  This is
+  // because the results of the CSS parser are dependent on these URIs, and we
+  // do not want to have to account for the URIs in the hash lookup.
+  bool cachingAllowed = sheet && baseURI == docURI;
+  if (cachingAllowed) {
+    MiscContainer* cont = sheet->LookupStyleAttr(aString);
+    if (cont) {
+      // Set our MiscContainer to the cached one.
+      NS_ADDREF(cont);
+      SetPtrValueAndType(cont, eOtherBase);
+      return true;
+    }
+  }
+
+  css::Loader* cssLoader = ownerDoc->CSSLoader();
+  nsCSSParser cssParser(cssLoader);
+
+  nsRefPtr<css::StyleRule> rule;
+  cssParser.ParseStyleAttribute(aString, docURI, baseURI,
+                                aElement->NodePrincipal(),
+                                getter_AddRefs(rule));
+  if (rule) {
+    rule->SetHTMLCSSStyleSheet(sheet);
+    SetTo(rule, &aString);
+    if (cachingAllowed) {
+      MiscContainer* cont = GetMiscContainer();
+      cont->Cache();
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
 void
 nsAttrValue::SetMiscAtomOrString(const nsAString* aValue)
 {
   NS_ASSERTION(GetMiscContainer(), "Must have MiscContainer!");
   NS_ASSERTION(!GetMiscContainer()->mStringBits,
                "Trying to re-set atom or string!");
   if (aValue) {
     uint32_t len = aValue->Length();
@@ -1610,105 +1739,119 @@ nsAttrValue::ResetMiscAtomOrString()
     cont->mStringBits = 0;
   }
 }
 
 void
 nsAttrValue::SetSVGType(ValueType aType, const void* aValue,
                         const nsAString* aSerialized) {
   NS_ABORT_IF_FALSE(IsSVGType(aType), "Not an SVG type");
-  if (EnsureEmptyMiscContainer()) {
-    MiscContainer* cont = GetMiscContainer();
-    // All SVG types are just pointers to classes so just setting any of them
-    // will do. We'll lose type-safety but the signature of the calling
-    // function should ensure we don't get anything unexpected, and once we
-    // stick aValue in a union we lose type information anyway.
-    cont->mSVGAngle = static_cast<const nsSVGAngle*>(aValue);
-    cont->mType = aType;
-    SetMiscAtomOrString(aSerialized);
-  }
+
+  MiscContainer* cont = EnsureEmptyMiscContainer();
+  // All SVG types are just pointers to classes so just setting any of them
+  // will do. We'll lose type-safety but the signature of the calling
+  // function should ensure we don't get anything unexpected, and once we
+  // stick aValue in a union we lose type information anyway.
+  cont->mValue.mSVGAngle = static_cast<const nsSVGAngle*>(aValue);
+  cont->mType = aType;
+  SetMiscAtomOrString(aSerialized);
 }
 
-bool
-nsAttrValue::EnsureEmptyMiscContainer()
+MiscContainer*
+nsAttrValue::ClearMiscContainer()
 {
-  MiscContainer* cont;
+  MiscContainer* cont = nullptr;
   if (BaseType() == eOtherBase) {
-    ResetMiscAtomOrString();
     cont = GetMiscContainer();
-    switch (cont->mType) {
-      case eCSSStyleRule:
-      {
-        NS_RELEASE(cont->mCSSStyleRule);
-        break;
-      }
-      case eURL:
-      {
-        NS_RELEASE(cont->mURL);
-        break;
-      }
-      case eImage:
-      {
-        NS_RELEASE(cont->mImage);
-        break;
-      }
-      case eAtomArray:
-      {
-        delete cont->mAtomArray;
-        break;
-      }
-      case eIntMarginValue:
-      {
-        delete cont->mIntMargin;
-        break;
-      }
-      default:
-      {
-        break;
+    if (cont->IsRefCounted() && cont->mValue.mRefCount > 1) {
+      // This MiscContainer is shared, we need a new one.
+      NS_RELEASE(cont);
+
+      cont = new MiscContainer;
+      SetPtrValueAndType(cont, eOtherBase);
+    }
+    else {
+      switch (cont->mType) {
+        case eCSSStyleRule:
+        {
+          MOZ_ASSERT(cont->mValue.mRefCount == 1);
+          cont->Release();
+          cont->Evict();
+          NS_RELEASE(cont->mValue.mCSSStyleRule);
+          break;
+        }
+        case eURL:
+        {
+          NS_RELEASE(cont->mValue.mURL);
+          break;
+        }
+        case eImage:
+        {
+          NS_RELEASE(cont->mValue.mImage);
+          break;
+        }
+        case eAtomArray:
+        {
+          delete cont->mValue.mAtomArray;
+          break;
+        }
+        case eIntMarginValue:
+        {
+          delete cont->mValue.mIntMargin;
+          break;
+        }
+        default:
+        {
+          break;
+        }
       }
     }
+    ResetMiscAtomOrString();
   }
   else {
     ResetIfSet();
+  }
 
+  return cont;
+}
+
+MiscContainer*
+nsAttrValue::EnsureEmptyMiscContainer()
+{
+  MiscContainer* cont = ClearMiscContainer();
+  if (cont) {
+    MOZ_ASSERT(BaseType() == eOtherBase);
+    ResetMiscAtomOrString();
+    cont = GetMiscContainer();
+  }
+  else {
     cont = new MiscContainer;
-    NS_ENSURE_TRUE(cont, false);
-
     SetPtrValueAndType(cont, eOtherBase);
   }
 
-  cont->mType = eColor;
-  cont->mStringBits = 0;
-  cont->mColor = 0;
-
-  return true;
+  return cont;
 }
 
 bool
 nsAttrValue::EnsureEmptyAtomArray()
 {
   if (Type() == eAtomArray) {
     ResetMiscAtomOrString();
     GetAtomArrayValue()->Clear();
     return true;
   }
 
-  if (!EnsureEmptyMiscContainer()) {
-    // should already be reset
-    return false;
-  }
-
   AtomArray* array = new AtomArray;
   if (!array) {
     Reset();
     return false;
   }
 
-  MiscContainer* cont = GetMiscContainer();
-  cont->mAtomArray = array;
+  MiscContainer* cont = EnsureEmptyMiscContainer();
+  cont->mValue.mAtomArray = array;
   cont->mType = eAtomArray;
 
   return true;
 }
 
 nsStringBuffer*
 nsAttrValue::GetStringBuffer(const nsAString& aValue) const
 {
@@ -1829,23 +1972,23 @@ nsAttrValue::SizeOfExcludingThis(nsMallo
       // We only count the size of the object pointed by otherPtr if it's a
       // string. When it's an atom, it's counted separatly.
       if (otherPtr &&
           static_cast<ValueBaseType>(container->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) == eStringBase) {
         nsStringBuffer* str = static_cast<nsStringBuffer*>(otherPtr);
         n += str ? str->SizeOfIncludingThisIfUnshared(aMallocSizeOf) : 0;
       }
 
-      if (Type() == eCSSStyleRule && container->mCSSStyleRule) {
+      if (Type() == eCSSStyleRule && container->mValue.mCSSStyleRule) {
         // TODO: mCSSStyleRule might be owned by another object which would
         //       make us count them twice, bug 677493.
         //n += container->mCSSStyleRule->SizeOfIncludingThis(aMallocSizeOf);
-      } else if (Type() == eAtomArray && container->mAtomArray) {
+      } else if (Type() == eAtomArray && container->mValue.mAtomArray) {
         // Don't measure each nsIAtom, they are measured separatly.
-        n += container->mAtomArray->SizeOfIncludingThis(aMallocSizeOf);
+        n += container->mValue.mAtomArray->SizeOfIncludingThis(aMallocSizeOf);
       }
       break;
     }
     case eAtomBase:    // Atoms are counted separately.
     case eIntegerBase: // The value is in mBits, nothing to do.
       break;
   }
 
--- a/content/base/src/nsAttrValue.h
+++ b/content/base/src/nsAttrValue.h
@@ -21,16 +21,18 @@
 #include "SVGAttrValueWrapper.h"
 
 typedef uintptr_t PtrBits;
 class nsAString;
 class nsIAtom;
 class nsIDocument;
 template<class E, class A> class nsTArray;
 struct nsTArrayDefaultAllocator;
+class nsStyledElementNotElementCSSInlineStyle;
+struct MiscContainer;
 
 namespace mozilla {
 namespace css {
 class StyleRule;
 struct URLValue;
 struct ImageValue;
 }
 }
@@ -61,32 +63,20 @@ public:
   nsCheapString(nsStringBuffer* aBuf)
   {
     if (aBuf)
       aBuf->ToString(aBuf->StorageSize()/2 - 1, *this);
   }
 };
 
 class nsAttrValue {
+  friend struct MiscContainer;
 public:
   typedef nsTArray< nsCOMPtr<nsIAtom> > AtomArray;
 
-  nsAttrValue();
-  nsAttrValue(const nsAttrValue& aOther);
-  explicit nsAttrValue(const nsAString& aValue);
-  explicit nsAttrValue(nsIAtom* aValue);
-  nsAttrValue(mozilla::css::StyleRule* aValue, const nsAString* aSerialized);
-  explicit nsAttrValue(const nsIntMargin& aValue);
-  ~nsAttrValue();
-
-  inline const nsAttrValue& operator=(const nsAttrValue& aOther);
-
-  static nsresult Init();
-  static void Shutdown();
-
   // This has to be the same as in ValueBaseType
   enum ValueType {
     eString =       0x00, //   00
                           //   01  this value indicates an 'misc' struct
     eAtom =         0x02, //   10
     eInteger =      0x03, // 0011
     eColor =        0x07, // 0111
     eEnum =         0x0B, // 1011  This should eventually die
@@ -110,16 +100,29 @@ public:
     ,eSVGPointList  =  0x23
     ,eSVGPreserveAspectRatio = 0x24
     ,eSVGStringList =  0x25
     ,eSVGTransformList = 0x26
     ,eSVGViewBox =     0x27
     ,eSVGTypesEnd =    0x34
   };
 
+  nsAttrValue();
+  nsAttrValue(const nsAttrValue& aOther);
+  explicit nsAttrValue(const nsAString& aValue);
+  explicit nsAttrValue(nsIAtom* aValue);
+  nsAttrValue(mozilla::css::StyleRule* aValue, const nsAString* aSerialized);
+  explicit nsAttrValue(const nsIntMargin& aValue);
+  ~nsAttrValue();
+
+  inline const nsAttrValue& operator=(const nsAttrValue& aOther);
+
+  static nsresult Init();
+  static void Shutdown();
+
   ValueType Type() const;
 
   void Reset();
 
   void SetTo(const nsAttrValue& aOther);
   void SetTo(const nsAString& aValue);
   void SetTo(nsIAtom* aValue);
   void SetTo(int16_t aInt);
@@ -352,61 +355,36 @@ public:
 
   /**
    * Convert a URL nsAttrValue to an Image nsAttrValue.
    *
    * @param aDocument the document this nsAttrValue belongs to.
    */
   void LoadImage(nsIDocument* aDocument);
 
+  /**
+   * Parse a string into a CSS style rule.
+   *
+   * @param aString the style attribute value to be parsed.
+   * @param aElement the element the attribute is set on.
+   */
+  bool ParseStyleAttribute(const nsAString& aString,
+                           nsStyledElementNotElementCSSInlineStyle* aElement);
+
   size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 
 private:
   // These have to be the same as in ValueType
   enum ValueBaseType {
     eStringBase =    eString,    // 00
     eOtherBase =     0x01,       // 01
     eAtomBase =      eAtom,      // 10
     eIntegerBase =   0x03        // 11
   };
 
-  struct MiscContainer
-  {
-    ValueType mType;
-    // mStringBits points to either nsIAtom* or nsStringBuffer* and is used when
-    // mType isn't mCSSStyleRule.
-    // Note eStringBase and eAtomBase is used also to handle the type of
-    // mStringBits.
-    PtrBits mStringBits;
-    union {
-      int32_t mInteger;
-      nscolor mColor;
-      uint32_t mEnumValue;
-      int32_t mPercent;
-      mozilla::css::StyleRule* mCSSStyleRule;
-      mozilla::css::URLValue* mURL;
-      mozilla::css::ImageValue* mImage;
-      AtomArray* mAtomArray;
-      double mDoubleValue;
-      nsIntMargin* mIntMargin;
-      const nsSVGAngle* mSVGAngle;
-      const nsSVGIntegerPair* mSVGIntegerPair;
-      const nsSVGLength2* mSVGLength;
-      const mozilla::SVGLengthList* mSVGLengthList;
-      const mozilla::SVGNumberList* mSVGNumberList;
-      const nsSVGNumberPair* mSVGNumberPair;
-      const mozilla::SVGPathData* mSVGPathData;
-      const mozilla::SVGPointList* mSVGPointList;
-      const mozilla::SVGAnimatedPreserveAspectRatio* mSVGPreserveAspectRatio;
-      const mozilla::SVGStringList* mSVGStringList;
-      const mozilla::SVGTransformList* mSVGTransformList;
-      const nsSVGViewBox* mSVGViewBox;
-    };
-  };
-
   inline ValueBaseType BaseType() const;
   inline bool IsSVGType(ValueType aType) const;
 
   /**
    * Get the index of an EnumTable in the sEnumTableArray.
    * If the EnumTable is not in the sEnumTableArray, it is added.
    *
    * @param aTable   the EnumTable to get the index of.
@@ -423,17 +401,22 @@ private:
   void SetSVGType(ValueType aType, const void* aValue,
                   const nsAString* aSerialized);
   inline void ResetIfSet();
 
   inline void* GetPtr() const;
   inline MiscContainer* GetMiscContainer() const;
   inline int32_t GetIntInternal() const;
 
-  bool EnsureEmptyMiscContainer();
+  // Clears the current MiscContainer.  This will return null if there is no
+  // existing container.
+  MiscContainer* ClearMiscContainer();
+  // Like ClearMiscContainer, except allocates a new container if one does not
+  // exist already.
+  MiscContainer* EnsureEmptyMiscContainer();
   bool EnsureEmptyAtomArray();
   nsStringBuffer* GetStringBuffer(const nsAString& aValue) const;
   // aStrict is set true if stringifying the return value equals with
   // aValue.
   int32_t StringToInteger(const nsAString& aValue,
                           bool* aStrict,
                           nsresult* aErrorCode,
                           bool aCanBePercent = false,
@@ -443,166 +426,43 @@ private:
   int32_t EnumTableEntryToValue(const EnumTable* aEnumTable,
                                 const EnumTable* aTableEntry);  
 
   static nsTArray<const EnumTable*, nsTArrayDefaultAllocator>* sEnumTableArray;
 
   PtrBits mBits;
 };
 
-/**
- * Implementation of inline methods
- */
-
 inline const nsAttrValue&
 nsAttrValue::operator=(const nsAttrValue& aOther)
 {
   SetTo(aOther);
   return *this;
 }
 
 inline nsIAtom*
 nsAttrValue::GetAtomValue() const
 {
   NS_PRECONDITION(Type() == eAtom, "wrong type");
   return reinterpret_cast<nsIAtom*>(GetPtr());
 }
 
-inline int32_t
-nsAttrValue::GetIntegerValue() const
-{
-  NS_PRECONDITION(Type() == eInteger, "wrong type");
-  return (BaseType() == eIntegerBase)
-         ? GetIntInternal()
-         : GetMiscContainer()->mInteger;
-}
-
-inline int16_t
-nsAttrValue::GetEnumValue() const
-{
-  NS_PRECONDITION(Type() == eEnum, "wrong type");
-  // We don't need to worry about sign extension here since we're
-  // returning an int16_t which will cut away the top bits.
-  return static_cast<int16_t>((
-    (BaseType() == eIntegerBase)
-    ? static_cast<uint32_t>(GetIntInternal())
-    : GetMiscContainer()->mEnumValue)
-      >> NS_ATTRVALUE_ENUMTABLEINDEX_BITS);
-}
-
-inline float
-nsAttrValue::GetPercentValue() const
-{
-  NS_PRECONDITION(Type() == ePercent, "wrong type");
-  return ((BaseType() == eIntegerBase)
-          ? GetIntInternal()
-          : GetMiscContainer()->mPercent)
-            / 100.0f;
-}
-
-inline nsAttrValue::AtomArray*
-nsAttrValue::GetAtomArrayValue() const
-{
-  NS_PRECONDITION(Type() == eAtomArray, "wrong type");
-  return GetMiscContainer()->mAtomArray;
-}
-
-inline mozilla::css::StyleRule*
-nsAttrValue::GetCSSStyleRuleValue() const
-{
-  NS_PRECONDITION(Type() == eCSSStyleRule, "wrong type");
-  return GetMiscContainer()->mCSSStyleRule;
-}
-
-inline mozilla::css::URLValue*
-nsAttrValue::GetURLValue() const
-{
-  NS_PRECONDITION(Type() == eURL, "wrong type");
-  return GetMiscContainer()->mURL;
-}
-
-inline mozilla::css::ImageValue*
-nsAttrValue::GetImageValue() const
-{
-  NS_PRECONDITION(Type() == eImage, "wrong type");
-  return GetMiscContainer()->mImage;
-}
-
-inline double
-nsAttrValue::GetDoubleValue() const
-{
-  NS_PRECONDITION(Type() == eDoubleValue, "wrong type");
-  return GetMiscContainer()->mDoubleValue;
-}
-
-inline bool
-nsAttrValue::GetIntMarginValue(nsIntMargin& aMargin) const
-{
-  NS_PRECONDITION(Type() == eIntMarginValue, "wrong type");
-  nsIntMargin* m = GetMiscContainer()->mIntMargin;
-  if (!m)
-    return false;
-  aMargin = *m;
-  return true;
-}
-
 inline nsAttrValue::ValueBaseType
 nsAttrValue::BaseType() const
 {
   return static_cast<ValueBaseType>(mBits & NS_ATTRVALUE_BASETYPE_MASK);
 }
 
-inline bool
-nsAttrValue::IsSVGType(ValueType aType) const
-{
-  return aType >= eSVGTypesBegin && aType <= eSVGTypesEnd;
-}
-
-inline void
-nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType)
-{
-  NS_ASSERTION(!(NS_PTR_TO_INT32(aValue) & ~NS_ATTRVALUE_POINTERVALUE_MASK),
-               "pointer not properly aligned, this will crash");
-  mBits = reinterpret_cast<PtrBits>(aValue) | aType;
-}
-
-inline void
-nsAttrValue::ResetIfSet()
-{
-  if (mBits) {
-    Reset();
-  }
-}
-
 inline void*
 nsAttrValue::GetPtr() const
 {
   NS_ASSERTION(BaseType() != eIntegerBase,
                "getting pointer from non-pointer");
   return reinterpret_cast<void*>(mBits & NS_ATTRVALUE_POINTERVALUE_MASK);
 }
 
-inline nsAttrValue::MiscContainer*
-nsAttrValue::GetMiscContainer() const
-{
-  NS_ASSERTION(BaseType() == eOtherBase, "wrong type");
-  return static_cast<MiscContainer*>(GetPtr());
-}
-
-inline int32_t
-nsAttrValue::GetIntInternal() const
-{
-  NS_ASSERTION(BaseType() == eIntegerBase,
-               "getting integer from non-integer");
-  // Make sure we get a signed value.
-  // Lets hope the optimizer optimizes this into a shift. Unfortunatly signed
-  // bitshift right is implementaion dependant.
-  return static_cast<int32_t>(mBits & ~NS_ATTRVALUE_INTEGERTYPE_MASK) /
-         NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER;
-}
-
 inline bool
 nsAttrValue::IsEmptyString() const
 {
   return !mBits;
 }
 
 #endif
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsAttrValueInlines.h
@@ -0,0 +1,216 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsAttrValueInlines_h__
+#define nsAttrValueInlines_h__
+
+struct MiscContainer
+{
+  typedef nsAttrValue::ValueType ValueType;
+
+  ValueType mType;
+  // mStringBits points to either nsIAtom* or nsStringBuffer* and is used when
+  // mType isn't mCSSStyleRule.
+  // Note eStringBase and eAtomBase is used also to handle the type of
+  // mStringBits.
+  PtrBits mStringBits;
+  union {
+    struct {
+      union {
+        int32_t mInteger;
+        nscolor mColor;
+        uint32_t mEnumValue;
+        int32_t mPercent;
+        mozilla::css::StyleRule* mCSSStyleRule;
+        mozilla::css::URLValue* mURL;
+        mozilla::css::ImageValue* mImage;
+        nsAttrValue::AtomArray* mAtomArray;
+        nsIntMargin* mIntMargin;
+        const nsSVGAngle* mSVGAngle;
+        const nsSVGIntegerPair* mSVGIntegerPair;
+        const nsSVGLength2* mSVGLength;
+        const mozilla::SVGLengthList* mSVGLengthList;
+        const mozilla::SVGNumberList* mSVGNumberList;
+        const nsSVGNumberPair* mSVGNumberPair;
+        const mozilla::SVGPathData* mSVGPathData;
+        const mozilla::SVGPointList* mSVGPointList;
+        const mozilla::SVGAnimatedPreserveAspectRatio* mSVGPreserveAspectRatio;
+        const mozilla::SVGStringList* mSVGStringList;
+        const mozilla::SVGTransformList* mSVGTransformList;
+        const nsSVGViewBox* mSVGViewBox;
+      };
+      uint32_t mRefCount : 31;
+      uint32_t mCached : 1;
+    } mValue;
+    double mDoubleValue;
+  };
+
+  MiscContainer()
+    : mType(nsAttrValue::eColor),
+      mStringBits(0)
+  {
+    MOZ_COUNT_CTOR(MiscContainer);
+    mValue.mColor = 0;
+    mValue.mRefCount = 0;
+    mValue.mCached = 0;
+  }
+
+  ~MiscContainer()
+  {
+    if (IsRefCounted()) {
+      MOZ_ASSERT(mValue.mRefCount == 0);
+      MOZ_ASSERT(!mValue.mCached);
+    }
+    MOZ_COUNT_DTOR(MiscContainer);
+  }
+
+  bool GetString(nsDependentString& aString) const;
+
+  inline bool IsRefCounted() const
+  {
+    // Nothing stops us from refcounting (and sharing) other types of
+    // MiscContainer (except eDoubleValue types) but there's no compelling
+    // reason to 
+    return mType == nsAttrValue::eCSSStyleRule;
+  }
+
+  inline int32_t AddRef() {
+    MOZ_ASSERT(IsRefCounted());
+    return ++mValue.mRefCount;
+  }
+
+  inline int32_t Release() {
+    MOZ_ASSERT(IsRefCounted());
+    return --mValue.mRefCount;
+  }
+
+  void Cache();
+  void Evict();
+};
+
+
+/**
+ * Implementation of inline methods
+ */
+
+inline int32_t
+nsAttrValue::GetIntegerValue() const
+{
+  NS_PRECONDITION(Type() == eInteger, "wrong type");
+  return (BaseType() == eIntegerBase)
+         ? GetIntInternal()
+         : GetMiscContainer()->mValue.mInteger;
+}
+
+inline int16_t
+nsAttrValue::GetEnumValue() const
+{
+  NS_PRECONDITION(Type() == eEnum, "wrong type");
+  // We don't need to worry about sign extension here since we're
+  // returning an int16_t which will cut away the top bits.
+  return static_cast<int16_t>((
+    (BaseType() == eIntegerBase)
+    ? static_cast<uint32_t>(GetIntInternal())
+    : GetMiscContainer()->mValue.mEnumValue)
+      >> NS_ATTRVALUE_ENUMTABLEINDEX_BITS);
+}
+
+inline float
+nsAttrValue::GetPercentValue() const
+{
+  NS_PRECONDITION(Type() == ePercent, "wrong type");
+  return ((BaseType() == eIntegerBase)
+          ? GetIntInternal()
+          : GetMiscContainer()->mValue.mPercent)
+            / 100.0f;
+}
+
+inline nsAttrValue::AtomArray*
+nsAttrValue::GetAtomArrayValue() const
+{
+  NS_PRECONDITION(Type() == eAtomArray, "wrong type");
+  return GetMiscContainer()->mValue.mAtomArray;
+}
+
+inline mozilla::css::StyleRule*
+nsAttrValue::GetCSSStyleRuleValue() const
+{
+  NS_PRECONDITION(Type() == eCSSStyleRule, "wrong type");
+  return GetMiscContainer()->mValue.mCSSStyleRule;
+}
+
+inline mozilla::css::URLValue*
+nsAttrValue::GetURLValue() const
+{
+  NS_PRECONDITION(Type() == eURL, "wrong type");
+  return GetMiscContainer()->mValue.mURL;
+}
+
+inline mozilla::css::ImageValue*
+nsAttrValue::GetImageValue() const
+{
+  NS_PRECONDITION(Type() == eImage, "wrong type");
+  return GetMiscContainer()->mValue.mImage;
+}
+
+inline double
+nsAttrValue::GetDoubleValue() const
+{
+  NS_PRECONDITION(Type() == eDoubleValue, "wrong type");
+  return GetMiscContainer()->mDoubleValue;
+}
+
+inline bool
+nsAttrValue::GetIntMarginValue(nsIntMargin& aMargin) const
+{
+  NS_PRECONDITION(Type() == eIntMarginValue, "wrong type");
+  nsIntMargin* m = GetMiscContainer()->mValue.mIntMargin;
+  if (!m)
+    return false;
+  aMargin = *m;
+  return true;
+}
+
+inline bool
+nsAttrValue::IsSVGType(ValueType aType) const
+{
+  return aType >= eSVGTypesBegin && aType <= eSVGTypesEnd;
+}
+
+inline void
+nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType)
+{
+  NS_ASSERTION(!(NS_PTR_TO_INT32(aValue) & ~NS_ATTRVALUE_POINTERVALUE_MASK),
+               "pointer not properly aligned, this will crash");
+  mBits = reinterpret_cast<PtrBits>(aValue) | aType;
+}
+
+inline void
+nsAttrValue::ResetIfSet()
+{
+  if (mBits) {
+    Reset();
+  }
+}
+
+inline MiscContainer*
+nsAttrValue::GetMiscContainer() const
+{
+  NS_ASSERTION(BaseType() == eOtherBase, "wrong type");
+  return static_cast<MiscContainer*>(GetPtr());
+}
+
+inline int32_t
+nsAttrValue::GetIntInternal() const
+{
+  NS_ASSERTION(BaseType() == eIntegerBase,
+               "getting integer from non-integer");
+  // Make sure we get a signed value.
+  // Lets hope the optimizer optimizes this into a shift. Unfortunatly signed
+  // bitshift right is implementaion dependant.
+  return static_cast<int32_t>(mBits & ~NS_ATTRVALUE_INTEGERTYPE_MASK) /
+         NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER;
+}
+
+#endif
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -94,16 +94,17 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsXULPopupManager.h"
 #include "nsIPermissionManager.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsNullPrincipal.h"
 #include "nsIRunnable.h"
 #include "nsDOMJSUtils.h"
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValue.h"
+#include "nsAttrValueInlines.h"
 #include "nsReferencedElement.h"
 #include "nsIDragService.h"
 #include "nsIChannelEventSink.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIOfflineCacheUpdate.h"
 #include "nsCPrefetchService.h"
 #include "nsIChromeRegistry.h"
 #include "nsEventDispatcher.h"
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -49,16 +49,17 @@
 #include "nsDOMString.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsMutationEvent.h"
 #include "nsNodeUtils.h"
 #include "mozilla/dom/DirectionalityUtils.h"
 #include "nsDocument.h"
 #include "nsAttrValueOrString.h"
+#include "nsAttrValueInlines.h"
 #ifdef MOZ_XUL
 #include "nsXULElement.h"
 #endif /* MOZ_XUL */
 #include "nsFrameManager.h"
 #include "nsFrameSelection.h"
 #ifdef DEBUG
 #include "nsRange.h"
 #endif
--- a/content/base/src/nsStyledElement.cpp
+++ b/content/base/src/nsStyledElement.cpp
@@ -2,16 +2,17 @@
 /* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsStyledElement.h"
 #include "nsGkAtoms.h"
 #include "nsAttrValue.h"
+#include "nsAttrValueInlines.h"
 #include "nsGenericElement.h"
 #include "nsMutationEvent.h"
 #include "nsDOMCSSDeclaration.h"
 #include "nsDOMCSSAttrDeclaration.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIDocument.h"
 #include "mozilla/css/StyleRule.h"
 #include "nsCSSParser.h"
@@ -246,28 +247,15 @@ nsStyledElementNotElementCSSInlineStyle:
       nsAutoString styleType;
       doc->GetHeaderData(nsGkAtoms::headerContentStyleType, styleType);
       if (!styleType.IsEmpty()) {
         static const char textCssStr[] = "text/css";
         isCSS = (styleType.EqualsIgnoreCase(textCssStr, sizeof(textCssStr) - 1));
       }
     }
 
-    if (isCSS) {
-      css::Loader* cssLoader = doc->CSSLoader();
-      nsCSSParser cssParser(cssLoader);
-
-      nsCOMPtr<nsIURI> baseURI = GetBaseURI();
-
-      nsRefPtr<css::StyleRule> rule;
-      cssParser.ParseStyleAttribute(aValue, doc->GetDocumentURI(),
-                                    baseURI,
-                                    NodePrincipal(),
-                                    getter_AddRefs(rule));
-      if (rule) {
-        aResult.SetTo(rule, &aValue);
-        return;
-      }
+    if (isCSS && aResult.ParseStyleAttribute(aValue, this)) {
+      return;
     }
   }
 
   aResult.SetTo(aValue);
 }
--- a/content/html/content/src/nsFormSubmission.cpp
+++ b/content/html/content/src/nsFormSubmission.cpp
@@ -12,16 +12,17 @@
 #include "nsIForm.h"
 #include "nsILinkHandler.h"
 #include "nsIDocument.h"
 #include "nsGkAtoms.h"
 #include "nsIFormControl.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsError.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsISaveAsCharset.h"
 #include "nsIFile.h"
 #include "nsIDOMFile.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsStringStream.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsNetUtil.h"
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -3,16 +3,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/. */
 
 #include "mozilla/Util.h"
 
 #include "nscore.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsCOMPtr.h"
 #include "nsIAtom.h"
 #include "nsIContentViewer.h"
 #include "mozilla/css/StyleRule.h"
 #include "nsIDocument.h"
 #include "nsIDocumentEncoder.h"
 #include "nsIDOMHTMLBodyElement.h"
 #include "nsIDOMHTMLDocument.h"
--- a/content/html/content/src/nsHTMLBRElement.cpp
+++ b/content/html/content/src/nsHTMLBRElement.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "nsIDOMHTMLBRElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 #include "nsRuleData.h"
 
 using namespace mozilla;
 
 class nsHTMLBRElement : public nsGenericHTMLElement,
--- a/content/html/content/src/nsHTMLBodyElement.cpp
+++ b/content/html/content/src/nsHTMLBodyElement.cpp
@@ -4,29 +4,30 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "nscore.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMHTMLBodyElement.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIDocument.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsIMarkupDocumentViewer.h"
 #include "nsMappedAttributes.h"
 #include "nsRuleData.h"
 #include "nsIDocShell.h"
 #include "nsIEditorDocShell.h"
 #include "nsRuleWalker.h"
-#include "jsapi.h"
+#include "jspubtd.h"
 
 //----------------------------------------------------------------------
 
 using namespace mozilla;
 
 class nsHTMLBodyElement;
 
 class BodyRule: public nsIStyleRule {
--- a/content/html/content/src/nsHTMLButtonElement.cpp
+++ b/content/html/content/src/nsHTMLButtonElement.cpp
@@ -1,16 +1,18 @@
 /* -*- 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/. */
+
 #include "nsIDOMHTMLButtonElement.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsIPresShell.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsIFormControl.h"
 #include "nsIForm.h"
 #include "nsFormSubmission.h"
 #include "nsFormSubmissionConstants.h"
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -1,14 +1,15 @@
 /* -*- 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/. */
 
 #include "nsHTMLCanvasElement.h"
+#include "nsAttrValueInlines.h"
 
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "nsNetUtil.h"
 #include "prmem.h"
 #include "nsDOMFile.h"
 
 #include "nsICanvasRenderingContextInternal.h"
--- a/content/html/content/src/nsHTMLFontElement.cpp
+++ b/content/html/content/src/nsHTMLFontElement.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "nsCOMPtr.h"
 #include "nsIDOMHTMLFontElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsMappedAttributes.h"
 #include "nsRuleData.h"
 #include "nsAlgorithm.h"
 #include "nsContentUtils.h"
 
--- a/content/html/content/src/nsHTMLHRElement.cpp
+++ b/content/html/content/src/nsHTMLHRElement.cpp
@@ -8,16 +8,17 @@
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLHRElement.h"
 
 #include "nsIDOMEventTarget.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsMappedAttributes.h"
+#include "nsAttrValueInlines.h"
 #include "nsRuleData.h"
 #include "nsCSSProps.h"
 
 using namespace mozilla;
 
 class nsHTMLHRElement : public nsGenericHTMLElement,
                         public nsIDOMHTMLHRElement
 {
--- a/content/html/content/src/nsHTMLIFrameElement.cpp
+++ b/content/html/content/src/nsHTMLIFrameElement.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "nsHTMLIFrameElement.h"
 #include "nsIDOMSVGDocument.h"
 #include "nsMappedAttributes.h"
+#include "nsAttrValueInlines.h"
 #include "nsError.h"
 #include "nsRuleData.h"
 #include "nsStyleConsts.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(IFrame)
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -1,16 +1,17 @@
 /* -*- 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/. */
 
 #include "mozilla/Util.h"
 
 #include "nsHTMLInputElement.h"
+#include "nsAttrValueInlines.h"
 
 #include "nsIDOMHTMLInputElement.h"
 #include "nsITextControlElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIRadioVisitor.h"
 #include "nsIPhonetic.h"
 
 #include "nsIControllers.h"
--- a/content/html/content/src/nsHTMLLIElement.cpp
+++ b/content/html/content/src/nsHTMLLIElement.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "nsIDOMHTMLLIElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 #include "nsRuleData.h"
 
 using namespace mozilla;
 
 class nsHTMLLIElement : public nsGenericHTMLElement,
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/Util.h"
 
 #include "base/basictypes.h"
 #include "nsIDOMHTMLMediaElement.h"
 #include "nsIDOMHTMLSourceElement.h"
 #include "nsHTMLMediaElement.h"
 #include "nsTimeRanges.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsGkAtoms.h"
 #include "nsSize.h"
 #include "nsIFrame.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsError.h"
--- a/content/html/content/src/nsHTMLMenuElement.cpp
+++ b/content/html/content/src/nsHTMLMenuElement.cpp
@@ -1,15 +1,15 @@
 /* -*- 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/. */
 
 #include "nsHTMLMenuElement.h"
-
+#include "nsAttrValueInlines.h"
 #include "nsIDOMHTMLMenuItemElement.h"
 #include "nsXULContextMenuBuilder.h"
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "nsHTMLMenuItemElement.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
 
--- a/content/html/content/src/nsHTMLMenuItemElement.cpp
+++ b/content/html/content/src/nsHTMLMenuItemElement.cpp
@@ -1,16 +1,17 @@
 /* -*- 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/. */
 
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "nsHTMLMenuItemElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsContentUtils.h"
 
 using namespace mozilla::dom;
 
 // First bits are needed for the menuitem type.
 #define NS_CHECKED_IS_TOGGLED (1 << 2)
 #define NS_ORIGINAL_CHECKED_VALUE (1 << 3)
 #define NS_MENUITEM_TYPE(bits) ((bits) & ~( \
--- a/content/html/content/src/nsHTMLMeterElement.cpp
+++ b/content/html/content/src/nsHTMLMeterElement.cpp
@@ -1,16 +1,17 @@
 /* -*- 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/. */
 
 #include "nsIDOMHTMLMeterElement.h"
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValue.h"
+#include "nsAttrValueInlines.h"
 #include "nsEventStateManager.h"
 #include "nsAlgorithm.h"
 
 
 class nsHTMLMeterElement : public nsGenericHTMLElement,
                            public nsIDOMHTMLMeterElement
 {
 public:
--- a/content/html/content/src/nsHTMLOListElement.cpp
+++ b/content/html/content/src/nsHTMLOListElement.cpp
@@ -5,16 +5,17 @@
 
 #include "mozilla/Util.h"
 
 #include "nsIDOMHTMLOListElement.h"
 #include "nsIDOMHTMLDListElement.h"
 #include "nsIDOMHTMLUListElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 #include "nsRuleData.h"
 
 using namespace mozilla;
 
 class nsHTMLSharedListElement : public nsGenericHTMLElement,
--- a/content/html/content/src/nsHTMLObjectElement.cpp
+++ b/content/html/content/src/nsHTMLObjectElement.cpp
@@ -3,16 +3,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/. */
 
 #include "mozilla/Util.h"
 
 #include "nsAutoPtr.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsObjectLoadingContent.h"
 #include "nsGkAtoms.h"
 #include "nsError.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMSVGDocument.h"
 #include "nsIDOMGetSVGDocument.h"
 #include "nsIDOMHTMLObjectElement.h"
--- a/content/html/content/src/nsHTMLPreElement.cpp
+++ b/content/html/content/src/nsHTMLPreElement.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "nsIDOMHTMLPreElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 #include "nsRuleData.h"
 
 using namespace mozilla;
 
 class nsHTMLPreElement : public nsGenericHTMLElement,
--- a/content/html/content/src/nsHTMLProgressElement.cpp
+++ b/content/html/content/src/nsHTMLProgressElement.cpp
@@ -1,16 +1,17 @@
 /* -*- 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/. */
 
 #include "nsIDOMHTMLProgressElement.h"
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValue.h"
+#include "nsAttrValueInlines.h"
 #include "nsEventStateManager.h"
 
 
 class nsHTMLProgressElement : public nsGenericHTMLElement,
                               public nsIDOMHTMLProgressElement
 {
 public:
   nsHTMLProgressElement(already_AddRefed<nsINodeInfo> aNodeInfo);
--- a/content/html/content/src/nsHTMLSharedElement.cpp
+++ b/content/html/content/src/nsHTMLSharedElement.cpp
@@ -7,16 +7,17 @@
 
 #include "nsIDOMHTMLParamElement.h"
 #include "nsIDOMHTMLBaseElement.h"
 #include "nsIDOMHTMLDirectoryElement.h"
 #include "nsIDOMHTMLQuoteElement.h"
 #include "nsIDOMHTMLHeadElement.h"
 #include "nsIDOMHTMLHtmlElement.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsRuleData.h"
 #include "nsMappedAttributes.h"
 #include "nsContentUtils.h"
 
 using namespace mozilla;
--- a/content/html/content/src/nsHTMLTableCaptionElement.cpp
+++ b/content/html/content/src/nsHTMLTableCaptionElement.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "nsIDOMHTMLTableCaptionElem.h"
 #include "nsIDOMEventTarget.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 #include "nsRuleData.h"
 
 using namespace mozilla;
 
 class nsHTMLTableCaptionElement :  public nsGenericHTMLElement,
--- a/content/html/content/src/nsHTMLTableCellElement.cpp
+++ b/content/html/content/src/nsHTMLTableCellElement.cpp
@@ -7,16 +7,17 @@
 
 #include "nsIDOMHTMLTableCellElement.h"
 #include "nsIDOMHTMLTableRowElement.h"
 #include "nsHTMLTableElement.h"
 #include "nsIDOMHTMLCollection.h"
 #include "nsIDOMEventTarget.h"
 #include "nsMappedAttributes.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsRuleData.h"
 #include "nsRuleWalker.h"
 #include "celldata.h"
 
 using namespace mozilla;
--- a/content/html/content/src/nsHTMLTableColElement.cpp
+++ b/content/html/content/src/nsHTMLTableColElement.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "nsIDOMHTMLTableColElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsMappedAttributes.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsRuleData.h"
 
 using namespace mozilla;
 
 // use the same protection as ancient code did 
 // http://lxr.mozilla.org/classic/source/lib/layout/laytable.c#46
--- a/content/html/content/src/nsHTMLTableElement.cpp
+++ b/content/html/content/src/nsHTMLTableElement.cpp
@@ -8,16 +8,17 @@
 #include "nsHTMLTableElement.h"
 #include "nsIDOMHTMLTableCaptionElem.h"
 #include "nsIDOMHTMLTableSectionElem.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMEventTarget.h"
 #include "nsError.h"
 #include "nsContentList.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsHTMLParts.h"
 #include "nsRuleData.h"
 #include "nsStyleContext.h"
 #include "nsIDocument.h"
 #include "nsContentUtils.h"
--- a/content/html/content/src/nsHTMLTableRowElement.cpp
+++ b/content/html/content/src/nsHTMLTableRowElement.cpp
@@ -8,16 +8,17 @@
 #include "nsIDOMHTMLTableRowElement.h"
 #include "nsIDOMHTMLTableElement.h"
 #include "nsIDOMHTMLTableSectionElem.h"
 #include "nsIDOMHTMLTableCellElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsError.h"
 #include "nsMappedAttributes.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsContentList.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsHTMLParts.h"
 #include "nsRuleData.h"
 #include "nsContentUtils.h"
 
 using namespace mozilla;
--- a/content/html/content/src/nsHTMLTableSectionElement.cpp
+++ b/content/html/content/src/nsHTMLTableSectionElement.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "nsIDOMHTMLTableSectionElem.h"
 #include "nsIDOMEventTarget.h"
 #include "nsMappedAttributes.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsHTMLParts.h"
 #include "nsStyleConsts.h"
 #include "nsContentList.h"
 #include "nsRuleData.h"
 #include "nsError.h"
 #include "nsContentUtils.h"
 
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -16,16 +16,17 @@
 #include "nsCOMPtr.h"
 #include "nsIComponentManager.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIFormControl.h"
 #include "nsIForm.h"
 #include "nsFormSubmission.h"
 #include "nsIDOMEventTarget.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsMappedAttributes.h"
 #include "nsIFormControlFrame.h"
 #include "nsITextControlFrame.h"
 #include "nsEventStates.h"
 #include "nsLinebreakConverter.h"
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -19,16 +19,17 @@
 #include "nsContentCreatorFunctions.h"
 #include "nsTextControlFrame.h"
 #include "nsIControllers.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsITransactionManager.h"
 #include "nsIControllerContext.h"
 #include "nsAttrValue.h"
+#include "nsAttrValueInlines.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMEventListener.h"
 #include "EditActionListener.h"
 #include "nsINativeKeyBindings.h"
 #include "nsIDocumentEncoder.h"
 #include "nsISelectionPrivate.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
--- a/content/smil/nsSMILAnimationFunction.cpp
+++ b/content/smil/nsSMILAnimationFunction.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsSMILAnimationFunction.h"
 #include "nsISMILAttr.h"
 #include "nsSMILParserUtils.h"
 #include "nsSMILNullType.h"
 #include "nsISMILAnimationElement.h"
 #include "nsSMILTimedElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 #include "nsIContent.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
--- a/content/smil/nsSMILTimedElement.cpp
+++ b/content/smil/nsSMILTimedElement.cpp
@@ -1,14 +1,15 @@
 /* -*- 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/. */
 
 #include "nsSMILTimedElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsSMILAnimationFunction.h"
 #include "nsSMILTimeValue.h"
 #include "nsSMILTimeValueSpec.h"
 #include "nsSMILInstanceTime.h"
 #include "nsSMILParserUtils.h"
 #include "nsSMILTimeContainer.h"
 #include "nsGkAtoms.h"
 #include "nsGUIEvent.h"
--- a/content/svg/content/src/DOMSVGTransform.cpp
+++ b/content/svg/content/src/DOMSVGTransform.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DOMSVGTransform.h"
 #include "DOMSVGMatrix.h"
 #include "SVGAnimatedTransformList.h"
 #include "nsError.h"
 #include <math.h>
 #include "nsContentUtils.h"
+#include "nsAttrValueInlines.h"
 
 namespace mozilla {
 
 //----------------------------------------------------------------------
 // nsISupports methods:
 
 // We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
 // clear our list's weak ref to us to be safe. (The other option would be to
--- a/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
+++ b/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsSMILValue.h"
 #include "SMILEnumType.h"
+#include "nsAttrValueInlines.h"
 
 using namespace mozilla;
 
 ////////////////////////////////////////////////////////////////////////
 // SVGAnimatedPreserveAspectRatio class
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(
   SVGAnimatedPreserveAspectRatio::DOMBaseVal, mSVGElement)
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
@@ -7,16 +7,17 @@
 #include "nsISMILAnimationElement.h"
 #include "nsSMILParserUtils.h"
 #include "nsSVGAngle.h"
 #include "SVGMotionSMILType.h"
 #include "SVGMotionSMILPathUtils.h"
 #include "nsSVGPathDataParser.h"
 #include "nsSVGPathElement.h" // for nsSVGPathList
 #include "nsSVGMpathElement.h"
+#include "nsAttrValueInlines.h"
 
 namespace mozilla {
 
 SVGMotionSMILAnimationFunction::SVGMotionSMILAnimationFunction()
   : mRotateType(eRotateType_Explicit),
     mRotateAngle(0.0f),
     mPathSourceType(ePathSourceType_None),
     mIsPathStale(true)  // Try to initialize path on first GetValues call
--- a/content/svg/content/src/nsSVGAngle.cpp
+++ b/content/svg/content/src/nsSVGAngle.cpp
@@ -8,16 +8,17 @@
 #include "nsSVGAngle.h"
 #include "prdtoa.h"
 #include "nsTextFormatter.h"
 #include "nsSVGMarkerElement.h"
 #include "nsMathUtils.h"
 #include "nsContentUtils.h" // NS_ENSURE_FINITE
 #include "nsSMILValue.h"
 #include "SVGOrientSMILType.h"
+#include "nsAttrValueInlines.h"
 #include "mozilla/Attributes.h"
 
 using namespace mozilla;
 
 /**
  * Mutable SVGAngle class for SVGSVGElement.createSVGAngle().
  *
  * Note that this class holds its own nsSVGAngle, which therefore can't be
--- a/content/svg/content/src/nsSVGLength2.cpp
+++ b/content/svg/content/src/nsSVGLength2.cpp
@@ -10,16 +10,17 @@
 #include "nsTextFormatter.h"
 #include "nsSVGSVGElement.h"
 #include "nsIFrame.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsSVGAttrTearoffTable.h"
 #include "nsContentUtils.h" // NS_ENSURE_FINITE
 #include "nsSMILValue.h"
 #include "nsSMILFloatType.h"
+#include "nsAttrValueInlines.h"
 
 using namespace mozilla;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGLength2::DOMBaseVal, mSVGElement)
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGLength2::DOMAnimVal, mSVGElement)
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGLength2::DOMAnimatedLength, mSVGElement)
--- a/content/svg/content/src/nsSVGViewBox.cpp
+++ b/content/svg/content/src/nsSVGViewBox.cpp
@@ -6,16 +6,17 @@
 #include "nsSVGViewBox.h"
 #include "prdtoa.h"
 #include "nsTextFormatter.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsMathUtils.h"
 #include "nsSMILValue.h"
 #include "SVGContentUtils.h"
 #include "SVGViewBoxSMILType.h"
+#include "nsAttrValueInlines.h"
 
 #define NUM_VIEWBOX_COMPONENTS 4
 using namespace mozilla;
 
 /* Implementation of nsSVGViewBoxRect methods */
 
 bool
 nsSVGViewBoxRect::operator==(const nsSVGViewBoxRect& aOther) const
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -82,16 +82,17 @@
 #include "nsGkAtoms.h"
 #include "nsXULContentUtils.h"
 #include "nsNodeUtils.h"
 #include "nsFrameLoader.h"
 #include "prlog.h"
 #include "rdf.h"
 #include "nsIControllers.h"
 #include "nsAttrValueOrString.h"
+#include "nsAttrValueInlines.h"
 #include "mozilla/Attributes.h"
 
 // The XUL doc interface
 #include "nsIDOMXULDocument.h"
 
 #include "nsReadableUtils.h"
 #include "nsIFrame.h"
 #include "nsNodeInfoManager.h"
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -19,17 +19,16 @@
 #include "nsIDOMXULElement.h"
 #include "nsIDOMHTMLFrameElement.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLMapElement.h"
 #include "nsIDOMHTMLLegendElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMRange.h"
 #include "nsIHTMLDocument.h"
-#include "nsGenericHTMLElement.h"
 #include "nsIDocShell.h"
 #include "nsIEditorDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsLayoutUtils.h"
 #include "nsIPresShell.h"
 #include "nsIContentViewer.h"
 #include "nsFrameIterator.h"
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -1,17 +1,16 @@
 # 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/.
 
 DEPTH            = @DEPTH@
 topsrcdir        = @top_srcdir@
 srcdir           = @srcdir@
 VPATH            = @srcdir@
-FAIL_ON_WARNINGS := 1
 
 MODULE           = dom
 LIBRARY_NAME     = dombindings_s
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 EXPORT_LIBRARY   = 1
 
 include $(topsrcdir)/config/config.mk
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -470,29 +470,27 @@ public:
     , mError(aError) {}
   ~GetUserMediaDevicesRunnable() {}
 
   NS_IMETHOD
   Run()
   {
     NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
 
-    uint32_t audioCount, videoCount, total, i;
+    uint32_t audioCount, videoCount, i;
     MediaManager* manager = MediaManager::Get();
 
     nsTArray<nsRefPtr<MediaEngineVideoSource> > videoSources;
     manager->GetBackend()->EnumerateVideoDevices(&videoSources);
     videoCount = videoSources.Length();
 
     nsTArray<nsRefPtr<MediaEngineAudioSource> > audioSources;
     manager->GetBackend()->EnumerateAudioDevices(&audioSources);
     audioCount = videoSources.Length();
 
-    total = videoCount + audioCount;
-
     nsTArray<nsCOMPtr<nsIMediaDevice> > *devices =
       new nsTArray<nsCOMPtr<nsIMediaDevice> >;
 
     for (i = 0; i < videoCount; i++) {
       devices->AppendElement(new MediaDevice(videoSources[i]));
     }
     for (i = 0; i < audioCount; i++) {
       devices->AppendElement(new MediaDevice(audioSources[i]));
--- a/layout/forms/nsLegendFrame.cpp
+++ b/layout/forms/nsLegendFrame.cpp
@@ -2,16 +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/. */
 
 #include "nsLegendFrame.h"
 #include "nsIContent.h"
 #include "nsIAtom.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsHTMLParts.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsFormControlFrame.h"
 
 nsIFrame*
 NS_NewLegendFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -65,16 +65,17 @@
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsINativeKeyBindings.h"
 #include "nsIJSContextStack.h"
 #include "nsFocusManager.h"
 #include "nsTextEditRules.h"
 #include "nsPresState.h"
 #include "nsContentList.h"
+#include "nsAttrValueInlines.h"
 
 #include "mozilla/Selection.h"
 
 #define DEFAULT_COLUMN_WIDTH 20
 
 using namespace mozilla;
 
 nsIFrame*
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -23,16 +23,17 @@
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsStyleContext.h"
 #include "nsIView.h"
 #include "nsHTMLParts.h"
 #include "nsGkAtoms.h"
 #include "nsIDOMEvent.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "prprf.h"
 #include "nsStyleChangeList.h"
 #include "nsFrameSelection.h"
 #include "nsFloatManager.h"
 #include "nsIntervalSet.h"
 #include "prenv.h"
 #include "plstr.h"
 #include "nsGUIEvent.h"
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -6,16 +6,17 @@
 /* rendering object for list-item bullets */
 
 #include "nsCOMPtr.h"
 #include "nsBulletFrame.h"
 #include "nsGkAtoms.h"
 #include "nsHTMLParts.h"
 #include "nsContainerFrame.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIDocument.h"
 #include "nsRenderingContext.h"
 #include "nsILoadGroup.h"
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 #include "prprf.h"
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -3,16 +3,17 @@
  * 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/. */
 
 /* rendering object for HTML <frameset> elements */
 
 #include "nsCOMPtr.h"
 #include "nsFrameSetFrame.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsLeafFrame.h"
 #include "nsContainerFrame.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIComponentManager.h"
 #include "nsIStreamListener.h"
 #include "nsIURL.h"
 #include "nsIDocument.h"
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -8,16 +8,17 @@
  * as <frame>, <iframe>, and some <object>s
  */
 
 #include "mozilla/layout/RenderFrameParent.h"
 
 #include "nsSubDocumentFrame.h"
 #include "nsCOMPtr.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellLoadInfo.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIBaseWindow.h"
 #include "nsIContentViewer.h"
 #include "nsPresContext.h"
--- a/layout/style/Rule.h
+++ b/layout/style/Rule.h
@@ -11,32 +11,33 @@
 #include "nsIStyleRule.h"
 #include "nsIDOMCSSRule.h"
 #include "nsCSSStyleSheet.h"
 
 class nsIStyleSheet;
 class nsIDocument;
 struct nsRuleData;
 template<class T> struct already_AddRefed;
+class nsHTMLCSSStyleSheet;
 
 namespace mozilla {
 namespace css {
 class GroupRule;
 
 #define DECL_STYLE_RULE_INHERIT_NO_DOMRULE  \
 virtual void MapRuleInfoInto(nsRuleData* aRuleData);
 
 #define DECL_STYLE_RULE_INHERIT  \
 DECL_STYLE_RULE_INHERIT_NO_DOMRULE \
 virtual nsIDOMCSSRule* GetDOMRule();
 
 class Rule : public nsIStyleRule {
 protected:
   Rule()
-    : mSheet(nullptr),
+    : mSheet(0),
       mParentRule(nullptr)
   {
   }
 
   Rule(const Rule& aCopy)
     : mSheet(aCopy.mSheet),
       mParentRule(aCopy.mParentRule)
   {
@@ -70,26 +71,30 @@ public:
     KEYFRAME_RULE,
     KEYFRAMES_RULE,
     DOCUMENT_RULE,
     SUPPORTS_RULE
   };
 
   virtual int32_t GetType() const = 0;
 
-  nsCSSStyleSheet* GetStyleSheet() const { return mSheet; }
+  nsCSSStyleSheet* GetStyleSheet() const;
+  nsHTMLCSSStyleSheet* GetHTMLCSSStyleSheet() const;
 
   // Return the document the rule lives in, if any
   nsIDocument* GetDocument() const
   {
     nsCSSStyleSheet* sheet = GetStyleSheet();
     return sheet ? sheet->GetDocument() : nullptr;
   }
 
   virtual void SetStyleSheet(nsCSSStyleSheet* aSheet);
+  // This does not need to be virtual, because GroupRule and MediaRule are not
+  // used for inline style.
+  void SetHTMLCSSStyleSheet(nsHTMLCSSStyleSheet* aSheet);
 
   void SetParentRule(GroupRule* aRule) {
     // We don't reference count this up reference. The group rule
     // will tell us when it's going away or when we're detached from
     // it.
     mParentRule = aRule;
   }
 
@@ -112,16 +117,18 @@ public:
     SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const = 0;
 
   // This is used to measure nsCOMArray<Rule>s.
   static size_t SizeOfCOMArrayElementIncludingThis(css::Rule* aElement,
                                                    nsMallocSizeOfFun aMallocSizeOf,
                                                    void* aData);
 
 protected:
-  nsCSSStyleSheet*  mSheet;
+  // This is either an nsCSSStyleSheet* or a nsHTMLStyleSheet*.  The former
+  // if the low bit is 0, the latter if the low bit is 1.
+  uintptr_t         mSheet;
   GroupRule*        mParentRule;
 };
 
 } // namespace css
 } // namespace mozilla
 
 #endif /* mozilla_css_Rule_h___ */
--- a/layout/style/StyleRule.cpp
+++ b/layout/style/StyleRule.cpp
@@ -1389,17 +1389,17 @@ StyleRule::Clone() const
 {
   nsRefPtr<Rule> clone = new StyleRule(*this);
   return clone.forget();
 }
 
 /* virtual */ nsIDOMCSSRule*
 StyleRule::GetDOMRule()
 {
-  if (!mSheet) {
+  if (!GetStyleSheet()) {
     // inline style rules aren't supposed to have a DOM rule object, only
     // a declaration.
     return nullptr;
   }
   if (!mDOMRule) {
     mDOMRule = new DOMCSSStyleRule(this);
     NS_ADDREF(mDOMRule);
   }
@@ -1413,24 +1413,25 @@ StyleRule::DeclarationChanged(Declaratio
   StyleRule* clone = new StyleRule(*this, aDecl);
   if (!clone) {
     return nullptr;
   }
 
   NS_ADDREF(clone); // for return
 
   if (aHandleContainer) {
+    nsCSSStyleSheet* sheet = GetStyleSheet();
     if (mParentRule) {
-      if (mSheet) {
-        mSheet->ReplaceRuleInGroup(mParentRule, this, clone);
+      if (sheet) {
+        sheet->ReplaceRuleInGroup(mParentRule, this, clone);
       } else {
         mParentRule->ReplaceStyleRule(this, clone);
       }
-    } else if (mSheet) {
-      mSheet->ReplaceStyleRule(this, clone);
+    } else if (sheet) {
+      sheet->ReplaceStyleRule(this, clone);
     }
   }
 
   return clone;
 }
 
 /* virtual */ void
 StyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
@@ -1444,17 +1445,17 @@ StyleRule::MapRuleInfoInto(nsRuleData* a
 /* virtual */ void
 StyleRule::List(FILE* out, int32_t aIndent) const
 {
   // Indent
   for (int32_t index = aIndent; --index >= 0; ) fputs("  ", out);
 
   nsAutoString buffer;
   if (mSelector)
-    mSelector->ToString(buffer, mSheet);
+    mSelector->ToString(buffer, GetStyleSheet());
 
   buffer.AppendLiteral(" ");
   fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
   if (nullptr != mDeclaration) {
     mDeclaration->List(out);
   }
   else {
     fputs("{ null declaration }", out);
@@ -1462,17 +1463,17 @@ StyleRule::List(FILE* out, int32_t aInde
   fputs("\n", out);
 }
 #endif
 
 void
 StyleRule::GetCssText(nsAString& aCssText)
 {
   if (mSelector) {
-    mSelector->ToString(aCssText, mSheet);
+    mSelector->ToString(aCssText, GetStyleSheet());
     aCssText.Append(PRUnichar(' '));
   }
   aCssText.Append(PRUnichar('{'));
   aCssText.Append(PRUnichar(' '));
   if (mDeclaration)
   {
     nsAutoString   tempString;
     mDeclaration->ToString( tempString );
@@ -1487,17 +1488,17 @@ StyleRule::SetCssText(const nsAString& a
 {
   // XXX TBI - need to re-parse rule & declaration
 }
 
 void
 StyleRule::GetSelectorText(nsAString& aSelectorText)
 {
   if (mSelector)
-    mSelector->ToString(aSelectorText, mSheet);
+    mSelector->ToString(aSelectorText, GetStyleSheet());
   else
     aSelectorText.Truncate();
 }
 
 void
 StyleRule::SetSelectorText(const nsAString& aSelectorText)
 {
   // XXX TBI - get a parser and re-parse the selectors,
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -37,16 +37,17 @@
 #include "nsCSSPseudoClasses.h"
 #include "nsCSSPseudoElements.h"
 #include "nsIContent.h"
 #include "nsCOMPtr.h"
 #include "nsHashKeys.h"
 #include "nsStyleUtil.h"
 #include "nsQuickSort.h"
 #include "nsAttrValue.h"
+#include "nsAttrValueInlines.h"
 #include "nsAttrName.h"
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
 #include "nsContentUtils.h"
 #include "nsIMediaList.h"
 #include "nsCSSRules.h"
 #include "nsIPrincipal.h"
 #include "nsStyleSet.h"
--- a/layout/style/nsCSSRules.cpp
+++ b/layout/style/nsCSSRules.cpp
@@ -53,23 +53,53 @@ IMPL_STYLE_RULE_INHERIT_MAP_RULE_INFO_IN
 // base class for all rule types in a CSS style sheet
 
 namespace mozilla {
 namespace css {
 
 NS_IMPL_ADDREF(Rule)
 NS_IMPL_RELEASE(Rule)
 
+nsCSSStyleSheet*
+Rule::GetStyleSheet() const
+{
+  if (!(mSheet & 0x1)) {
+    return reinterpret_cast<nsCSSStyleSheet*>(mSheet);
+  }
+
+  return nullptr;
+}
+
+nsHTMLCSSStyleSheet*
+Rule::GetHTMLCSSStyleSheet() const
+{
+  if (mSheet & 0x1) {
+    return reinterpret_cast<nsHTMLCSSStyleSheet*>(mSheet & ~uintptr_t(0x1));
+  }
+
+  return nullptr;
+}
+
 /* virtual */ void
 Rule::SetStyleSheet(nsCSSStyleSheet* aSheet)
 {
   // We don't reference count this up reference. The style sheet
   // will tell us when it's going away or when we're detached from
   // it.
-  mSheet = aSheet;
+  mSheet = reinterpret_cast<uintptr_t>(aSheet);
+}
+
+void
+Rule::SetHTMLCSSStyleSheet(nsHTMLCSSStyleSheet* aSheet)
+{
+  // We don't reference count this up reference. The style sheet
+  // will tell us when it's going away or when we're detached from
+  // it.
+  mSheet = reinterpret_cast<uintptr_t>(aSheet);
+  mSheet |= 0x1;
 }
 
 nsresult
 Rule::GetParentRule(nsIDOMCSSRule** aParentRule)
 {
   if (mParentRule) {
     NS_IF_ADDREF(*aParentRule = mParentRule->GetDOMRule());
   } else {
@@ -78,17 +108,17 @@ Rule::GetParentRule(nsIDOMCSSRule** aPar
   return NS_OK;
 }
 
 nsresult
 Rule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
 {
   NS_ENSURE_ARG_POINTER(aSheet);
 
-  NS_IF_ADDREF(*aSheet = mSheet);
+  NS_IF_ADDREF(*aSheet = GetStyleSheet());
   return NS_OK;
 }
 
 size_t
 Rule::SizeOfCOMArrayElementIncludingThis(css::Rule* aElement,
                                          nsMallocSizeOfFun aMallocSizeOf,
                                          void* aData)
 {
@@ -566,20 +596,21 @@ GroupRule::List(FILE* out, int32_t aInde
   fputs("}\n", out);
 }
 #endif
 
 void
 GroupRule::AppendStyleRule(Rule* aRule)
 {
   mRules.AppendObject(aRule);
-  aRule->SetStyleSheet(mSheet);
+  nsCSSStyleSheet* sheet = GetStyleSheet();
+  aRule->SetStyleSheet(sheet);
   aRule->SetParentRule(this);
-  if (mSheet) {
-    mSheet->SetModifiedByChildRule();
+  if (sheet) {
+    sheet->SetModifiedByChildRule();
   }
 }
 
 Rule*
 GroupRule::GetStyleRuleAt(int32_t aIndex) const
 {
   return mRules.SafeObjectAt(aIndex);
 }
@@ -607,31 +638,31 @@ GroupRule::DeleteStyleRuleAt(uint32_t aI
   }
   return mRules.RemoveObjectAt(aIndex) ? NS_OK : NS_ERROR_ILLEGAL_VALUE;
 }
 
 nsresult
 GroupRule::InsertStyleRulesAt(uint32_t aIndex,
                               nsCOMArray<Rule>& aRules)
 {
-  aRules.EnumerateForwards(SetStyleSheetReference, mSheet);
+  aRules.EnumerateForwards(SetStyleSheetReference, GetStyleSheet());
   aRules.EnumerateForwards(SetParentRuleReference, this);
   if (! mRules.InsertObjectsAt(aRules, aIndex)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 nsresult
 GroupRule::ReplaceStyleRule(Rule* aOld, Rule* aNew)
 {
   int32_t index = mRules.IndexOf(aOld);
   NS_ENSURE_TRUE(index != -1, NS_ERROR_UNEXPECTED);
   mRules.ReplaceObjectAt(aNew, index);
-  aNew->SetStyleSheet(mSheet);
+  aNew->SetStyleSheet(GetStyleSheet());
   aNew->SetParentRule(this);
   aOld->SetStyleSheet(nullptr);
   aOld->SetParentRule(nullptr);
   return NS_OK;
 }
 
 nsresult
 GroupRule::AppendRulesToCssText(nsAString& aCssText)
@@ -666,39 +697,41 @@ GroupRule::GetCssRules(nsIDOMCSSRuleList
 
   NS_ADDREF(*aRuleList = mRuleCollection);
   return NS_OK;
 }
 
 nsresult
 GroupRule::InsertRule(const nsAString & aRule, uint32_t aIndex, uint32_t* _retval)
 {
-  NS_ENSURE_TRUE(mSheet, NS_ERROR_FAILURE);
+  nsCSSStyleSheet* sheet = GetStyleSheet();
+  NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
   
   if (aIndex > uint32_t(mRules.Count()))
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
 
   NS_ASSERTION(uint32_t(mRules.Count()) <= INT32_MAX,
                "Too many style rules!");
 
-  return mSheet->InsertRuleIntoGroup(aRule, this, aIndex, _retval);
+  return sheet->InsertRuleIntoGroup(aRule, this, aIndex, _retval);
 }
 
 nsresult
 GroupRule::DeleteRule(uint32_t aIndex)
 {
-  NS_ENSURE_TRUE(mSheet, NS_ERROR_FAILURE);
+  nsCSSStyleSheet* sheet = GetStyleSheet();
+  NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
 
   if (aIndex >= uint32_t(mRules.Count()))
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
 
   NS_ASSERTION(uint32_t(mRules.Count()) <= INT32_MAX,
                "Too many style rules!");
 
-  return mSheet->DeleteRuleFromGroup(this, aIndex);
+  return sheet->DeleteRuleFromGroup(this, aIndex);
 }
 
 /* virtual */ size_t
 GroupRule::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
 {
   return mRules.SizeOfExcludingThis(Rule::SizeOfCOMArrayElementIncludingThis,
                                     aMallocSizeOf);
 
@@ -717,17 +750,17 @@ MediaRule::MediaRule()
 
 MediaRule::MediaRule(const MediaRule& aCopy)
   : GroupRule(aCopy)
 {
   if (aCopy.mMedia) {
     aCopy.mMedia->Clone(getter_AddRefs(mMedia));
     if (mMedia) {
       // XXXldb This doesn't really make sense.
-      mMedia->SetStyleSheet(aCopy.mSheet);
+      mMedia->SetStyleSheet(aCopy.GetStyleSheet());
     }
   }
 }
 
 MediaRule::~MediaRule()
 {
   if (mMedia) {
     mMedia->SetStyleSheet(nullptr);
@@ -791,17 +824,17 @@ MediaRule::Clone() const
   return clone.forget();
 }
 
 nsresult
 MediaRule::SetMedia(nsMediaList* aMedia)
 {
   mMedia = aMedia;
   if (aMedia)
-    mMedia->SetStyleSheet(mSheet);
+    mMedia->SetStyleSheet(GetStyleSheet());
   return NS_OK;
 }
 
 // nsIDOMCSSRule methods
 NS_IMETHODIMP
 MediaRule::GetType(uint16_t* aType)
 {
   *aType = nsIDOMCSSRule::MEDIA_RULE;
@@ -1995,18 +2028,19 @@ nsCSSKeyframeRule::SetKeyText(const nsAS
   InfallibleTArray<float> newSelectors;
   // FIXME: pass filename and line number
   if (parser.ParseKeyframeSelectorString(aKeyText, nullptr, 0, newSelectors)) {
     newSelectors.SwapElements(mKeys);
   } else {
     // for now, we don't do anything if the parse fails
   }
 
-  if (mSheet) {
-    mSheet->SetModifiedByChildRule();
+  nsCSSStyleSheet* sheet = GetStyleSheet();
+  if (sheet) {
+    sheet->SetModifiedByChildRule();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCSSKeyframeRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
 {
@@ -2021,18 +2055,19 @@ void
 nsCSSKeyframeRule::ChangeDeclaration(css::Declaration* aDeclaration)
 {
   // Be careful to not assign to an nsAutoPtr if we would be assigning
   // the thing it already holds.
   if (aDeclaration != mDeclaration) {
     mDeclaration = aDeclaration;
   }
 
-  if (mSheet) {
-    mSheet->SetModifiedByChildRule();
+  nsCSSStyleSheet* sheet = GetStyleSheet();
+  if (sheet) {
+    sheet->SetModifiedByChildRule();
   }
 }
 
 /* virtual */ size_t
 nsCSSKeyframeRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
 {
   return aMallocSizeOf(this);
 
@@ -2145,18 +2180,19 @@ nsCSSKeyframesRule::GetName(nsAString& a
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCSSKeyframesRule::SetName(const nsAString& aName)
 {
   mName = aName;
 
-  if (mSheet) {
-    mSheet->SetModifiedByChildRule();
+  nsCSSStyleSheet* sheet = GetStyleSheet();
+  if (sheet) {
+    sheet->SetModifiedByChildRule();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCSSKeyframesRule::GetCssRules(nsIDOMCSSRuleList* *aRuleList)
 {
@@ -2207,18 +2243,19 @@ nsCSSKeyframesRule::FindRuleIndexForKey(
 }
 
 NS_IMETHODIMP
 nsCSSKeyframesRule::DeleteRule(const nsAString& aKey)
 {
   uint32_t index = FindRuleIndexForKey(aKey);
   if (index != RULE_NOT_FOUND) {
     mRules.RemoveObjectAt(index);
-    if (mSheet) {
-      mSheet->SetModifiedByChildRule();
+    nsCSSStyleSheet* sheet = GetStyleSheet();
+    if (sheet) {
+      sheet->SetModifiedByChildRule();
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCSSKeyframesRule::FindRule(const nsAString& aKey,
                              nsIDOMMozCSSKeyframeRule** aResult)
--- a/layout/style/nsHTMLCSSStyleSheet.cpp
+++ b/layout/style/nsHTMLCSSStyleSheet.cpp
@@ -17,25 +17,51 @@
 #include "nsIStyleRuleProcessor.h"
 #include "nsPresContext.h"
 #include "nsIDocument.h"
 #include "nsCOMPtr.h"
 #include "nsRuleWalker.h"
 #include "nsRuleData.h"
 #include "nsRuleProcessorData.h"
 #include "mozilla/dom/Element.h"
+#include "nsAttrValue.h"
+#include "nsAttrValueInlines.h"
 
 using namespace mozilla::dom;
 namespace css = mozilla::css;
 
+namespace {
+
+PLDHashOperator
+ClearAttrCache(const nsAString& aKey, MiscContainer*& aValue, void*)
+{
+  // Ideally we'd just call MiscContainer::Evict, but we can't do that since
+  // we're iterating the hashtable.
+  MOZ_ASSERT(aValue->mType == nsAttrValue::eCSSStyleRule);
+
+  aValue->mValue.mCSSStyleRule->SetHTMLCSSStyleSheet(nullptr);
+  aValue->mValue.mCached = 0;
+
+  return PL_DHASH_REMOVE;
+}
+
+} // anonymous namespace
+
 nsHTMLCSSStyleSheet::nsHTMLCSSStyleSheet()
   : mDocument(nullptr)
 {
 }
 
+nsHTMLCSSStyleSheet::~nsHTMLCSSStyleSheet()
+{
+  // We may go away before all of our cached style attributes do,
+  // so clean up any that are left.
+  mCachedStyleAttrs.Enumerate(ClearAttrCache, nullptr);
+}
+
 NS_IMPL_ISUPPORTS2(nsHTMLCSSStyleSheet,
                    nsIStyleSheet,
                    nsIStyleRuleProcessor)
 
 /* virtual */ void
 nsHTMLCSSStyleSheet::RulesMatching(ElementRuleProcessorData* aData)
 {
   Element* element = aData->mElement;
@@ -89,16 +115,17 @@ nsHTMLCSSStyleSheet::Init(nsIURI* aURL, 
   if (! aURL || ! aDocument)
     return NS_ERROR_NULL_POINTER;
 
   if (mURL || mDocument)
     return NS_ERROR_ALREADY_INITIALIZED;
 
   mDocument = aDocument; // not refcounted!
   mURL = aURL;
+  mCachedStyleAttrs.Init();
   return NS_OK;
 }
 
 // Test if style is dependent on content state
 /* virtual */ nsRestyleHint
 nsHTMLCSSStyleSheet::HasStateDependentStyle(StateRuleProcessorData* aData)
 {
   return nsRestyleHint(0);
@@ -137,16 +164,42 @@ nsHTMLCSSStyleSheet::SizeOfExcludingThis
 
 /* virtual */ size_t
 nsHTMLCSSStyleSheet::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
 {
   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
 }
 
 void
+nsHTMLCSSStyleSheet::CacheStyleAttr(const nsAString& aSerialized,
+                                    MiscContainer* aValue)
+{
+  mCachedStyleAttrs.Put(aSerialized, aValue);
+}
+
+void
+nsHTMLCSSStyleSheet::EvictStyleAttr(const nsAString& aSerialized,
+                                    MiscContainer* aValue)
+{
+#ifdef DEBUG
+  {
+    NS_ASSERTION(aValue = mCachedStyleAttrs.Get(aSerialized),
+                 "Cached value does not match?!");
+  }
+#endif
+  mCachedStyleAttrs.Remove(aSerialized);
+}
+
+MiscContainer*
+nsHTMLCSSStyleSheet::LookupStyleAttr(const nsAString& aSerialized)
+{
+  return mCachedStyleAttrs.Get(aSerialized);
+}
+
+void
 nsHTMLCSSStyleSheet::Reset(nsIURI* aURL)
 {
   mURL = aURL;
 }
 
 /* virtual */ nsIURI*
 nsHTMLCSSStyleSheet::GetSheetURI() const
 {
--- a/layout/style/nsHTMLCSSStyleSheet.h
+++ b/layout/style/nsHTMLCSSStyleSheet.h
@@ -10,20 +10,23 @@
 #ifndef nsHTMLCSSStyleSheet_h_
 #define nsHTMLCSSStyleSheet_h_
 
 #include "mozilla/Attributes.h"
 
 #include "nsIStyleSheet.h"
 #include "nsIStyleRuleProcessor.h"
 
+struct MiscContainer;
+
 class nsHTMLCSSStyleSheet MOZ_FINAL : public nsIStyleSheet,
                                       public nsIStyleRuleProcessor {
 public:
   nsHTMLCSSStyleSheet();
+  ~nsHTMLCSSStyleSheet();
 
   NS_DECL_ISUPPORTS
 
   nsresult Init(nsIURI* aURL, nsIDocument* aDocument);
   void Reset(nsIURI* aURL);
 
   // nsIStyleSheet
   virtual nsIURI* GetSheetURI() const;
@@ -54,18 +57,23 @@ public:
   virtual nsRestyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData) MOZ_OVERRIDE;
   virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) MOZ_OVERRIDE;
   virtual NS_MUST_OVERRIDE size_t
     SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const MOZ_OVERRIDE;
   virtual NS_MUST_OVERRIDE size_t
     SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const MOZ_OVERRIDE;
 
+  void CacheStyleAttr(const nsAString& aSerialized, MiscContainer* aValue);
+  void EvictStyleAttr(const nsAString& aSerialized, MiscContainer* aValue);
+  MiscContainer* LookupStyleAttr(const nsAString& aSerialized);
+
 private: 
   nsHTMLCSSStyleSheet(const nsHTMLCSSStyleSheet& aCopy) MOZ_DELETE;
   nsHTMLCSSStyleSheet& operator=(const nsHTMLCSSStyleSheet& aCopy) MOZ_DELETE;
 
 protected:
   nsCOMPtr<nsIURI> mURL;
   nsIDocument*     mDocument;
+  nsDataHashtable<nsStringHashKey, MiscContainer*> mCachedStyleAttrs;
 };
 
 #endif /* !defined(nsHTMLCSSStyleSheet_h_) */
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -9,16 +9,17 @@
 #include "nsTablePainter.h"
 #include "nsStyleContext.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include "nsCSSRendering.h"
 #include "nsIContent.h"
 #include "nsGenericHTMLElement.h"
+#include "nsAttrValueInlines.h"
 #include "nsHTMLParts.h"
 #include "nsGkAtoms.h"
 #include "nsIPresShell.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMHTMLTableCellElement.h"
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif