Implement remaining properties in computed style (with some hacks for counter() values for content), and fix some page-break-* bugs exposed by the added test coverage. b=316981 r+sr=bzbarsky
authordbaron@dbaron.org
Sun, 22 Jul 2007 10:58:37 -0700
changeset 3750 3bca698f9012436c3643a3aa9156e8440377d0b7
parent 3749 9c6f622772095ae5e170ec8210b7d4266fd36986
child 3751 34f8c970d8b1d2a1996545860eb43b981ca5a7a5
push idunknown
push userunknown
push dateunknown
bugs316981
milestone1.9a7pre
Implement remaining properties in computed style (with some hacks for counter() values for content), and fix some page-break-* bugs exposed by the added test coverage. b=316981 r+sr=bzbarsky
layout/style/nsCSSKeywords.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsROCSSPrimitiveValue.cpp
layout/style/nsROCSSPrimitiveValue.h
layout/style/nsRuleNode.cpp
layout/style/test/test_compute_data_with_start_struct.html
layout/style/test/test_inherit_computation.html
layout/style/test/test_initial_computation.html
layout/style/test/test_value_computation.html
layout/style/test/test_value_storage.html
--- a/layout/style/nsCSSKeywords.cpp
+++ b/layout/style/nsCSSKeywords.cpp
@@ -112,16 +112,17 @@ nsCSSKeywords::LookupKeyword(const nsASt
   }  
   return eCSSKeyword_UNKNOWN;
 }
 
 const nsAFlatCString& 
 nsCSSKeywords::GetStringValue(nsCSSKeyword aKeyword)
 {
   NS_ASSERTION(gKeywordTable, "no lookup table, needs addref");
+  NS_ASSERTION(0 <= aKeyword && aKeyword < eCSSKeyword_COUNT, "out of range");
   if (gKeywordTable) {
     return gKeywordTable->GetStringValue(PRInt32(aKeyword));
   } else {
     static nsDependentCString kNullStr("");
     return kNullStr;
   }
 }
 
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -593,48 +593,153 @@ nsComputedDOMStyle::GetColumnGap(nsIDOMC
   } else {
     SetValueToCoord(val, GetStyleColumn()->mColumnGap);
   }
 
   return CallQueryInterface(val, aValue);
 }
 
 nsresult
+nsComputedDOMStyle::GetContent(nsIDOMCSSValue** aValue)
+{
+  const nsStyleContent *content = GetStyleContent();
+
+  if (content->ContentCount() == 0) {
+    nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+    NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
+    val->SetIdent(nsGkAtoms::none);
+    return CallQueryInterface(val, aValue);
+  }
+
+  if (content->ContentCount() == 1 &&
+      content->ContentAt(0).mType == eStyleContentType_AltContent) {
+    nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+    NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
+    val->SetIdent(eCSSKeyword__moz_alt_content);
+    return CallQueryInterface(val, aValue);
+  }
+
+  nsDOMCSSValueList *valueList = GetROCSSValueList(PR_FALSE);
+  NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY);
+
+  for (PRUint32 i = 0, i_end = content->ContentCount(); i < i_end; ++i) {
+    nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
+    if (!val || !valueList->AppendCSSValue(val)) {
+      delete valueList;
+      delete val;
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    const nsStyleContentData &data = content->ContentAt(i);
+    switch (data.mType) {
+      case eStyleContentType_String:
+        {
+          nsString str;
+          nsStyleUtil::EscapeCSSString(nsDependentString(data.mContent.mString),
+                                       str);
+          str.Insert(PRUnichar('"'), 0);
+          str.Append(PRUnichar('"'));
+          val->SetString(str);
+        }
+        break;
+      case eStyleContentType_Image:
+        {
+          nsCOMPtr<nsIURI> uri;
+          if (data.mContent.mImage) {
+            data.mContent.mImage->GetURI(getter_AddRefs(uri));
+          }
+          val->SetURI(uri);
+        }
+        break;
+      case eStyleContentType_Attr:
+        val->SetString(nsDependentString(data.mContent.mString),
+                       nsIDOMCSSPrimitiveValue::CSS_ATTR);
+        break;
+      case eStyleContentType_Counter:
+      case eStyleContentType_Counters:
+        {
+          /* FIXME: counters should really use an object */
+          nsAutoString str;
+          if (data.mType == eStyleContentType_Counter) {
+            str.AppendLiteral("counter(");
+          }
+          else {
+            str.AppendLiteral("counters(");
+          }
+          // WRITE ME
+          nsCSSValue::Array *a = data.mContent.mCounters;
+
+          str.Append(a->Item(0).GetStringBufferValue());
+          PRInt32 typeItem = 1;
+          if (data.mType == eStyleContentType_Counters) {
+            typeItem = 2;
+            str.AppendLiteral(", \"");
+            nsString itemstr;
+            nsStyleUtil::EscapeCSSString(
+              nsDependentString(a->Item(1).GetStringBufferValue()), itemstr);
+            str.Append(itemstr);
+            str.Append(PRUnichar('"'));
+          }
+          PRInt32 type = a->Item(typeItem).GetIntValue();
+          if (type != NS_STYLE_LIST_STYLE_DECIMAL) {
+            str.AppendLiteral(", ");
+            str.AppendInt(type);
+          }
+
+          str.Append(PRUnichar(')'));
+          val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_COUNTER);
+        }
+        break;
+      case eStyleContentType_OpenQuote:
+        val->SetIdent(eCSSKeyword_open_quote);
+        break;
+      case eStyleContentType_CloseQuote:
+        val->SetIdent(eCSSKeyword_close_quote);
+        break;
+      case eStyleContentType_NoOpenQuote:
+        val->SetIdent(eCSSKeyword_no_open_quote);
+        break;
+      case eStyleContentType_NoCloseQuote:
+        val->SetIdent(eCSSKeyword_no_close_quote);
+        break;
+      case eStyleContentType_AltContent:
+      default:
+        NS_NOTREACHED("unexpected type");
+        break;
+    }
+  }
+
+  return CallQueryInterface(valueList, aValue);
+}
+
+nsresult
 nsComputedDOMStyle::GetCounterIncrement(nsIDOMCSSValue** aValue)
 {
   const nsStyleContent *content = GetStyleContent();
 
   if (content->CounterIncrementCount() == 0) {
     nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
     NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
     val->SetIdent(nsGkAtoms::none);
     return CallQueryInterface(val, aValue);
   }
 
   nsDOMCSSValueList *valueList = GetROCSSValueList(PR_FALSE);
   NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY);
 
   for (PRUint32 i = 0, i_end = content->CounterIncrementCount(); i < i_end; ++i) {
     nsROCSSPrimitiveValue* name = GetROCSSPrimitiveValue();
-    if (!name) {
-      delete valueList;
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    if (!valueList->AppendCSSValue(name)) {
+    if (!name || !valueList->AppendCSSValue(name)) {
       delete valueList;
       delete name;
       return NS_ERROR_OUT_OF_MEMORY;
     }
     
     nsROCSSPrimitiveValue* value = GetROCSSPrimitiveValue();
-    if (!value) {
-      delete valueList;
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    if (!valueList->AppendCSSValue(value)) {
+    if (!value || !valueList->AppendCSSValue(value)) {
       delete valueList;
       delete value;
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     const nsStyleCounterData *data = content->GetCounterIncrementAt(i);
     name->SetString(data->mCounter);
     value->SetNumber(data->mValue); // XXX This should really be integer
@@ -655,46 +760,82 @@ nsComputedDOMStyle::GetCounterReset(nsID
     return CallQueryInterface(val, aValue);
   }
 
   nsDOMCSSValueList *valueList = GetROCSSValueList(PR_FALSE);
   NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY);
 
   for (PRUint32 i = 0, i_end = content->CounterResetCount(); i < i_end; ++i) {
     nsROCSSPrimitiveValue* name = GetROCSSPrimitiveValue();
-    if (!name) {
-      delete valueList;
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    if (!valueList->AppendCSSValue(name)) {
+    if (!name || !valueList->AppendCSSValue(name)) {
       delete valueList;
       delete name;
       return NS_ERROR_OUT_OF_MEMORY;
     }
     
     nsROCSSPrimitiveValue* value = GetROCSSPrimitiveValue();
-    if (!value) {
-      delete valueList;
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    if (!valueList->AppendCSSValue(value)) {
+    if (!value || !valueList->AppendCSSValue(value)) {
       delete valueList;
       delete value;
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     const nsStyleCounterData *data = content->GetCounterResetAt(i);
     name->SetString(data->mCounter);
     value->SetNumber(data->mValue); // XXX This should really be integer
   }
 
   return CallQueryInterface(valueList, aValue);
 }
 
 nsresult
+nsComputedDOMStyle::GetQuotes(nsIDOMCSSValue** aValue)
+{
+  const nsStyleQuotes *quotes = GetStyleQuotes();
+
+  if (quotes->QuotesCount() == 0) {
+    nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+    NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
+    val->SetIdent(nsGkAtoms::none);
+    return CallQueryInterface(val, aValue);
+  }
+
+  nsDOMCSSValueList *valueList = GetROCSSValueList(PR_FALSE);
+  NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY);
+
+  for (PRUint32 i = 0, i_end = quotes->QuotesCount(); i < i_end; ++i) {
+    nsROCSSPrimitiveValue* openVal = GetROCSSPrimitiveValue();
+    if (!openVal || !valueList->AppendCSSValue(openVal)) {
+      delete valueList;
+      delete openVal;
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    
+    nsROCSSPrimitiveValue* closeVal = GetROCSSPrimitiveValue();
+    if (!closeVal || !valueList->AppendCSSValue(closeVal)) {
+      delete valueList;
+      delete closeVal;
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    nsString s;
+    nsStyleUtil::EscapeCSSString(*quotes->OpenQuoteAt(i), s);
+    s.Insert(PRUnichar('"'), 0);
+    s.Append(PRUnichar('"'));
+    openVal->SetString(s);
+    nsStyleUtil::EscapeCSSString(*quotes->CloseQuoteAt(i), s);
+    s.Insert(PRUnichar('"'), 0);
+    s.Append(PRUnichar('"'));
+    closeVal->SetString(s);
+  }
+
+  return CallQueryInterface(valueList, aValue);
+}
+
+nsresult
 nsComputedDOMStyle::GetFontFamily(nsIDOMCSSValue** aValue)
 {
   nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
   NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
 
   const nsStyleFont* font = GetStyleFont();
 
   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocumentWeak);
@@ -915,16 +1056,61 @@ nsComputedDOMStyle::GetBackgroundOrigin(
                                nsCSSProps::kBackgroundOriginKTable);
 
   val->SetIdent(backgroundOrigin);
 
   return CallQueryInterface(val, aValue);
 }
 
 nsresult
+nsComputedDOMStyle::GetBackgroundPosition(nsIDOMCSSValue** aValue)
+{
+  nsDOMCSSValueList *valueList = GetROCSSValueList(PR_FALSE);
+  NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY);
+
+  nsROCSSPrimitiveValue *valX = GetROCSSPrimitiveValue();
+  if (!valX || !valueList->AppendCSSValue(valX)) {
+    delete valueList;
+    delete valX;
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  nsROCSSPrimitiveValue *valY = GetROCSSPrimitiveValue();
+  if (!valY || !valueList->AppendCSSValue(valY)) {
+    delete valueList;
+    delete valY;
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  const nsStyleBackground *bg = GetStyleBackground();
+
+  if (NS_STYLE_BG_X_POSITION_LENGTH & bg->mBackgroundFlags) {
+    valX->SetAppUnits(bg->mBackgroundXPosition.mCoord);
+  }
+  else if (NS_STYLE_BG_X_POSITION_PERCENT & bg->mBackgroundFlags) {
+    valX->SetPercent(bg->mBackgroundXPosition.mFloat);
+  }
+  else {
+    valX->SetPercent(0.0f);
+  }
+
+  if (NS_STYLE_BG_Y_POSITION_LENGTH & bg->mBackgroundFlags) {
+    valY->SetAppUnits(bg->mBackgroundYPosition.mCoord);
+  }
+  else if (NS_STYLE_BG_Y_POSITION_PERCENT & bg->mBackgroundFlags) {
+    valY->SetPercent(bg->mBackgroundYPosition.mFloat);
+  }
+  else {
+    valY->SetPercent(0.0f);
+  }
+
+  return CallQueryInterface(valueList, aValue);  
+}
+
+nsresult
 nsComputedDOMStyle::GetBackgroundRepeat(nsIDOMCSSValue** aValue)
 {
   nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
   NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
 
   const nsAFlatCString& backgroundRepeat =
     nsCSSProps::ValueToKeyword(GetStyleBackground()->mBackgroundRepeat,
                                nsCSSProps::kBackgroundRepeatKTable);
@@ -1891,16 +2077,27 @@ nsComputedDOMStyle::GetFloatEdge(nsIDOMC
     nsCSSProps::ValueToKeyword(GetStyleBorder()->mFloatEdge,
                                nsCSSProps::kFloatEdgeKTable);
   val->SetIdent(floatEdgeIdent);
 
   return CallQueryInterface(val, aValue);
 }
 
 nsresult
+nsComputedDOMStyle::GetForceBrokenImageIcon(nsIDOMCSSValue** aValue)
+{
+  nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+  NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
+
+  val->SetNumber(GetStyleUIReset()->mForceBrokenImageIcon);
+
+  return CallQueryInterface(val, aValue);
+}
+
+nsresult
 nsComputedDOMStyle::GetIMEMode(nsIDOMCSSValue** aValue)
 {
   nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
   NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
 
   const nsStyleUIReset *uiData = GetStyleUIReset();
 
   nsCSSKeyword keyword;
@@ -2187,16 +2384,50 @@ nsComputedDOMStyle::GetOverflowY(nsIDOMC
   } else {
     val->SetIdent(nsGkAtoms::_auto);
   }
 
   return CallQueryInterface(val, aValue);
 }
 
 nsresult
+nsComputedDOMStyle::GetPageBreakAfter(nsIDOMCSSValue** aValue)
+{
+  nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+  NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
+
+  const nsStyleDisplay *display = GetStyleDisplay();
+
+  if (display->mBreakAfter) {
+    val->SetIdent(nsGkAtoms::always);
+  } else {
+    val->SetIdent(nsGkAtoms::_auto);
+  }
+
+  return CallQueryInterface(val, aValue);
+}
+
+nsresult
+nsComputedDOMStyle::GetPageBreakBefore(nsIDOMCSSValue** aValue)
+{
+  nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+  NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
+
+  const nsStyleDisplay *display = GetStyleDisplay();
+
+  if (display->mBreakBefore) {
+    val->SetIdent(nsGkAtoms::always);
+  } else {
+    val->SetIdent(nsGkAtoms::_auto);
+  }
+
+  return CallQueryInterface(val, aValue);
+}
+
+nsresult
 nsComputedDOMStyle::GetHeight(nsIDOMCSSValue** aValue)
 {
   nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
   NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
 
   PRBool calcHeight = PR_FALSE;
   
   if (mFrame) {
@@ -3397,17 +3628,17 @@ nsComputedDOMStyle::GetQueryableProperty
      * Implementations of CSS2 styles *
     \* ****************************** */
 
     // COMPUTED_STYLE_MAP_ENTRY(azimuth,                    Azimuth),
     //// COMPUTED_STYLE_MAP_ENTRY(background,               Background),
     COMPUTED_STYLE_MAP_ENTRY(background_attachment,         BackgroundAttachment),
     COMPUTED_STYLE_MAP_ENTRY(background_color,              BackgroundColor),
     COMPUTED_STYLE_MAP_ENTRY(background_image,              BackgroundImage),
-    //// COMPUTED_STYLE_MAP_ENTRY(background_position,      BackgroundPosition),
+    COMPUTED_STYLE_MAP_ENTRY(background_position,           BackgroundPosition),
     COMPUTED_STYLE_MAP_ENTRY(background_repeat,             BackgroundRepeat),
     //// COMPUTED_STYLE_MAP_ENTRY(border,                   Border),
     //// COMPUTED_STYLE_MAP_ENTRY(border_bottom,            BorderBottom),
     COMPUTED_STYLE_MAP_ENTRY(border_bottom_color,           BorderBottomColor),
     COMPUTED_STYLE_MAP_ENTRY(border_bottom_style,           BorderBottomStyle),
     COMPUTED_STYLE_MAP_ENTRY(border_bottom_width,           BorderBottomWidth),
     COMPUTED_STYLE_MAP_ENTRY(border_collapse,               BorderCollapse),
     //// COMPUTED_STYLE_MAP_ENTRY(border_color,             BorderColor),
@@ -3426,17 +3657,17 @@ nsComputedDOMStyle::GetQueryableProperty
     COMPUTED_STYLE_MAP_ENTRY(border_top_style,              BorderTopStyle),
     COMPUTED_STYLE_MAP_ENTRY(border_top_width,              BorderTopWidth),
     //// COMPUTED_STYLE_MAP_ENTRY(border_width,             BorderWidth),
     COMPUTED_STYLE_MAP_ENTRY(bottom,                        Bottom),
     COMPUTED_STYLE_MAP_ENTRY(caption_side,                  CaptionSide),
     COMPUTED_STYLE_MAP_ENTRY(clear,                         Clear),
     COMPUTED_STYLE_MAP_ENTRY(clip,                          Clip),
     COMPUTED_STYLE_MAP_ENTRY(color,                         Color),
-    // COMPUTED_STYLE_MAP_ENTRY(content,                    Content),
+    COMPUTED_STYLE_MAP_ENTRY(content,                       Content),
     COMPUTED_STYLE_MAP_ENTRY(counter_increment,             CounterIncrement),
     COMPUTED_STYLE_MAP_ENTRY(counter_reset,                 CounterReset),
     //// COMPUTED_STYLE_MAP_ENTRY(cue,                      Cue),
     // COMPUTED_STYLE_MAP_ENTRY(cue_after,                  CueAfter),
     // COMPUTED_STYLE_MAP_ENTRY(cue_before,                 CueBefore),
     COMPUTED_STYLE_MAP_ENTRY(cursor,                        Cursor),
     COMPUTED_STYLE_MAP_ENTRY(direction,                     Direction),
     COMPUTED_STYLE_MAP_ENTRY(display,                       Display),
@@ -3482,26 +3713,26 @@ nsComputedDOMStyle::GetQueryableProperty
     COMPUTED_STYLE_MAP_ENTRY(overflow_x,                    OverflowX),
     COMPUTED_STYLE_MAP_ENTRY(overflow_y,                    OverflowY),
     //// COMPUTED_STYLE_MAP_ENTRY(padding,                  Padding),
     COMPUTED_STYLE_MAP_ENTRY(padding_bottom,                PaddingBottom),
     COMPUTED_STYLE_MAP_ENTRY(padding_left,                  PaddingLeft),
     COMPUTED_STYLE_MAP_ENTRY(padding_right,                 PaddingRight),
     COMPUTED_STYLE_MAP_ENTRY(padding_top,                   PaddingTop),
     // COMPUTED_STYLE_MAP_ENTRY(page,                       Page),
-    // COMPUTED_STYLE_MAP_ENTRY(page_break_after,           PageBreakAfter),
-    // COMPUTED_STYLE_MAP_ENTRY(page_break_before,          PageBreakBefore),
+    COMPUTED_STYLE_MAP_ENTRY(page_break_after,              PageBreakAfter),
+    COMPUTED_STYLE_MAP_ENTRY(page_break_before,             PageBreakBefore),
     // COMPUTED_STYLE_MAP_ENTRY(page_break_inside,          PageBreakInside),
     //// COMPUTED_STYLE_MAP_ENTRY(pause,                    Pause),
     // COMPUTED_STYLE_MAP_ENTRY(pause_after,                PauseAfter),
     // COMPUTED_STYLE_MAP_ENTRY(pause_before,               PauseBefore),
     // COMPUTED_STYLE_MAP_ENTRY(pitch,                      Pitch),
     // COMPUTED_STYLE_MAP_ENTRY(pitch_range,                PitchRange),
     COMPUTED_STYLE_MAP_ENTRY(position,                      Position),
-    // COMPUTED_STYLE_MAP_ENTRY(quotes,                     Quotes),
+    COMPUTED_STYLE_MAP_ENTRY(quotes,                        Quotes),
     // COMPUTED_STYLE_MAP_ENTRY(richness,                   Richness),
     COMPUTED_STYLE_MAP_ENTRY(right,                         Right),
     //// COMPUTED_STYLE_MAP_ENTRY(size,                     Size),
     // COMPUTED_STYLE_MAP_ENTRY(speak,                      Speak),
     // COMPUTED_STYLE_MAP_ENTRY(speak_header,               SpeakHeader),
     // COMPUTED_STYLE_MAP_ENTRY(speak_numeral,              SpeakNumeral),
     // COMPUTED_STYLE_MAP_ENTRY(speak_punctuation,          SpeakPunctuation),
     // COMPUTED_STYLE_MAP_ENTRY(speech_rate,                SpeechRate),
@@ -3547,16 +3778,17 @@ nsComputedDOMStyle::GetQueryableProperty
     COMPUTED_STYLE_MAP_ENTRY(box_ordinal_group,             BoxOrdinalGroup),
     COMPUTED_STYLE_MAP_ENTRY(box_orient,                    BoxOrient),
     COMPUTED_STYLE_MAP_ENTRY(box_pack,                      BoxPack),
     COMPUTED_STYLE_MAP_ENTRY(box_sizing,                    BoxSizing),
     COMPUTED_STYLE_MAP_ENTRY(_moz_column_count,             ColumnCount),
     COMPUTED_STYLE_MAP_ENTRY(_moz_column_width,             ColumnWidth),
     COMPUTED_STYLE_MAP_ENTRY(_moz_column_gap,               ColumnGap),
     COMPUTED_STYLE_MAP_ENTRY(float_edge,                    FloatEdge),
+    COMPUTED_STYLE_MAP_ENTRY(force_broken_image_icon,  ForceBrokenImageIcon),
     COMPUTED_STYLE_MAP_ENTRY(image_region,                  ImageRegion),
     COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_bottomLeft, OutlineRadiusBottomLeft),
     COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_bottomRight,OutlineRadiusBottomRight),
     COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_topLeft,    OutlineRadiusTopLeft),
     COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_topRight,   OutlineRadiusTopRight),
     COMPUTED_STYLE_MAP_ENTRY(user_focus,                    UserFocus),
     COMPUTED_STYLE_MAP_ENTRY(user_input,                    UserInput),
     COMPUTED_STYLE_MAP_ENTRY(user_modify,                   UserModify),
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -142,16 +142,17 @@ private:
   nsresult GetFontSizeAdjust(nsIDOMCSSValue** aValue);
   nsresult GetFontWeight(nsIDOMCSSValue** aValue);
   nsresult GetFontVariant(nsIDOMCSSValue** aValue);
 
   /* Background properties */
   nsresult GetBackgroundAttachment(nsIDOMCSSValue** aValue);
   nsresult GetBackgroundColor(nsIDOMCSSValue** aValue);
   nsresult GetBackgroundImage(nsIDOMCSSValue** aValue);
+  nsresult GetBackgroundPosition(nsIDOMCSSValue** aValue);
   nsresult GetBackgroundRepeat(nsIDOMCSSValue** aValue);
   nsresult GetBackgroundClip(nsIDOMCSSValue** aValue);
   nsresult GetBackgroundInlinePolicy(nsIDOMCSSValue** aValue);
   nsresult GetBackgroundOrigin(nsIDOMCSSValue** aValue);
 
   /* Padding properties */
   nsresult GetPadding(nsIDOMCSSValue** aValue);
   nsresult GetPaddingTop(nsIDOMCSSValue** aValue);
@@ -206,20 +207,24 @@ private:
   nsresult GetOutlineColor(nsIDOMCSSValue** aValue);
   nsresult GetOutlineOffset(nsIDOMCSSValue** aValue);
   nsresult GetOutlineRadiusBottomLeft(nsIDOMCSSValue** aValue);
   nsresult GetOutlineRadiusBottomRight(nsIDOMCSSValue** aValue);
   nsresult GetOutlineRadiusTopLeft(nsIDOMCSSValue** aValue);
   nsresult GetOutlineRadiusTopRight(nsIDOMCSSValue** aValue);
 
   /* Content Properties */
+  nsresult GetContent(nsIDOMCSSValue** aValue);
   nsresult GetCounterIncrement(nsIDOMCSSValue** aValue);
   nsresult GetCounterReset(nsIDOMCSSValue** aValue);
   nsresult GetMarkerOffset(nsIDOMCSSValue** aValue);
 
+  /* Quotes Properties */
+  nsresult GetQuotes(nsIDOMCSSValue** aValue);
+
   /* z-index */
   nsresult GetZIndex(nsIDOMCSSValue** aValue);
 
   /* List properties */
   nsresult GetListStyleImage(nsIDOMCSSValue** aValue);
   nsresult GetListStylePosition(nsIDOMCSSValue** aValue);
   nsresult GetListStyleType(nsIDOMCSSValue** aValue);
   nsresult GetImageRegion(nsIDOMCSSValue** aValue);
@@ -247,19 +252,22 @@ private:
   nsresult GetClear(nsIDOMCSSValue** aValue);
   nsresult GetCssFloat(nsIDOMCSSValue** aValue);
   nsresult GetDisplay(nsIDOMCSSValue** aValue);
   nsresult GetPosition(nsIDOMCSSValue** aValue);
   nsresult GetClip(nsIDOMCSSValue** aValue);
   nsresult GetOverflow(nsIDOMCSSValue** aValue);
   nsresult GetOverflowX(nsIDOMCSSValue** aValue);
   nsresult GetOverflowY(nsIDOMCSSValue** aValue);
+  nsresult GetPageBreakAfter(nsIDOMCSSValue** aValue);
+  nsresult GetPageBreakBefore(nsIDOMCSSValue** aValue);
 
   /* User interface properties */
   nsresult GetCursor(nsIDOMCSSValue** aValue);
+  nsresult GetForceBrokenImageIcon(nsIDOMCSSValue** aValue);
   nsresult GetIMEMode(nsIDOMCSSValue** aValue);
   nsresult GetUserFocus(nsIDOMCSSValue** aValue);
   nsresult GetUserInput(nsIDOMCSSValue** aValue);
   nsresult GetUserModify(nsIDOMCSSValue** aValue);
   nsresult GetUserSelect(nsIDOMCSSValue** aValue);
 
   /* Column properties */
   nsresult GetColumnCount(nsIDOMCSSValue** aValue);
--- a/layout/style/nsROCSSPrimitiveValue.cpp
+++ b/layout/style/nsROCSSPrimitiveValue.cpp
@@ -131,16 +131,17 @@ nsROCSSPrimitiveValue::GetCssText(nsAStr
     case CSS_IDENT :
       {
         const char *atomValue;
         mValue.mAtom->GetUTF8String(&atomValue);
         AppendUTF8toUTF16(atomValue, tmpStr);
         break;
       }
     case CSS_STRING :
+    case CSS_COUNTER : /* FIXME: COUNTER should use an object */
       {
         tmpStr.Append(mValue.mString);
         break;
       }
     case CSS_URI :
       {
         nsXPIDLString uri;
         if (mValue.mURI) {
@@ -150,16 +151,23 @@ nsROCSSPrimitiveValue::GetCssText(nsAStr
                         NS_LITERAL_STRING(")"));
         } else {
           // XXXldb Any better ideas?  It's good to have something that
           // doesn't parse so that things round-trip "correctly".
           tmpStr.Assign(NS_LITERAL_STRING("url(invalid-url:)"));
         }
         break;
       }
+    case CSS_ATTR :
+      {
+        tmpStr.AppendLiteral("attr(");
+        tmpStr.Append(mValue.mString);
+        tmpStr.Append(PRUnichar(')'));
+        break;
+      }
     case CSS_PERCENTAGE :
       {
         tmpStr.AppendFloat(mValue.mFloat * 100);
         tmpStr.Append(PRUnichar('%'));
         break;
       }
     case CSS_NUMBER :
       {
@@ -271,18 +279,16 @@ nsROCSSPrimitiveValue::GetCssText(nsAStr
     case CSS_DEG :
     case CSS_RAD :
     case CSS_GRAD :
     case CSS_MS :
     case CSS_S :
     case CSS_HZ :
     case CSS_KHZ :
     case CSS_DIMENSION :
-    case CSS_ATTR :
-    case CSS_COUNTER :
       NS_ERROR("We have a bogus value set.  This should not happen");
       return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
   if (NS_SUCCEEDED(result)) {
     aCssText.Assign(tmpStr);
   }
 
@@ -408,25 +414,25 @@ nsROCSSPrimitiveValue::SetStringValue(PR
 NS_IMETHODIMP
 nsROCSSPrimitiveValue::GetStringValue(nsAString& aReturn)
 {
   switch (mType) {
     case CSS_IDENT:
       mValue.mAtom->ToString(aReturn);
       break;
     case CSS_STRING:
+    case CSS_ATTR:
       aReturn.Assign(mValue.mString);
       break;
     case CSS_URI: {
       nsCAutoString spec;
       if (mValue.mURI)
         mValue.mURI->GetSpec(spec);
       CopyUTF8toUTF16(spec, aReturn);
       } break;
-    case CSS_ATTR:
     default:
       aReturn.Truncate();
       return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
   return NS_OK;
 }
 
 
--- a/layout/style/nsROCSSPrimitiveValue.h
+++ b/layout/style/nsROCSSPrimitiveValue.h
@@ -42,16 +42,17 @@
 
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsString.h"
 #include "nsCoord.h"
 #include "nsUnitConversion.h"
 #include "nsReadableUtils.h"
 #include "nsIURI.h"
 #include "nsIAtom.h"
+#include "nsCSSKeywords.h"
 
 #include "nsCOMPtr.h"
 #include "nsDOMError.h"
 #include "nsDOMCSSRect.h"
 #include "nsDOMCSSRGBColor.h"
 
 class nsROCSSPrimitiveValue : public nsIDOMCSSPrimitiveValue
 {
@@ -63,16 +64,18 @@ public:
 
   // nsIDOMCSSValue
   NS_DECL_NSIDOMCSSVALUE
 
   // nsROCSSPrimitiveValue
   nsROCSSPrimitiveValue(PRInt32 aAppUnitsPerInch);
   virtual ~nsROCSSPrimitiveValue();
 
+  // FIXME Many of these methods should be out-of-line.
+
   void SetNumber(float aValue)
   {
     Reset();
     mValue.mFloat = aValue;
     mType = CSS_NUMBER;
   }
 
   void SetNumber(PRInt32 aValue)
@@ -111,46 +114,54 @@ public:
   void SetIdent(nsIAtom* aAtom)
   {
     NS_PRECONDITION(aAtom, "Don't pass in a null atom");
     Reset();
     NS_ADDREF(mValue.mAtom = aAtom);
     mType = CSS_IDENT;
   }
 
+  // FIXME More callers should use this variant.
+  void SetIdent(nsCSSKeyword aKeyword)
+  {
+    SetIdent(nsCSSKeywords::GetStringValue(aKeyword));
+  }
+
   void SetIdent(const nsACString& aString)
   {
     Reset();
     mValue.mAtom = NS_NewAtom(aString);
     if (mValue.mAtom) {
       mType = CSS_IDENT;
     } else {
       // XXXcaa We should probably let the caller know we are out of memory
       mType = CSS_UNKNOWN;
     }
   }
 
-  void SetString(const nsACString& aString)
+  // FIXME: CSS_STRING should imply a string with "" and a need for escaping.
+  void SetString(const nsACString& aString, PRUint16 aType = CSS_STRING)
   {
     Reset();
     mValue.mString = ToNewUnicode(aString);
     if (mValue.mString) {
-      mType = CSS_STRING;
+      mType = aType;
     } else {
       // XXXcaa We should probably let the caller know we are out of memory
       mType = CSS_UNKNOWN;
     }
   }
 
-  void SetString(const nsAString& aString)
+  // FIXME: CSS_STRING should imply a string with "" and a need for escaping.
+  void SetString(const nsAString& aString, PRUint16 aType = CSS_STRING)
   {
     Reset();
     mValue.mString = ToNewUnicode(aString);
     if (mValue.mString) {
-      mType = CSS_STRING;
+      mType = aType;
     } else {
       // XXXcaa We should probably let the caller know we are out of memory
       mType = CSS_UNKNOWN;
     }
   }
 
   void SetURI(nsIURI *aURI)
   {
@@ -191,16 +202,18 @@ public:
   void Reset(void)
   {
     switch (mType) {
       case CSS_IDENT:
         NS_ASSERTION(mValue.mAtom, "Null atom should never happen");
         NS_RELEASE(mValue.mAtom);
         break;
       case CSS_STRING:
+      case CSS_ATTR:
+      case CSS_COUNTER: // FIXME: Counter should use an object
         NS_ASSERTION(mValue.mString, "Null string should never happen");
         nsMemory::Free(mValue.mString);
         mValue.mString = nsnull;
         break;
       case CSS_URI:
         NS_IF_RELEASE(mValue.mURI);
         break;
       case CSS_RECT:
@@ -221,16 +234,16 @@ private:
 
   union {
     nscoord         mAppUnits;
     float           mFloat;
     nsDOMCSSRGBColor* mColor;
     nsIDOMRect*     mRect;
     PRUnichar*      mString;
     nsIURI*         mURI;
-    nsIAtom*        mAtom;
+    nsIAtom*        mAtom; // FIXME use nsCSSKeyword instead
   } mValue;
   
   PRInt32 mAppUnitsPerInch;
 };
 
 #endif /* nsROCSSPrimitiveValue_h___ */
 
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -2766,21 +2766,42 @@ nsRuleNode::ComputeDisplayData(nsStyleSt
     display->mBreakType = NS_STYLE_CLEAR_NONE;
   }
   else if (eCSSUnit_Inherit == displayData.mClear.GetUnit()) {
     inherited = PR_TRUE;
     display->mBreakType = parentDisplay->mBreakType;
   }
 
   // temp fix for bug 24000
+  // Map 'auto' and 'avoid' to PR_FALSE, and 'always', 'left', and
+  // 'right' to PR_TRUE.
+  // "A conforming user agent may interpret the values 'left' and
+  // 'right' as 'always'." - CSS2.1, section 13.3.1
   if (eCSSUnit_Enumerated == displayData.mBreakBefore.GetUnit()) {
-    display->mBreakBefore = (NS_STYLE_PAGE_BREAK_ALWAYS == displayData.mBreakBefore.GetIntValue());
-  }
+    display->mBreakBefore = (NS_STYLE_PAGE_BREAK_AVOID != displayData.mBreakBefore.GetIntValue());
+  }
+  else if (eCSSUnit_Auto == displayData.mBreakBefore.GetUnit() ||
+           eCSSUnit_Initial == displayData.mBreakBefore.GetUnit()) {
+    display->mBreakBefore = PR_FALSE;
+  }
+  else if (eCSSUnit_Inherit == displayData.mBreakBefore.GetUnit()) {
+    inherited = PR_TRUE;
+    display->mBreakBefore = parentDisplay->mBreakBefore;
+  }
+
   if (eCSSUnit_Enumerated == displayData.mBreakAfter.GetUnit()) {
-    display->mBreakAfter = (NS_STYLE_PAGE_BREAK_ALWAYS == displayData.mBreakAfter.GetIntValue());
+    display->mBreakAfter = (NS_STYLE_PAGE_BREAK_AVOID != displayData.mBreakAfter.GetIntValue());
+  }
+  else if (eCSSUnit_Auto == displayData.mBreakAfter.GetUnit() ||
+           eCSSUnit_Initial == displayData.mBreakAfter.GetUnit()) {
+    display->mBreakAfter = PR_FALSE;
+  }
+  else if (eCSSUnit_Inherit == displayData.mBreakAfter.GetUnit()) {
+    inherited = PR_TRUE;
+    display->mBreakAfter = parentDisplay->mBreakAfter;
   }
   // end temp fix
 
   // float: enum, none, inherit
   if (eCSSUnit_Enumerated == displayData.mFloat.GetUnit()) {
     display->mFloats = displayData.mFloat.GetIntValue();
   }
   else if (eCSSUnit_None == displayData.mFloat.GetUnit()) {
--- a/layout/style/test/test_compute_data_with_start_struct.html
+++ b/layout/style/test/test_compute_data_with_start_struct.html
@@ -16,34 +16,28 @@
 </p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 var gNoComputedStyle = {
-  "-moz-force-broken-image-icon": true,
   "-moz-border-end": true, // NB: shorthand
   "-moz-border-end-color": true,
   "-moz-border-end-style": true,
   "-moz-border-end-width": true,
   "-moz-border-start": true, // NB: shorthand
   "-moz-border-start-color": true,
   "-moz-border-start-style": true,
   "-moz-border-start-width": true,
   "-moz-margin-end": true,
   "-moz-margin-start": true,
   "-moz-padding-end": true,
   "-moz-padding-start": true,
-  "background-position": true,
-  "content": true,
-  "page-break-after": true,
-  "page-break-before": true,
-  "quotes": true,
 };
 
 var gXFailComputed = {
   // The initial value of -moz-user-select can't be specified and isn't
   // serialized correctly.
   "-moz-user-select": true
 };
 
--- a/layout/style/test/test_inherit_computation.html
+++ b/layout/style/test/test_inherit_computation.html
@@ -18,34 +18,28 @@
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for computation of CSS 'inherit' **/
 
 var gNoComputedStyle = {
-  "-moz-force-broken-image-icon": true,
   "-moz-border-end": true, // NB: shorthand
   "-moz-border-end-color": true,
   "-moz-border-end-style": true,
   "-moz-border-end-width": true,
   "-moz-border-start": true, // NB: shorthand
   "-moz-border-start-color": true,
   "-moz-border-start-style": true,
   "-moz-border-start-width": true,
   "-moz-margin-end": true,
   "-moz-margin-start": true,
   "-moz-padding-end": true,
   "-moz-padding-start": true,
-  "background-position": true,
-  "content": true,
-  "page-break-after": true,
-  "page-break-before": true,
-  "quotes": true,
 };
 
 function xfail_diffcomputed(property) {
   return property in gNoComputedStyle;
 }
 
 var gBrokenInherit = {
   // Not implemented in nsRuleNode
--- a/layout/style/test/test_initial_computation.html
+++ b/layout/style/test/test_initial_computation.html
@@ -31,34 +31,28 @@
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for computation of CSS '-moz-initial' **/
 
 var gNoComputedStyle = {
-  "-moz-force-broken-image-icon": true,
   "-moz-border-end": true, // NB: shorthand
   "-moz-border-end-color": true,
   "-moz-border-end-style": true,
   "-moz-border-end-width": true,
   "-moz-border-start": true, // NB: shorthand
   "-moz-border-start-color": true,
   "-moz-border-start-style": true,
   "-moz-border-start-width": true,
   "-moz-margin-end": true,
   "-moz-margin-start": true,
   "-moz-padding-end": true,
   "-moz-padding-start": true,
-  "background-position": true,
-  "content": true,
-  "page-break-after": true,
-  "page-break-before": true,
-  "quotes": true,
 };
 
 function xfail_diffcomputed(property) {
   return property in gNoComputedStyle;
 }
 
 var gBrokenInitial = {
   // Presumably either not parsed or not implemented in nsRuleNode.
@@ -126,16 +120,17 @@ var gBrokenInitial = {
   "outline-width": true,
   "overflow": true,
   "padding": true,
   "padding-bottom": true,
   "padding-left": true,
   "padding-right": true,
   "padding-top": true,
   "position": true,
+  "quotes": true,
   "right": true,
   "table-layout": true,
   "text-decoration": true,
   "text-indent": true,
   "text-transform": true,
   "top": true,
   "unicode-bidi": true,
   "vertical-align": true,
--- a/layout/style/test/test_value_computation.html
+++ b/layout/style/test/test_value_computation.html
@@ -31,74 +31,61 @@
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for computation of values in property database **/
 
 var gNoComputedStyle = {
-  "-moz-force-broken-image-icon": true,
   "-moz-border-end": true, // NB: shorthand
   "-moz-border-end-color": true,
   "-moz-border-end-style": true,
   "-moz-border-end-width": true,
   "-moz-border-start": true, // NB: shorthand
   "-moz-border-start-color": true,
   "-moz-border-start-style": true,
   "-moz-border-start-width": true,
   "-moz-margin-end": true,
   "-moz-margin-start": true,
   "-moz-padding-end": true,
   "-moz-padding-start": true,
-  "background-position": true,
-  "content": true,
-  "page-break-after": true,
-  "page-break-before": true,
-  "quotes": true,
 };
 
 function xfail_diffcomputed(property) {
   return property in gNoComputedStyle;
 }
 
 var gNotAccepted = {
   "-moz-column-width": [ "50%" ],
   "-moz-user-select": [ "auto" ],
   "background-color": [ "rgb(255.0,0.387,3489)" ],
   "list-style": [ "none disc outside" ],
 };
 
-var gBackgroundValuesWithOnlyPosition = {
-  "top": true,
-  "left": true,
-  "50% 50%": true,
-  "center": true,
-  "bottom right scroll none transparent repeat": true,
-  "50% transparent": true,
-  "transparent 50%": true,
-  "50%": true,
-};
-
 var gBadComputed = {
   // NS_STYLE_COLUMN_COUNT_AUTO is 0
   "-moz-column-count": [ "0" ],
 
   "clip": [ "rect(auto,auto,auto,auto)" ],
 
   // No idea what's happening for these two either
   "border-top": [ "thin" ],
   "border-right": [ "thin" ],
   "border-bottom": [ "thin" ],
   "border-left": [ "thin" ],
   "outline-width": [ "3px" ],
 
   // 'normal' should compute to 0
   "word-spacing": [ "0", "0px", "-0em" ],
 
+  // These values are treated as auto.
+  "page-break-after": [ "avoid" ],
+  "page-break-before": [ "avoid" ],
+
   // These are probably bogus tests...
   "-moz-outline-radius": [ "0%" ],
   "-moz-outline-radius-bottomleft": [ "0%" ],
   "-moz-outline-radius-bottomright": [ "0%" ],
   "-moz-outline-radius-topleft": [ "0%" ],
   "-moz-outline-radius-topright": [ "0%" ],
 };
 
@@ -127,20 +114,16 @@ function xfail_value(property, value, is
   if ((property in gBadComputed) &&
       gBadComputed[property].indexOf(value) != -1)
     return true;
 
   if (!has_frame && (property in gBadComputedNoFrame) &&
       gBadComputedNoFrame[property].indexOf(value) != -1)
     return true;
 
-  // One subproperty of 'background' is in gNoComputedStyle
-  if (property == "background" && value in gBackgroundValuesWithOnlyPosition)
-    return true;
-
   return false;
 }
 
 function xfail_empty(property, value) {
   if ((property in gNoComputedStyle) &&
       !("subproperties" in gCSSProperties[property]))
     return true;
 
--- a/layout/style/test/test_value_storage.html
+++ b/layout/style/test/test_value_storage.html
@@ -53,18 +53,16 @@ var gShorthandsWithoutCondensingSerializ
   "cue": true,
   "font": true,
   "list-style": true,
   "outline": true,
   "pause": true,
 };
 
 var gNoComputedValue = {
-  "background-position": true,
-  "content": true,
 };
 
 var gNotAccepted = {
   "-moz-column-width": [ "50%" ],
   "-moz-user-select": [ "auto" ],
   "background-color": [ "rgb(255.0,0.387,3489)" ],
   "list-style": [ "none disc outside" ],
 };