Rewrite the pref for forbidding pages from setting colors and backgrounds so that it changes transparency less often and interferes less with user and user-agent styles. b=58048, 255829, 255411 r+sr=bzbarsky
authordbaron@dbaron.org
Wed, 16 May 2007 14:10:31 -0700
changeset 1540 90c36357680cbc7e6c33708dc3bdd3cc76ec9572
parent 1539 99dd842c007c386f18d6e958526b8768f8adf8e7
child 1541 f5fbc835f7ab317c2cbc46397c38c4734161b841
push idunknown
push userunknown
push dateunknown
bugs58048, 255829, 255411
milestone1.9a5pre
Rewrite the pref for forbidding pages from setting colors and backgrounds so that it changes transparency less often and interferes less with user and user-agent styles. b=58048, 255829, 255411 r+sr=bzbarsky
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsPresShell.cpp
layout/style/nsCSSDataBlock.cpp
layout/style/nsRuleData.h
layout/style/nsRuleNode.cpp
layout/style/test/test_initial_computation.html
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1363,8 +1363,28 @@ nsPresContext::EnsureVisible(PRBool aUns
 void
 nsPresContext::CountReflows(const char * aName, nsIFrame * aFrame)
 {
   if (mShell) {
     mShell->CountReflows(aName, aFrame);
   }
 }
 #endif
+
+PRBool
+nsPresContext::IsChrome()
+{
+  PRBool isChrome = PR_FALSE;
+  nsCOMPtr<nsISupports> container = GetContainer();
+  if (container) {
+    nsresult result;
+    nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(container, &result));
+    if (NS_SUCCEEDED(result) && docShell) {
+      PRInt32 docShellType;
+      result = docShell->GetItemType(&docShellType);
+      if (NS_SUCCEEDED(result)) {
+        isChrome = nsIDocShellTreeItem::typeChrome == docShellType;
+      }
+    }
+  }
+  return isChrome;
+}
+
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -695,16 +695,19 @@ public:
    */
   const nscoord* GetBorderWidthTable() { return mBorderWidthTable; }
 
   PRBool IsDynamic() { return (mType == eContext_PageLayout || mType == eContext_Galley); }
   PRBool IsScreen() { return (mMedium == nsGkAtoms::screen ||
                               mType == eContext_PageLayout ||
                               mType == eContext_PrintPreview); }
 
+  // Is this presentation in a chrome docshell?
+  PRBool IsChrome();
+
   const nsTArray<nsIFrame*>& GetActivePopups() {
     NS_ASSERTION(this == RootPresContext(), "Only on root prescontext");
     return mActivePopups;
   }
   void NotifyAddedActivePopupToTop(nsIFrame* aFrame) {
     NS_ASSERTION(this == RootPresContext(), "Only on root prescontext");
     mActivePopups.AppendElement(aFrame);
   }
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1050,17 +1050,16 @@ protected:
 #endif
 
     /**
     * methods that manage rules that are used to implement the associated preferences
     *  - initially created for bugs 31816, 20760, 22963
     */
   nsresult ClearPreferenceStyleRules(void);
   nsresult CreatePreferenceStyleSheet(void);
-  nsresult SetPrefColorRules(void);
   nsresult SetPrefLinkRules(void);
   nsresult SetPrefFocusRules(void);
   nsresult SetPrefNoScriptRule();
   nsresult SetPrefNoFramesRule(void);
 
   // methods for painting a range to an offscreen buffer
 
   // given a display list, clip the items within the list to
@@ -1778,21 +1777,16 @@ PresShell::SetPreferenceStyleRules(PRBoo
 #endif
       // if here, we need to create rules for the prefs
       // - this includes the background-color, the text-color,
       //   the link color, the visited link color and the link-underlining
     
       // first clear any exising rules
       result = ClearPreferenceStyleRules();
       
-      // now do the color rules
-      if (NS_SUCCEEDED(result)) {
-        result = SetPrefColorRules();
-      }
-
       // now the link rules (must come after the color rules, or links will not be correct color!)
       // XXX - when there is both an override and agent pref stylesheet this won't matter,
       //       as the color rules will be overrides and the links rules will be agent
       if (NS_SUCCEEDED(result)) {
         result = SetPrefLinkRules();
       }
       if (NS_SUCCEEDED(result)) {
         result = SetPrefFocusRules();
@@ -1878,83 +1872,16 @@ nsresult PresShell::CreatePreferenceStyl
   return result;
 }
 
 // XXX We want these after the @namespace rule.  Does order matter
 // for these rules, or can we call nsICSSStyleRule::StyleRuleCount()
 // and just "append"?
 static PRUint32 sInsertPrefSheetRulesAt = 1;
 
-nsresult PresShell::SetPrefColorRules(void)
-{
-  NS_ASSERTION(mPresContext,"null prescontext not allowed");
-  if (mPresContext) {
-    nsresult result = NS_OK;
-
-    // see if we need to create the rules first
-    PRBool useDocColors =
-      mPresContext->GetCachedBoolPref(kPresContext_UseDocumentColors);
-    if (!useDocColors) {
-
-#ifdef DEBUG_attinasi
-      printf(" - Creating rules for document colors\n");
-#endif
-
-      // OK, not using document colors, so we have to force the user's colors via style rules
-      if (!mPrefStyleSheet) {
-        result = CreatePreferenceStyleSheet();
-      }
-      if (NS_SUCCEEDED(result)) {
-        NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null");
-
-        nscolor bgColor = mPresContext->DefaultBackgroundColor();
-        nscolor textColor = mPresContext->DefaultColor();
-
-        // get the DOM interface to the stylesheet
-        nsCOMPtr<nsIDOMCSSStyleSheet> sheet(do_QueryInterface(mPrefStyleSheet,&result));
-        if (NS_SUCCEEDED(result)) {
-          PRUint32 index = 0;
-          nsAutoString strColor, strBackgroundColor;
-
-          // create a rule for background and foreground color and
-          // add it to the style sheet              
-          // - the rule is !important so it overrides all but author
-          //   important rules (when put into an agent stylesheet) and 
-          //   all (even author important) when put into an override stylesheet
-
-          ///////////////////////////////////////////////////////////////
-          // - default colors: ':root {color:#RRGGBB !important;
-          //                           background: #RRGGBB !important;}'
-          ColorToString(textColor,strColor);
-          ColorToString(bgColor,strBackgroundColor);
-          result = sheet->InsertRule(NS_LITERAL_STRING("*|*:root {color:") +
-                                     strColor +
-                                     NS_LITERAL_STRING(" !important; ") +
-                                     NS_LITERAL_STRING("border-color: -moz-use-text-color !important; ") +
-                                     NS_LITERAL_STRING("background:") +
-                                     strBackgroundColor +
-                                     NS_LITERAL_STRING(" !important; }"),
-                                     sInsertPrefSheetRulesAt, &index);
-          NS_ENSURE_SUCCESS(result, result);
-
-          ///////////////////////////////////////////////////////////////
-          // - everything else inherits the color
-          // (the background color will be handled in 
-          //  nsRuleNode::ComputeBackgroundData)
-          result = sheet->InsertRule(NS_LITERAL_STRING("*|* {color: inherit !important; border-color: -moz-use-text-color !important; background-image: none !important; } "),
-                                     sInsertPrefSheetRulesAt, &index);
-        }
-      }
-    }
-    return result;
-  } else {
-    return NS_ERROR_FAILURE;
-  }
-}
-
 nsresult
 PresShell::SetPrefNoScriptRule()
 {
   nsresult rv = NS_OK;
 
   // also handle the case where print is done from print preview
   // see bug #342439 for more details
   PRBool scriptEnabled = mDocument->IsScriptEnabled() ||
@@ -2041,21 +1968,17 @@ nsresult PresShell::SetPrefLinkRules(voi
   //   which they are if we put them in the agent stylesheet,
   //   though if using an override sheet this will cause authors grief still
   //   In the agent stylesheet, they are !important when we are ignoring document colors
   
   nscolor linkColor(mPresContext->DefaultLinkColor());
   nscolor activeColor(mPresContext->DefaultActiveLinkColor());
   nscolor visitedColor(mPresContext->DefaultVisitedLinkColor());
   
-  PRBool useDocColors =
-    mPresContext->GetCachedBoolPref(kPresContext_UseDocumentColors);
-  NS_NAMED_LITERAL_STRING(notImportantStr, "}");
-  NS_NAMED_LITERAL_STRING(importantStr, "!important}");
-  const nsAString& ruleClose = useDocColors ? notImportantStr : importantStr;
+  NS_NAMED_LITERAL_STRING(ruleClose, "}");
   PRUint32 index = 0;
   nsAutoString strColor;
 
   // insert a rule to color links: '*|*:link {color: #RRGGBB [!important];}'
   ColorToString(linkColor, strColor);
   rv = sheet->InsertRule(NS_LITERAL_STRING("*|*:link{color:") +
                          strColor + ruleClose,
                          sInsertPrefSheetRulesAt, &index);
--- a/layout/style/nsCSSDataBlock.cpp
+++ b/layout/style/nsCSSDataBlock.cpp
@@ -39,16 +39,17 @@
  * compact representation of the property-value pairs within a CSS
  * declaration, and the code for expanding and compacting it
  */
 
 #include "nsCSSDataBlock.h"
 #include "nsCSSProps.h"
 #include "nsRuleData.h"
 #include "nsRuleNode.h"
+#include "nsStyleSet.h"
 
 /*
  * nsCSSCompressedDataBlock holds property-value pairs corresponding to
  * CSS declaration blocks.  The value is stored in one of the six CSS
  * data types.  These six types are nsCSSValue, nsCSSRect,
  * nsCSSValueList, nsCSSCounterData, nsCSSQuotes, and nsCSSValuePair, and
  * each correspond to a value of the nsCSSType enumeration.
  *
@@ -166,16 +167,26 @@ inline nsCSSQuotes*& QuotesAtCursor(char
                     & NS_REINTERPRET_CAST(CDBPointerStorage*, aCursor)->value);
 }
 
 inline nsCSSQuotes* QuotesAtCursor(const char *aCursor) {
     return NS_STATIC_CAST(nsCSSQuotes*,
                 NS_REINTERPRET_CAST(const CDBPointerStorage*, aCursor)->value);
 }
 
+static PRBool
+ShouldIgnoreColors(nsRuleData *aRuleData)
+{
+    nsPresContext *presContext = aRuleData->mPresContext;
+    return aRuleData->mLevel != nsStyleSet::eAgentSheet &&
+           aRuleData->mLevel != nsStyleSet::eUserSheet &&
+           !presContext->GetCachedBoolPref(kPresContext_UseDocumentColors) &&
+           !presContext->IsChrome();
+}
+
 nsresult
 nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const
 {
     // If we have no data for this struct, then return immediately.
     // This optimization should make us return most of the time, so we
     // have to worry much less (although still some) about the speed of
     // the rest of the function.
     if (!(nsCachedStyleData::GetBitForSID(aRuleData->mSID) & mStyleBits))
@@ -202,16 +213,42 @@ nsCSSCompressedDataBlock::MapRuleInfoInt
                             val->StartImageLoad(aRuleData->mPresContext->Document(),
                                                 iProp == eCSSProperty_background_image);
                         }
                         *target = *val;
                         if (iProp == eCSSProperty_font_family) {
                             // XXX Are there other things like this?
                             aRuleData->mFontData->mFamilyFromHTML = PR_FALSE;
                         }
+                        else if (iProp == eCSSProperty_color ||
+                                 iProp == eCSSProperty_background_color ||
+                                 iProp == eCSSProperty_background_image ||
+                                 iProp == eCSSProperty_border_top_color ||
+                                 iProp == eCSSProperty_border_right_color ||
+                                 iProp == eCSSProperty_border_bottom_color ||
+                                 iProp == eCSSProperty_border_left_color) {
+                            if (ShouldIgnoreColors(aRuleData)) {
+                                if (iProp == eCSSProperty_background_color) {
+                                    // Force non-'transparent' background
+                                    // colors to the user's default.
+                                    nsCSSUnit u = target->GetUnit();
+                                    if (u != eCSSUnit_Enumerated &&
+                                        u != eCSSUnit_Inherit &&
+                                        u != eCSSUnit_Initial) {
+                                        target->SetColorValue(aRuleData->
+                                            mPresContext->
+                                            DefaultBackgroundColor());
+                                    }
+                                } else {
+                                    // Ignore 'color', 'border-*-color', and
+                                    // 'background-image'
+                                    *target = nsCSSValue();
+                                }
+                            }
+                        }
                     }
                     cursor += CDBValueStorage_advance;
                 } break;
 
                 case eCSSType_Rect: {
                     const nsCSSRect* val = RectAtCursor(cursor);
                     NS_ASSERTION(val->HasValue(), "oops");
                     nsCSSRect* target = NS_STATIC_CAST(nsCSSRect*, prop);
@@ -261,16 +298,25 @@ nsCSSCompressedDataBlock::MapRuleInfoInt
                 // fall through
                 case eCSSType_CounterData:
                 case eCSSType_Quotes: {
                     void** target = NS_STATIC_CAST(void**, prop);
                     if (!*target) {
                         void* val = PointerAtCursor(cursor);
                         NS_ASSERTION(val, "oops");
                         *target = val;
+
+                        if (iProp == eCSSProperty_border_top_colors ||
+                            iProp == eCSSProperty_border_right_colors ||
+                            iProp == eCSSProperty_border_bottom_colors ||
+                            iProp == eCSSProperty_border_left_colors) {
+                            if (ShouldIgnoreColors(aRuleData)) {
+                                *target = nsnull;
+                            }
+                        }
                     }
                     cursor += CDBPointerStorage_advance;
                 } break;
             }
         } else {
             switch (nsCSSProps::kTypeTable[iProp]) {
                 case eCSSType_Value: {
                     cursor += CDBValueStorage_advance;
--- a/layout/style/nsRuleData.h
+++ b/layout/style/nsRuleData.h
@@ -51,16 +51,18 @@ class nsStyleContext;
 
 struct nsRuleData;
 typedef void (*nsPostResolveFunc)(nsStyleStruct* aStyleStruct, nsRuleData* aData);
 
 struct nsRuleData
 {
   nsStyleStructID mSID;
   PRPackedBool mCanStoreInRuleTree;
+  PRPackedBool mIsImportantRule;
+  PRUint8 mLevel; // an nsStyleSet::sheetType
   nsPresContext* mPresContext;
   nsStyleContext* mStyleContext;
   nsPostResolveFunc mPostResolveCallback;
   nsRuleDataFont* mFontData; // Should always be stack-allocated! We don't own these structures!
   nsRuleDataDisplay* mDisplayData;
   nsRuleDataMargin* mMarginData;
   nsRuleDataList* mListData;
   nsRuleDataPosition* mPositionData;
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -46,17 +46,16 @@
 
 #include "nsRuleNode.h"
 #include "nscore.h"
 #include "nsIServiceManager.h"
 #include "nsIDeviceContext.h"
 #include "nsILookAndFeel.h"
 #include "nsIPresShell.h"
 #include "nsIFontMetrics.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsStyleUtil.h"
 #include "nsCSSPseudoElements.h"
 #include "nsThemeConstants.h"
 #include "nsITheme.h"
 #include "pldhash.h"
 #include "nsStyleContext.h"
 #include "nsStyleSet.h"
 #include "nsSize.h"
@@ -1388,18 +1387,21 @@ nsRuleNode::WalkRuleTree(const nsStyleSt
     startStruct = ruleNode->mStyleData.GetStyleData(aSID);
     if (startStruct)
       break; // We found a rule with fully specified data.  We don't
              // need to go up the tree any further, since the remainder
              // of this branch has already been computed.
 
     // Ask the rule to fill in the properties that it specifies.
     nsIStyleRule *rule = ruleNode->mRule;
-    if (rule)
+    if (rule) {
+      aRuleData->mLevel = ruleNode->GetLevel();
+      aRuleData->mIsImportantRule = ruleNode->IsImportantRule();
       rule->MapRuleInfoInto(aRuleData);
+    }
 
     // Now we check to see how many properties have been specified by
     // the rules we've examined so far.
     RuleDetail oldDetail = detail;
     detail = CheckSpecifiedProperties(aSID, *aSpecificData);
   
     if (oldDetail == eRuleNone && detail != eRuleNone)
       highestNode = ruleNode;
@@ -1480,47 +1482,28 @@ nsRuleNode::WalkRuleTree(const nsStyleSt
   // If we have a post-resolve callback, handle that now.
   if (aRuleData->mPostResolveCallback && (NS_LIKELY(res != nsnull)))
     (*aRuleData->mPostResolveCallback)((nsStyleStruct*)res, aRuleData);
 
   // Now return the result.
   return res;
 }
 
-static PRBool
-IsChrome(nsPresContext* aPresContext)
-{
-  PRBool isChrome = PR_FALSE;
-  nsCOMPtr<nsISupports> container = aPresContext->GetContainer();
-  if (container) {
-    nsresult result;
-    nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(container, &result));
-    if (NS_SUCCEEDED(result) && docShell) {
-      PRInt32 docShellType;
-      result = docShell->GetItemType(&docShellType);
-      if (NS_SUCCEEDED(result)) {
-        isChrome = nsIDocShellTreeItem::typeChrome == docShellType;
-      }
-    }
-  }
-  return isChrome;
-}
-
 const nsStyleStruct*
 nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
 {
   switch (aSID) {
     case eStyleStruct_Font: 
     {
       nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
       if (NS_LIKELY(fontData != nsnull)) {
         nscoord minimumFontSize =
           mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
 
-        if (minimumFontSize > 0 && !IsChrome(mPresContext)) {
+        if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
           fontData->mFont.size = PR_MAX(fontData->mSize, minimumFontSize);
         }
         else {
           fontData->mFont.size = fontData->mSize;
         }
         aContext->SetStyle(eStyleStruct_Font, fontData);
       }
       return fontData;
@@ -2215,18 +2198,21 @@ nsRuleNode::SetGenericFont(nsPresContext
     // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
     for (nsRuleNode* ruleNode = context->GetRuleNode(); ruleNode;
          ruleNode = ruleNode->GetParent()) {
       if (ruleNode->mNoneBits & fontBit)
         // no more font rules on this branch, get out
         break;
 
       nsIStyleRule *rule = ruleNode->GetRule();
-      if (rule)
+      if (rule) {
+        ruleData.mLevel = ruleNode->GetLevel();
+        ruleData.mIsImportantRule = ruleNode->IsImportantRule();
         rule->MapRuleInfoInto(&ruleData);
+      }
     }
 
     // Compute the delta from the information that the rules specified
     fontData.mFamily.Reset(); // avoid unnecessary operations in SetFont()
 
     nsRuleNode::SetFont(aPresContext, context, aMinFontSize,
                         PR_TRUE, fontData, *defaultFont,
                         &parentFont, aFont, dummy);
@@ -2280,17 +2266,17 @@ nsRuleNode::ComputeFontData(nsStyleStruc
 
   PRBool useDocumentFonts =
     mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
 
   // See if we are in the chrome
   // We only need to know this to determine if we have to use the
   // document fonts (overriding the useDocumentFonts flag), or to
   // determine if we have to override the minimum font-size constraint.
-  if ((!useDocumentFonts || minimumFontSize > 0) && IsChrome(mPresContext)) {
+  if ((!useDocumentFonts || minimumFontSize > 0) && mPresContext->IsChrome()) {
     // if we are not using document fonts, but this is a XUL document,
     // then we use the document fonts anyway
     useDocumentFonts = PR_TRUE;
     minimumFontSize = 0;
   }
 
   // Figure out if we are a generic font
   PRUint8 generic = kGenericFont_NONE;
@@ -2378,17 +2364,17 @@ nsRuleNode::ComputeTextData(nsStyleStruc
              aContext, mPresContext, inherited);
     if (textData.mLineHeight.IsFixedLengthUnit() ||
         textData.mLineHeight.GetUnit() == eCSSUnit_Pixel) {
       nscoord lh = nsStyleFont::ZoomText(mPresContext,
                                          text->mLineHeight.GetCoordValue());
       nscoord minimumFontSize =
         mPresContext->GetCachedIntPref(kPresContext_MinimumFontSize);
 
-      if (minimumFontSize > 0 && !IsChrome(mPresContext)) {
+      if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
         // If we applied a minimum font size, scale the line height by
         // the same ratio.  (If we *might* have applied a minimum font
         // size, we can't cache in the rule tree.)
         inherited = PR_TRUE;
         const nsStyleFont *font = aContext->GetStyleFont();
         if (font->mSize != 0) {
           lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
         } else {
@@ -3059,33 +3045,28 @@ nsRuleNode::ComputeBackgroundData(nsStyl
     bg->mBackgroundColor = parentBG->mBackgroundColor;
     bg->mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT;
     bg->mBackgroundFlags |= (parentFlags & NS_STYLE_BG_COLOR_TRANSPARENT);
     inherited = PR_TRUE;
   }
   else if (SetColor(colorData.mBackColor, parentBG->mBackgroundColor, 
                     mPresContext, aContext, bg->mBackgroundColor, inherited)) {
     bg->mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT;
-    // if not using document colors, we have to use the user's background color
-    // instead of any background color other than transparent
-    if (!mPresContext->GetCachedBoolPref(kPresContext_UseDocumentColors) &&
-        !IsChrome(mPresContext)) {
-      bg->mBackgroundColor = mPresContext->DefaultBackgroundColor();
-    }
-  }
-  else if (eCSSUnit_Enumerated == colorData.mBackColor.GetUnit()) {
-    //bg->mBackgroundColor = parentBG->mBackgroundColor; XXXwdh crap crap crap!
+  }
+  else if (eCSSUnit_Enumerated == colorData.mBackColor.GetUnit() ||
+           eCSSUnit_Initial == colorData.mBackColor.GetUnit()) {
     bg->mBackgroundFlags |= NS_STYLE_BG_COLOR_TRANSPARENT;
   }
 
   // background-image: url (stored as image), none, inherit
   if (eCSSUnit_Image == colorData.mBackImage.GetUnit()) {
     bg->mBackgroundImage = colorData.mBackImage.GetImageValue();
   }
-  else if (eCSSUnit_None == colorData.mBackImage.GetUnit()) {
+  else if (eCSSUnit_None == colorData.mBackImage.GetUnit() ||
+           eCSSUnit_Initial == colorData.mBackImage.GetUnit()) {
     bg->mBackgroundImage = nsnull;
   }
   else if (eCSSUnit_Inherit == colorData.mBackImage.GetUnit()) {
     inherited = PR_TRUE;
     bg->mBackgroundImage = parentBG->mBackgroundImage;
   }
 
   if (bg->mBackgroundImage) {
@@ -3097,25 +3078,31 @@ nsRuleNode::ComputeBackgroundData(nsStyl
   // background-repeat: enum, inherit
   if (eCSSUnit_Enumerated == colorData.mBackRepeat.GetUnit()) {
     bg->mBackgroundRepeat = colorData.mBackRepeat.GetIntValue();
   }
   else if (eCSSUnit_Inherit == colorData.mBackRepeat.GetUnit()) {
     inherited = PR_TRUE;
     bg->mBackgroundRepeat = parentBG->mBackgroundRepeat;
   }
+  else if (eCSSUnit_Initial == colorData.mBackRepeat.GetUnit()) {
+    bg->mBackgroundRepeat = NS_STYLE_BG_REPEAT_XY;
+  }
 
   // background-attachment: enum, inherit
   if (eCSSUnit_Enumerated == colorData.mBackAttachment.GetUnit()) {
     bg->mBackgroundAttachment = colorData.mBackAttachment.GetIntValue();
   }
   else if (eCSSUnit_Inherit == colorData.mBackAttachment.GetUnit()) {
     inherited = PR_TRUE;
     bg->mBackgroundAttachment = parentBG->mBackgroundAttachment;
   }
+  else if (eCSSUnit_Initial == colorData.mBackAttachment.GetUnit()) {
+    bg->mBackgroundAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL;
+  }
 
   // background-clip: enum, inherit, initial
   if (eCSSUnit_Enumerated == colorData.mBackClip.GetUnit()) {
     bg->mBackgroundClip = colorData.mBackClip.GetIntValue();
   }
   else if (eCSSUnit_Inherit == colorData.mBackClip.GetUnit()) {
     bg->mBackgroundClip = parentBG->mBackgroundClip;
   }
@@ -3176,16 +3163,19 @@ nsRuleNode::ComputeBackgroundData(nsStyl
     bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH;
   }
   else if (eCSSUnit_Inherit == colorData.mBackPosition.mXValue.GetUnit()) {
     inherited = PR_TRUE;
     bg->mBackgroundXPosition = parentBG->mBackgroundXPosition;
     bg->mBackgroundFlags &= ~(NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT);
     bg->mBackgroundFlags |= (parentFlags & (NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT));
   }
+  else if (eCSSUnit_Initial == colorData.mBackPosition.mXValue.GetUnit()) {
+    bg->mBackgroundFlags &= ~(NS_STYLE_BG_X_POSITION_LENGTH | NS_STYLE_BG_X_POSITION_PERCENT);
+  }
 
   if (eCSSUnit_Percent == colorData.mBackPosition.mYValue.GetUnit()) {
     bg->mBackgroundYPosition.mFloat = colorData.mBackPosition.mYValue.GetPercentValue();
     bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PERCENT;
     bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH;
   }
   else if (colorData.mBackPosition.mYValue.IsLengthUnit()) {
     bg->mBackgroundYPosition.mCoord = CalcLength(colorData.mBackPosition.mYValue, nsnull,
@@ -3212,16 +3202,19 @@ nsRuleNode::ComputeBackgroundData(nsStyl
     bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH;
   }
   else if (eCSSUnit_Inherit == colorData.mBackPosition.mYValue.GetUnit()) {
     inherited = PR_TRUE;
     bg->mBackgroundYPosition = parentBG->mBackgroundYPosition;
     bg->mBackgroundFlags &= ~(NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT);
     bg->mBackgroundFlags |= (parentFlags & (NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT));
   }
+  else if (eCSSUnit_Initial == colorData.mBackPosition.mYValue.GetUnit()) {
+    bg->mBackgroundFlags &= ~(NS_STYLE_BG_Y_POSITION_LENGTH | NS_STYLE_BG_Y_POSITION_PERCENT);
+  }
 
   COMPUTE_END_RESET(Background, bg)
 }
 
 const nsStyleStruct*
 nsRuleNode::ComputeMarginData(nsStyleStruct* aStartStruct,
                               const nsRuleDataStruct& aData, 
                               nsStyleContext* aContext, 
--- a/layout/style/test/test_initial_computation.html
+++ b/layout/style/test/test_initial_computation.html
@@ -106,20 +106,16 @@ var gBrokenInitial = {
   "-moz-outline-radius-bottomleft": true,
   "-moz-outline-radius-bottomright": true,
   "-moz-outline-radius-topleft": true,
   "-moz-outline-radius-topright": true,
   "-moz-user-focus": true,
   "-moz-user-input": true,
   "-moz-user-modify": true,
   "-moz-user-select": true,
-  "background-attachment": true,
-  "background-color": true,
-  "background-image": true,
-  "background-repeat": true,
   "border-bottom-color": true,
   "border-collapse": true,
   "border-color": true,
   "border-left-color": true,
   "border-right-color": true,
   "border-spacing": true,
   "border-top-color": true,
   "bottom": true,