Bug 271586 – Implement CSS3 column-rule-*. r+sr=roc,dbaron
authorMichael Ventnor <ventnor.bugzilla@gmail.com>
Sat, 19 Jul 2008 12:38:25 +0200
changeset 16055 8f3ff19953831e8e44a14b8fbbf8fc22944e9ea9
parent 16054 a4ddc249593bcdad1a901435df3df6226c973f7a
child 16056 df4e95009fdc9f69e4ff114a54c2230de616895a
push id723
push userdgottwald@mozilla.com
push dateSat, 19 Jul 2008 10:38:51 +0000
treeherdermozilla-central@8f3ff1995383 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs271586
milestone1.9.1a1pre
Bug 271586 – Implement CSS3 column-rule-*. r+sr=roc,dbaron
dom/public/idl/css/nsIDOMCSS2Properties.idl
layout/generic/nsColumnSetFrame.cpp
layout/reftests/columns/columnrule-basic-ref.html
layout/reftests/columns/columnrule-basic.html
layout/reftests/columns/columnrule-complex-ref.html
layout/reftests/columns/columnrule-complex.html
layout/reftests/columns/columnrule-linestyles-notref.html
layout/reftests/columns/columnrule-linestyles.html
layout/reftests/columns/reftest.list
layout/style/nsCSSDataBlock.cpp
layout/style/nsCSSDeclaration.cpp
layout/style/nsCSSParser.cpp
layout/style/nsCSSPropList.h
layout/style/nsCSSProps.cpp
layout/style/nsCSSStruct.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleContext.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/nsStyleStructList.h
layout/style/test/property_database.js
layout/style/test/test_dont_use_document_colors.html
layout/style/test/test_inherit_storage.html
layout/style/test/test_initial_storage.html
--- a/dom/public/idl/css/nsIDOMCSS2Properties.idl
+++ b/dom/public/idl/css/nsIDOMCSS2Properties.idl
@@ -401,17 +401,17 @@ interface nsIDOMCSS2Properties : nsISupp
 
            attribute DOMString        wordSpacing;
                                         // raises(DOMException) on setting
 
            attribute DOMString        zIndex;
                                         // raises(DOMException) on setting
 };
 
-[scriptable, uuid(f1781ae4-00e6-4751-8698-2925f925fd76)]
+[scriptable, uuid(5d8aab68-445b-4675-8661-8d722dbcb721)]
 interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties
 {
            /* Non-DOM 2 extensions */
 
            /* Mozilla extension CSS properties */
            attribute DOMString        MozAppearance;
                                         // raises(DOMException) on setting
 
@@ -595,9 +595,20 @@ interface nsIDOMNSCSS2Properties : nsIDO
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozBoxShadow;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozBorderImage;
                                         // raises(DOMException) on setting
 
+           attribute DOMString        MozColumnRule;
+                                        // raises(DOMException) on setting
+
+           attribute DOMString        MozColumnRuleWidth;
+                                        // raises(DOMException) on setting
+
+           attribute DOMString        MozColumnRuleStyle;
+                                        // raises(DOMException) on setting
+
+           attribute DOMString        MozColumnRuleColor;
+                                        // raises(DOMException) on setting
 };
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -44,16 +44,18 @@
 #include "nsISupports.h"
 #include "nsIAtom.h"
 #include "nsPresContext.h"
 #include "nsHTMLParts.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsCOMPtr.h"
 #include "nsLayoutUtils.h"
+#include "nsDisplayList.h"
+#include "nsCSSRendering.h"
 
 class nsColumnSetFrame : public nsHTMLContainerFrame {
 public:
   nsColumnSetFrame(nsStyleContext* aContext);
 
   NS_IMETHOD SetInitialChildList(nsIAtom*        aListName,
                                  nsIFrame*       aChildList);
 
@@ -91,16 +93,20 @@ public:
   }
 
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists);
 
   virtual nsIAtom* GetType() const;
 
+  virtual void PaintColumnRule(nsIRenderingContext* aCtx,
+                               const nsRect&        aDirtyRect,
+                               const nsPoint&       aPt);
+
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const {
     return MakeFrameName(NS_LITERAL_STRING("ColumnSet"), aResult);
   }
 #endif
 
 protected:
   nscoord        mLastBalanceHeight;
@@ -187,16 +193,95 @@ nsColumnSetFrame::nsColumnSetFrame(nsSty
 }
 
 nsIAtom*
 nsColumnSetFrame::GetType() const
 {
   return nsGkAtoms::columnSetFrame;
 }
 
+static void
+PaintColumnRule(nsIFrame* aFrame, nsIRenderingContext* aCtx,
+                const nsRect& aDirtyRect, nsPoint aPt)
+{
+  static_cast<nsColumnSetFrame*>(aFrame)->PaintColumnRule(aCtx, aDirtyRect, aPt);
+}
+
+void
+nsColumnSetFrame::PaintColumnRule(nsIRenderingContext* aCtx,
+                                  const nsRect& aDirtyRect,
+                                  const nsPoint& aPt)
+{
+  nsIFrame* child = mFrames.FirstChild();
+  if (!child)
+    return;  // no columns
+
+  nsIFrame* nextSibling = child->GetNextSibling();
+  if (!nextSibling)
+    return;  // 1 column only - this means no gap to draw on
+
+  PRBool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
+  const nsStyleColumn* colStyle = GetStyleColumn();
+
+  PRUint8 ruleStyle;
+  // Per spec, inset => ridge and outset => groove
+  if (colStyle->mColumnRuleStyle == NS_STYLE_BORDER_STYLE_INSET)
+    ruleStyle = NS_STYLE_BORDER_STYLE_RIDGE;
+  else if (colStyle->mColumnRuleStyle == NS_STYLE_BORDER_STYLE_OUTSET)
+    ruleStyle = NS_STYLE_BORDER_STYLE_GROOVE;
+  else
+    ruleStyle = colStyle->mColumnRuleStyle;
+
+  nsPresContext* presContext = PresContext();
+  nscoord ruleWidth = colStyle->GetComputedColumnRuleWidth();
+  if (!ruleWidth)
+    return;
+
+  nscolor ruleColor;
+  if (colStyle->mColumnRuleColorIsForeground)
+    ruleColor = GetStyleColor()->mColor;
+  else
+    ruleColor = colStyle->mColumnRuleColor;
+
+  // In order to re-use a large amount of code, we treat the column rule as a border.
+  // We create a new border style object and fill in all the details of the column rule as
+  // the left border. PaintBorder() does all the rendering for us, so we not
+  // only save an enormous amount of code but we'll support all the line styles that
+  // we support on borders!
+  nsStyleBorder border(presContext);
+  border.SetBorderWidth(NS_SIDE_LEFT, ruleWidth);
+  border.SetBorderStyle(NS_SIDE_LEFT, ruleStyle);
+  border.SetBorderColor(NS_SIDE_LEFT, ruleColor);
+
+  while (nextSibling) {
+    // The frame tree goes RTL in RTL
+    nsIFrame* leftSibling = isRTL ? nextSibling : child;
+    nsIFrame* rightSibling = isRTL ? child : nextSibling;
+
+    // Each child frame's position coordinates is actually relative to this nsColumnSetFrame.
+    // linePt will be at the top-left edge to paint the line.
+    nsPoint edgeOfLeftSibling = leftSibling->GetRect().TopRight() + aPt;
+    nsPoint edgeOfRightSibling = rightSibling->GetRect().TopLeft() + aPt;
+    nsPoint linePt((edgeOfLeftSibling.x + edgeOfRightSibling.x - ruleWidth) / 2,
+                   edgeOfLeftSibling.y);
+
+    nscoord minimumHeight = PR_MIN(nsLayoutUtils::CalculateContentBottom(child),
+                                   nsLayoutUtils::CalculateContentBottom(nextSibling));
+    nsRect lineRect(linePt, nsSize(ruleWidth, minimumHeight));
+
+    nsCSSRendering::PaintBorder(presContext, *aCtx, this, aDirtyRect,
+                                lineRect, border, GetStyleContext(),
+                                // Remember, we only have the "left" "border". Skip everything else
+                                (1 << NS_SIDE_TOP | 1 << NS_SIDE_RIGHT | 1 << NS_SIDE_BOTTOM));
+
+    child = nextSibling;
+    nextSibling = nextSibling->GetNextSibling();
+  }
+}
+
 NS_IMETHODIMP
 nsColumnSetFrame::SetInitialChildList(nsIAtom*        aListName,
                                       nsIFrame*       aChildList)
 {
   NS_ASSERTION(!aListName, "Only default child list supported");
   NS_ASSERTION(aChildList && !aChildList->GetNextSibling(),
                "initial child list must have exactly one child");
   // Queue up the frames for the content frame
@@ -920,16 +1005,19 @@ nsColumnSetFrame::Reflow(nsPresContext* 
 }
 
 NS_IMETHODIMP
 nsColumnSetFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                    const nsRect&           aDirtyRect,
                                    const nsDisplayListSet& aLists) {
   nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
   NS_ENSURE_SUCCESS(rv, rv);
+
+  aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
+      nsDisplayGeneric(this, ::PaintColumnRule, "ColumnRule"));
   
   nsIFrame* kid = mFrames.FirstChild();
   // Our children won't have backgrounds so it doesn't matter where we put them.
   while (kid) {
     nsresult rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
     NS_ENSURE_SUCCESS(rv, rv);
     kid = kid->GetNextSibling();
   }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnrule-basic-ref.html
@@ -0,0 +1,2 @@
+<div style="position: absolute; top: 20px; left: 517px; width: 6px; background-color: red; height: 100px;"></div>
+<div style="position: absolute; top: 20px; left: 20px; -moz-column-count:2; -moz-column-gap: 0px;"><div style="height:200px; width: 500px;">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed feugiat libero vel diam. Pellentesque pulvinar commodo lacus. Sed fringilla. Sed lectus. Praesent laoreet orci vitae nisi. Duis venenatis tristique massa. Sed commodo diam at mauris.</div></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnrule-basic.html
@@ -0,0 +1,1 @@
+<div style="position: absolute; top: 20px; left: 20px; -moz-column-count:2; -moz-column-gap: 0px; -moz-column-rule: 6px red solid;"><div style="height:200px; width: 500px;">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed feugiat libero vel diam. Pellentesque pulvinar commodo lacus. Sed fringilla. Sed lectus. Praesent laoreet orci vitae nisi. Duis venenatis tristique massa. Sed commodo diam at mauris.</div></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnrule-complex-ref.html
@@ -0,0 +1,4 @@
+<div style="position: absolute; top: 20px; left: 317px; width: 6px; background-color: red; height: 50px;"></div>
+<div style="position: absolute; top: 20px; left: 617px; width: 6px; background-color: red; height: 50px;"></div>
+<div style="position: absolute; top: 20px; left: 917px; width: 6px; background-color: red; height: 50px;"></div>
+<div style="position: absolute; top: 20px; left: 20px; -moz-column-count:4; -moz-column-gap: 0px;"><div style="height:200px; width: 300px;">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed feugiat libero vel diam. Pellentesque pulvinar commodo lacus. Sed fringilla. Sed lectus. Praesent laoreet orci vitae nisi. Duis venenatis tristique massa.</div></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnrule-complex.html
@@ -0,0 +1,1 @@
+<div style="position: absolute; top: 20px; left: 20px; -moz-column-count:4; -moz-column-gap: 0px; -moz-column-rule: 6px red solid;"><div style="height:200px; width: 300px;">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed feugiat libero vel diam. Pellentesque pulvinar commodo lacus. Sed fringilla. Sed lectus. Praesent laoreet orci vitae nisi. Duis venenatis tristique massa.</div></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnrule-linestyles-notref.html
@@ -0,0 +1,1 @@
+<div style="-moz-column-count:2; -moz-column-gap: 3px; -moz-column-rule: 6px red solid;"><div style="height:100px; width: 300px;">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed feugiat libero vel diam. Pellentesque pulvinar commodo lacus. Sed fringilla. Sed lectus. Praesent laoreet orci vitae nisi. Duis venenatis tristique massa. Sed commodo diam at mauris.</div></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/columns/columnrule-linestyles.html
@@ -0,0 +1,2 @@
+<!-- Make sure no-one regresses line styles on column rules -->
+<div style="-moz-column-count:2; -moz-column-gap: 3px; -moz-column-rule: 6px red dotted;"><div style="height:100px; width: 300px;">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed feugiat libero vel diam. Pellentesque pulvinar commodo lacus. Sed fringilla. Sed lectus. Praesent laoreet orci vitae nisi. Duis venenatis tristique massa. Sed commodo diam at mauris.</div></div>
--- a/layout/reftests/columns/reftest.list
+++ b/layout/reftests/columns/reftest.list
@@ -11,8 +11,11 @@
 == column-balancing-overflow-003.html column-balancing-overflow-003.ref.html
 == column-balancing-overflow-004.html column-balancing-overflow-004.ref.html
 == column-balancing-overflow-005.html column-balancing-overflow-005.ref.html
 == column-balancing-000.html column-balancing-000.ref.html
 == column-balancing-001.html column-balancing-000.ref.html
 == column-balancing-002.html column-balancing-002.ref.html
 == column-balancing-003.html column-balancing-000.ref.html
 == column-balancing-004.html column-balancing-004.ref.html
+== columnrule-basic.html columnrule-basic-ref.html
+== columnrule-complex.html columnrule-complex-ref.html
+!= columnrule-linestyles.html columnrule-linestyles-notref.html
--- a/layout/style/nsCSSDataBlock.cpp
+++ b/layout/style/nsCSSDataBlock.cpp
@@ -232,16 +232,17 @@ nsCSSCompressedDataBlock::MapRuleInfoInt
                                  iProp == eCSSProperty_border_top_color ||
                                  iProp == eCSSProperty_border_right_color_value ||
                                  iProp == eCSSProperty_border_right_color_ltr_source ||
                                  iProp == eCSSProperty_border_right_color_rtl_source ||
                                  iProp == eCSSProperty_border_bottom_color ||
                                  iProp == eCSSProperty_border_left_color_value ||
                                  iProp == eCSSProperty_border_left_color_ltr_source ||
                                  iProp == eCSSProperty_border_left_color_rtl_source ||
+                                 iProp == eCSSProperty__moz_column_rule_color ||
                                  iProp == eCSSProperty_outline_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 &&
--- a/layout/style/nsCSSDeclaration.cpp
+++ b/layout/style/nsCSSDeclaration.cpp
@@ -573,16 +573,17 @@ nsCSSDeclaration::GetValue(nsCSSProperty
       // XXX More consistency checking needed before falling through.
       aProperty = eCSSProperty_border_top;
     case eCSSProperty_border_top:
     case eCSSProperty_border_right:
     case eCSSProperty_border_bottom:
     case eCSSProperty_border_left:
     case eCSSProperty_border_start:
     case eCSSProperty_border_end:
+    case eCSSProperty__moz_column_rule:
     case eCSSProperty_outline: {
       const nsCSSProperty* subprops =
         nsCSSProps::SubpropertyEntryFor(aProperty);
       NS_ASSERTION(nsCSSProps::kTypeTable[subprops[0]] == eCSSType_Value &&
                    nsCSSProps::kTypeTable[subprops[1]] == eCSSType_Value &&
                    nsCSSProps::kTypeTable[subprops[2]] == eCSSType_Value,
                    "type mismatch");
       if (!AppendValueToString(subprops[0], aValue) ||
@@ -1118,16 +1119,17 @@ nsCSSDeclaration::ToString(nsAString& aS
   PRInt32 borderRightWidth = 0, borderRightStyle = 0, borderRightColor = 0;
   PRInt32 borderStartWidth = 0, borderStartStyle = 0, borderStartColor = 0;
   PRInt32 borderEndWidth = 0, borderEndStyle = 0, borderEndColor = 0;
   PRInt32 marginTop = 0,  marginBottom = 0,  marginLeft = 0,  marginRight = 0;
   PRInt32 paddingTop = 0, paddingBottom = 0, paddingLeft = 0, paddingRight = 0;
   PRInt32 bgColor = 0, bgImage = 0, bgRepeat = 0, bgAttachment = 0;
   PRInt32 bgPosition = 0;
   PRInt32 overflowX = 0, overflowY = 0;
+  PRInt32 columnRuleWidth = 0, columnRuleStyle = 0, columnRuleColor = 0;
   PRUint32 borderPropertiesSet = 0, finalBorderPropertiesToSet = 0;
 #ifdef MOZ_SVG
   PRInt32 markerEnd = 0, markerMid = 0, markerStart = 0;
 #endif
 
   for (index = 0; index < count; index++) {
     nsCSSProperty property = OrderValueAt(index);
     switch (property) {
@@ -1202,16 +1204,20 @@ nsCSSDeclaration::ToString(nsAString& aS
       case eCSSProperty_background_image:      bgImage       = index+1; break;
       case eCSSProperty_background_repeat:     bgRepeat      = index+1; break;
       case eCSSProperty_background_attachment: bgAttachment  = index+1; break;
       case eCSSProperty_background_position:   bgPosition    = index+1; break;
 
       case eCSSProperty_overflow_x:            overflowX     = index+1; break;
       case eCSSProperty_overflow_y:            overflowY     = index+1; break;
 
+      case eCSSProperty__moz_column_rule_width: columnRuleWidth = index+1; break;
+      case eCSSProperty__moz_column_rule_style: columnRuleStyle = index+1; break;
+      case eCSSProperty__moz_column_rule_color: columnRuleColor = index+1; break;
+
 #ifdef MOZ_SVG
       case eCSSProperty_marker_end:            markerEnd     = index+1; break;
       case eCSSProperty_marker_mid:            markerMid     = index+1; break;
       case eCSSProperty_marker_start:          markerStart   = index+1; break;
 #endif
 
       default: break;
     }
@@ -1280,16 +1286,23 @@ nsCSSDeclaration::ToString(nsAString& aS
                         PR_TRUE);
   TryBackgroundShorthand(aString,
                          bgColor, bgImage, bgRepeat, bgAttachment,
                          bgPosition);
   TryOverflowShorthand(aString, overflowX, overflowY);
 #ifdef MOZ_SVG
   TryMarkerShorthand(aString, markerEnd, markerMid, markerStart);
 #endif
+
+  if (columnRuleColor && columnRuleStyle && columnRuleWidth) {
+    TryBorderSideShorthand(aString, eCSSProperty__moz_column_rule,
+                           columnRuleWidth, columnRuleStyle, columnRuleColor);
+    columnRuleWidth = columnRuleStyle = columnRuleColor = 0;
+  }
+
   // FIXME The order of the declarations should depend on the *-source
   // properties.
   if (borderStartWidth && borderStartStyle && borderStartColor &&
       TryBorderSideShorthand(aString, eCSSProperty_border_start,
                              borderStartWidth, borderStartStyle, borderStartColor))
     borderStartWidth = borderStartStyle = borderStartColor = 0;
   if (borderEndWidth && borderEndStyle && borderEndColor &&
       TryBorderSideShorthand(aString, eCSSProperty_border_end,
@@ -1369,16 +1382,20 @@ nsCSSDeclaration::ToString(nsAString& aS
       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_overflow_y, overflowY)
 
 #ifdef MOZ_SVG
       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_marker_end, markerEnd)
       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_marker_mid, markerMid)
       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_marker_start, markerStart)
 #endif
 
+      NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty__moz_column_rule_width, columnRuleWidth)
+      NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty__moz_column_rule_style, columnRuleStyle)
+      NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty__moz_column_rule_color, columnRuleColor)
+
       case eCSSProperty_margin_left_ltr_source:
       case eCSSProperty_margin_left_rtl_source:
       case eCSSProperty_margin_right_ltr_source:
       case eCSSProperty_margin_right_rtl_source:
       case eCSSProperty_padding_left_ltr_source:
       case eCSSProperty_padding_left_rtl_source:
       case eCSSProperty_padding_right_ltr_source:
       case eCSSProperty_padding_right_rtl_source:
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -3744,16 +3744,21 @@ static const nsCSSProperty kBorderStartI
 static const nsCSSProperty kBorderEndIDs[] = {
   eCSSProperty_border_end_width_value,
   eCSSProperty_border_end_style_value,
   eCSSProperty_border_end_color_value,
   eCSSProperty_border_end_width,
   eCSSProperty_border_end_style,
   eCSSProperty_border_end_color
 };
+static const nsCSSProperty kColumnRuleIDs[] = {
+  eCSSProperty__moz_column_rule_width,
+  eCSSProperty__moz_column_rule_style,
+  eCSSProperty__moz_column_rule_color
+};
 
 PRBool CSSParserImpl::ParseEnum(nsresult& aErrorCode, nsCSSValue& aValue,
                                 const PRInt32 aKeywordTable[])
 {
   nsSubstring* ident = NextIdent(aErrorCode);
   if (nsnull == ident) {
     return PR_FALSE;
   }
@@ -4494,16 +4499,18 @@ PRBool CSSParserImpl::ParseProperty(nsre
                                        NS_BOXPROP_SOURCE_LOGICAL);
   case eCSSProperty__moz_border_radius:
     return ParseBorderRadius(aErrorCode);
   case eCSSProperty__moz_outline_radius:
     return ParseOutlineRadius(aErrorCode);
   case eCSSProperty_clip:
     return ParseRect(mTempData.mDisplay.mClip, aErrorCode,
                      eCSSProperty_clip);
+  case eCSSProperty__moz_column_rule:
+    return ParseBorderSide(aErrorCode, kColumnRuleIDs, PR_FALSE);
   case eCSSProperty_content:
     return ParseContent(aErrorCode);
   case eCSSProperty_counter_increment:
     return ParseCounterData(aErrorCode, &mTempData.mContent.mCounterIncrement,
                             aPropID);
   case eCSSProperty_counter_reset:
     return ParseCounterData(aErrorCode, &mTempData.mContent.mCounterReset,
                             aPropID);
@@ -4676,17 +4683,19 @@ PRBool CSSParserImpl::ParseSingleValuePr
   case eCSSProperty_border_bottom:
   case eCSSProperty_border_end:
   case eCSSProperty_border_left:
   case eCSSProperty_border_right:
   case eCSSProperty_border_start:
   case eCSSProperty_border_top:
   case eCSSProperty_border_width:
   case eCSSProperty__moz_border_radius:
+  case eCSSProperty_box_shadow:
   case eCSSProperty_clip:
+  case eCSSProperty__moz_column_rule:
   case eCSSProperty_content:
   case eCSSProperty_counter_increment:
   case eCSSProperty_counter_reset:
   case eCSSProperty_cue:
   case eCSSProperty_cursor:
   case eCSSProperty_font:
   case eCSSProperty_image_region:
   case eCSSProperty_list_style:
@@ -4702,17 +4711,16 @@ PRBool CSSParserImpl::ParseSingleValuePr
   case eCSSProperty_padding_end:
   case eCSSProperty_padding_left:
   case eCSSProperty_padding_right:
   case eCSSProperty_padding_start:
   case eCSSProperty_pause:
   case eCSSProperty_quotes:
   case eCSSProperty_size:
   case eCSSProperty_text_shadow:
-  case eCSSProperty_box_shadow:
   case eCSSProperty_COUNT:
 #ifdef MOZ_SVG
   case eCSSProperty_fill:
   case eCSSProperty_stroke:
   case eCSSProperty_stroke_dasharray:
   case eCSSProperty_marker:
 #endif
     NS_ERROR("not a single value property");
@@ -4777,32 +4785,35 @@ PRBool CSSParserImpl::ParseSingleValuePr
     return ParseVariant(aErrorCode, aValue, VARIANT_HK,
                         nsCSSProps::kBorderCollapseKTable);
   case eCSSProperty_border_bottom_color:
   case eCSSProperty_border_end_color_value: // for internal use
   case eCSSProperty_border_left_color_value: // for internal use
   case eCSSProperty_border_right_color_value: // for internal use
   case eCSSProperty_border_start_color_value: // for internal use
   case eCSSProperty_border_top_color:
+  case eCSSProperty__moz_column_rule_color:
     return ParseVariant(aErrorCode, aValue, VARIANT_HCK, 
                         nsCSSProps::kBorderColorKTable);
   case eCSSProperty_border_bottom_style:
   case eCSSProperty_border_end_style_value: // for internal use
   case eCSSProperty_border_left_style_value: // for internal use
   case eCSSProperty_border_right_style_value: // for internal use
   case eCSSProperty_border_start_style_value: // for internal use
   case eCSSProperty_border_top_style:
+  case eCSSProperty__moz_column_rule_style:
     return ParseVariant(aErrorCode, aValue, VARIANT_HOK,
                         nsCSSProps::kBorderStyleKTable);
   case eCSSProperty_border_bottom_width:
   case eCSSProperty_border_end_width_value: // for internal use
   case eCSSProperty_border_left_width_value: // for internal use
   case eCSSProperty_border_right_width_value: // for internal use
   case eCSSProperty_border_start_width_value: // for internal use
   case eCSSProperty_border_top_width:
+  case eCSSProperty__moz_column_rule_width:
     return ParsePositiveVariant(aErrorCode, aValue, VARIANT_HKL,
                                 nsCSSProps::kBorderWidthKTable);
   case eCSSProperty__moz_border_radius_topLeft:
   case eCSSProperty__moz_border_radius_topRight:
   case eCSSProperty__moz_border_radius_bottomRight:
   case eCSSProperty__moz_border_radius_bottomLeft:
     return ParsePositiveVariant(aErrorCode, aValue, VARIANT_HLP, nsnull);
   case eCSSProperty__moz_column_count:
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -371,16 +371,20 @@ CSS_PROP_BORDER(-moz-box-shadow, box_sha
 CSS_PROP_POSITION(-moz-box-sizing, box_sizing, MozBoxSizing, Position, mBoxSizing, eCSSType_Value, kBoxSizingKTable) // XXX bug 3935
 CSS_PROP_TABLEBORDER(caption-side, caption_side, CaptionSide, Table, mCaptionSide, eCSSType_Value, kCaptionSideKTable)
 CSS_PROP_DISPLAY(clear, clear, Clear, Display, mClear, eCSSType_Value, kClearKTable)
 CSS_PROP_DISPLAY(clip, clip, Clip, Display, mClip, eCSSType_Rect, nsnull)
 CSS_PROP_COLOR(color, color, Color, Color, mColor, eCSSType_Value, nsnull)
 CSS_PROP_COLUMN(-moz-column-count, _moz_column_count, MozColumnCount, Column, mColumnCount, eCSSType_Value, nsnull)
 CSS_PROP_COLUMN(-moz-column-width, _moz_column_width, MozColumnWidth, Column, mColumnWidth, eCSSType_Value, nsnull)
 CSS_PROP_COLUMN(-moz-column-gap, _moz_column_gap, MozColumnGap, Column, mColumnGap, eCSSType_Value, nsnull)
+CSS_PROP_SHORTHAND(-moz-column-rule, _moz_column_rule, MozColumnRule)
+CSS_PROP_COLUMN(-moz-column-rule-color, _moz_column_rule_color, MozColumnRuleColor, Column, mColumnRuleColor, eCSSType_Value, nsnull)
+CSS_PROP_COLUMN(-moz-column-rule-style, _moz_column_rule_style, MozColumnRuleStyle, Column, mColumnRuleStyle, eCSSType_Value, kBorderStyleKTable)
+CSS_PROP_COLUMN(-moz-column-rule-width, _moz_column_rule_width, MozColumnRuleWidth, Column, mColumnRuleWidth, eCSSType_Value, kBorderWidthKTable)
 CSS_PROP_CONTENT(content, content, Content, Content, mContent, eCSSType_ValueList, kContentKTable)
 CSS_PROP_CONTENT(counter-increment, counter_increment, CounterIncrement, Content, mCounterIncrement, eCSSType_CounterData, nsnull) // XXX bug 137285
 CSS_PROP_CONTENT(counter-reset, counter_reset, CounterReset, Content, mCounterReset, eCSSType_CounterData, nsnull) // XXX bug 137285
 CSS_PROP_SHORTHAND(cue, cue, Cue)
 CSS_PROP_BACKENDONLY(cue-after, cue_after, CueAfter, Aural, mCueAfter, eCSSType_Value, nsnull)
 CSS_PROP_BACKENDONLY(cue-before, cue_before, CueBefore, Aural, mCueBefore, eCSSType_Value, nsnull)
 CSS_PROP_USERINTERFACE(cursor, cursor, Cursor, UserInterface, mCursor, eCSSType_ValueList, kCursorKTable)
 CSS_PROP_VISIBILITY(direction, direction, Direction, Display, mDirection, eCSSType_Value, kDirectionKTable)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1597,16 +1597,23 @@ static const nsCSSProperty gMozMarginEnd
 static const nsCSSProperty gOutlineSubpropTable[] = {
   // nsCSSDeclaration.cpp outputs the subproperties in this order.
   eCSSProperty_outline_color,
   eCSSProperty_outline_style,
   eCSSProperty_outline_width,
   eCSSProperty_UNKNOWN
 };
 
+static const nsCSSProperty gMozColumnRuleSubpropTable[] = {
+  eCSSProperty__moz_column_rule_width,
+  eCSSProperty__moz_column_rule_style,
+  eCSSProperty__moz_column_rule_color,
+  eCSSProperty_UNKNOWN
+};
+
 static const nsCSSProperty gOverflowSubpropTable[] = {
   eCSSProperty_overflow_x,
   eCSSProperty_overflow_y,
   eCSSProperty_UNKNOWN
 };
 
 static const nsCSSProperty gPaddingSubpropTable[] = {
   // Code relies on these being in top-right-bottom-left order.
--- a/layout/style/nsCSSStruct.h
+++ b/layout/style/nsCSSStruct.h
@@ -563,16 +563,19 @@ private:
 
 struct nsCSSColumn : public nsCSSStruct  {
   nsCSSColumn(void);
   ~nsCSSColumn(void);
 
   nsCSSValue  mColumnCount;
   nsCSSValue  mColumnWidth;
   nsCSSValue  mColumnGap;
+  nsCSSValue  mColumnRuleColor;
+  nsCSSValue  mColumnRuleWidth;
+  nsCSSValue  mColumnRuleStyle;
 private:
   nsCSSColumn(const nsCSSColumn& aOther); // NOT IMPLEMENTED
 };
 
 struct nsRuleDataColumn : public nsCSSColumn {
   nsRuleDataColumn() {}
 private:
   nsRuleDataColumn(const nsRuleDataColumn& aOther); // NOT IMPLEMENTED
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -608,16 +608,65 @@ nsComputedDOMStyle::GetColumnGap(nsIDOMC
   } else {
     SetValueToCoord(val, GetStyleColumn()->mColumnGap);
   }
 
   return CallQueryInterface(val, aValue);
 }
 
 nsresult
+nsComputedDOMStyle::GetColumnRuleWidth(nsIDOMCSSValue** aValue)
+{
+  nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+  if (!val)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  SetValueToCoord(val, GetStyleColumn()->GetComputedColumnRuleWidth());
+  return CallQueryInterface(val, aValue);
+}
+
+nsresult
+nsComputedDOMStyle::GetColumnRuleStyle(nsIDOMCSSValue** aValue)
+{
+  nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+  if (!val)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  const nsStyleColumn* column = GetStyleColumn();
+  if (column->mColumnRuleStyle == NS_STYLE_BORDER_STYLE_NONE) {
+    val->SetIdent(nsGkAtoms::none);
+  } else {
+    const nsAFlatCString& style =
+      nsCSSProps::ValueToKeyword(column->mColumnRuleStyle,
+                                 nsCSSProps::kBorderStyleKTable);
+    val->SetIdent(style);
+  }
+  return CallQueryInterface(val, aValue);
+}
+
+nsresult
+nsComputedDOMStyle::GetColumnRuleColor(nsIDOMCSSValue** aValue)
+{
+  nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+  if (!val)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  const nsStyleColumn* column = GetStyleColumn();
+  nscolor ruleColor;
+  if (column->mColumnRuleColorIsForeground) {
+    ruleColor = GetStyleColor()->mColor;
+  } else {
+    ruleColor = column->mColumnRuleColor;
+  }
+
+  SetToRGBAColor(val, ruleColor);
+  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);
@@ -3944,16 +3993,20 @@ 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_shadow,                    BoxShadow),
     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(_moz_column_rule,         ColumnRule),
+    COMPUTED_STYLE_MAP_ENTRY(_moz_column_rule_color,        ColumnRuleColor),
+    COMPUTED_STYLE_MAP_ENTRY(_moz_column_rule_width,        ColumnRuleWidth),
+    COMPUTED_STYLE_MAP_ENTRY(_moz_column_rule_style,        ColumnRuleStyle),
     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(stack_sizing,                  StackSizing),
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -279,16 +279,19 @@ private:
   nsresult GetUserInput(nsIDOMCSSValue** aValue);
   nsresult GetUserModify(nsIDOMCSSValue** aValue);
   nsresult GetUserSelect(nsIDOMCSSValue** aValue);
 
   /* Column properties */
   nsresult GetColumnCount(nsIDOMCSSValue** aValue);
   nsresult GetColumnWidth(nsIDOMCSSValue** aValue);
   nsresult GetColumnGap(nsIDOMCSSValue** aValue);
+  nsresult GetColumnRuleWidth(nsIDOMCSSValue** aValue);
+  nsresult GetColumnRuleStyle(nsIDOMCSSValue** aValue);
+  nsresult GetColumnRuleColor(nsIDOMCSSValue** aValue);
 
 #ifdef MOZ_SVG
   /* SVG properties */
   nsresult GetSVGPaintFor(PRBool aFill, nsIDOMCSSValue** aValue);
 
   nsresult GetFill(nsIDOMCSSValue** aValue);
   nsresult GetStroke(nsIDOMCSSValue** aValue);
   nsresult GetMarkerEnd(nsIDOMCSSValue** aValue);
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -1698,17 +1698,17 @@ nsRuleNode::SetDefaultOnRoot(const nsSty
       if (NS_LIKELY(xul != nsnull)) {
         aContext->SetStyle(eStyleStruct_XUL, xul);
       }
       return xul;
     }
 
     case eStyleStruct_Column:
     {
-      nsStyleColumn* column = new (mPresContext) nsStyleColumn();
+      nsStyleColumn* column = new (mPresContext) nsStyleColumn(mPresContext);
       if (NS_LIKELY(column != nsnull)) {
         aContext->SetStyle(eStyleStruct_Column, column);
       }
       return column;
     }
 
 #ifdef MOZ_SVG
     case eStyleStruct_SVG:
@@ -4707,17 +4707,17 @@ nsRuleNode::ComputeXULData(void* aStartS
 
 const void* 
 nsRuleNode::ComputeColumnData(void* aStartStruct,
                               const nsRuleDataStruct& aData, 
                               nsStyleContext* aContext, 
                               nsRuleNode* aHighestNode,
                               const RuleDetail aRuleDetail, PRBool aInherited)
 {
-  COMPUTE_START_RESET(Column, (), column, parent, Column, columnData)
+  COMPUTE_START_RESET(Column, (mPresContext), column, parent, Column, columnData)
 
   // column-width: length, auto, inherit
   SetCoord(columnData.mColumnWidth,
            column->mColumnWidth, parent->mColumnWidth,
            SETCOORD_LAH | SETCOORD_INITIAL_AUTO,
            aContext, mPresContext, inherited);
 
   // column-gap: length, percentage, inherit, normal
@@ -4734,16 +4734,71 @@ nsRuleNode::ComputeColumnData(void* aSta
     column->mColumnCount = columnData.mColumnCount.GetIntValue();
     // Max 1000 columns - wallpaper for bug 345583.
     column->mColumnCount = PR_MIN(column->mColumnCount, 1000);
   } else if (eCSSUnit_Inherit == columnData.mColumnCount.GetUnit()) {
     inherited = PR_TRUE;
     column->mColumnCount = parent->mColumnCount;
   }
 
+  // column-rule-width: length, enum, inherit
+  const nsCSSValue& widthValue = columnData.mColumnRuleWidth;
+  if (eCSSUnit_Initial == widthValue.GetUnit()) {
+    column->SetColumnRuleWidth(
+        (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
+  }
+  else if (eCSSUnit_Enumerated == widthValue.GetUnit()) {
+    NS_ASSERTION(widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
+                 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
+                 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
+                 "Unexpected enum value");
+    column->SetColumnRuleWidth(
+        (mPresContext->GetBorderWidthTable())[widthValue.GetIntValue()]);
+  }
+  else if (eCSSUnit_Inherit == widthValue.GetUnit()) {
+    column->SetColumnRuleWidth(parent->GetComputedColumnRuleWidth());
+    inherited = PR_TRUE;
+  }
+  else if (widthValue.IsLengthUnit()) {
+    column->SetColumnRuleWidth(CalcLength(widthValue, aContext,
+                                          mPresContext, inherited));
+  }
+
+  // column-rule-style: enum, none, inherit
+  const nsCSSValue& styleValue = columnData.mColumnRuleStyle;
+  if (eCSSUnit_Enumerated == styleValue.GetUnit()) {
+    column->mColumnRuleStyle = styleValue.GetIntValue();
+  }
+  else if (eCSSUnit_None == styleValue.GetUnit() ||
+           eCSSUnit_Initial == styleValue.GetUnit()) {
+    column->mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
+  }
+  else if (eCSSUnit_Inherit == styleValue.GetUnit()) {
+    inherited = PR_TRUE;
+    column->mColumnRuleStyle = parent->mColumnRuleStyle;
+  }
+
+  // column-rule-color: color, inherit
+  const nsCSSValue& colorValue = columnData.mColumnRuleColor;
+  if (eCSSUnit_Inherit == colorValue.GetUnit()) {
+    inherited = PR_TRUE;
+    column->mColumnRuleColorIsForeground = PR_FALSE;
+    if (parent->mColumnRuleColorIsForeground) {
+      column->mColumnRuleColor = parentContext->GetStyleColor()->mColor;
+    } else {
+      column->mColumnRuleColor = parent->mColumnRuleColor;
+    }
+  }
+  else if (eCSSUnit_Initial == colorValue.GetUnit()) {
+    column->mColumnRuleColorIsForeground = PR_TRUE;
+  }
+  else if (SetColor(colorValue, 0, mPresContext, aContext, column->mColumnRuleColor, inherited)) {
+    column->mColumnRuleColorIsForeground = PR_FALSE;
+  }
+
   COMPUTE_END_RESET(Column, column)
 }
 
 #ifdef MOZ_SVG
 static void
 SetSVGPaint(const nsCSSValuePair& aValue, const nsStyleSVGPaint& parentPaint,
             nsPresContext* aPresContext, nsStyleContext *aContext, 
             nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -811,17 +811,21 @@ void nsStyleContext::DumpRegressionData(
   // Column
   IndentBy(out,aIndent);
   const nsStyleColumn* column = GetStyleColumn();
   fprintf(out, "<column data=\"%d ",
     (int)column->mColumnCount);
   column->mColumnWidth.ToString(str);
   fprintf(out, "%s ", NS_ConvertUTF16toUTF8(str).get());
   column->mColumnGap.ToString(str);
-  fprintf(out, "%s", NS_ConvertUTF16toUTF8(str).get());
+  fprintf(out, "%s ", NS_ConvertUTF16toUTF8(str).get());
+  fprintf(out, "%d %d %ld",
+    (int)column->GetComputedColumnRuleWidth(),
+    (int)column->mColumnRuleStyle,
+    (long)column->mColumnRuleColor);
   fprintf(out, "\" />\n");
 
   // XUL
   IndentBy(out,aIndent);
   const nsStyleXUL* xul = GetStyleXUL();
   fprintf(out, "<xul data=\"%d %d %d %d %d %d",
     (int)xul->mBoxAlign,
     (int)xul->mBoxDirection,
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -653,21 +653,28 @@ nsChangeHint nsStyleXUL::MaxDifference()
 {
   return NS_STYLE_HINT_FRAMECHANGE;
 }
 #endif
 
 // --------------------
 // nsStyleColumn
 //
-nsStyleColumn::nsStyleColumn() 
-{ 
+nsStyleColumn::nsStyleColumn(nsPresContext* aPresContext)
+{
   mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
   mColumnWidth.SetAutoValue();
   mColumnGap.SetNormalValue();
+
+  mColumnRuleWidth = (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
+  mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
+  mColumnRuleColor = NS_RGB(0, 0, 0);
+  mColumnRuleColorIsForeground = PR_TRUE;
+
+  mTwipsPerPixel = aPresContext->AppUnitsPerDevPixel();
 }
 
 nsStyleColumn::~nsStyleColumn() 
 {
 }
 
 nsStyleColumn::nsStyleColumn(const nsStyleColumn& aSource)
 {
@@ -677,31 +684,36 @@ nsStyleColumn::nsStyleColumn(const nsSty
 nsChangeHint nsStyleColumn::CalcDifference(const nsStyleColumn& aOther) const
 {
   if ((mColumnWidth.GetUnit() == eStyleUnit_Auto)
       != (aOther.mColumnWidth.GetUnit() == eStyleUnit_Auto) ||
       mColumnCount != aOther.mColumnCount)
     // We force column count changes to do a reframe, because it's tricky to handle
     // some edge cases where the column count gets smaller and content overflows.
     // XXX not ideal
-    return nsChangeHint_ReconstructFrame;
+    return NS_STYLE_HINT_FRAMECHANGE;
 
   if (mColumnWidth != aOther.mColumnWidth ||
       mColumnGap != aOther.mColumnGap)
-    return nsChangeHint_ReflowFrame;
+    return NS_STYLE_HINT_REFLOW;
+
+  if (GetComputedColumnRuleWidth() != aOther.GetComputedColumnRuleWidth() ||
+      mColumnRuleStyle != aOther.mColumnRuleStyle ||
+      mColumnRuleColor != aOther.mColumnRuleColor ||
+      mColumnRuleColorIsForeground != aOther.mColumnRuleColorIsForeground)
+    return NS_STYLE_HINT_VISUAL;
 
   return NS_STYLE_HINT_NONE;
 }
 
 #ifdef DEBUG
 /* static */
 nsChangeHint nsStyleColumn::MaxDifference()
 {
-  return NS_CombineHint(nsChangeHint_ReconstructFrame,
-                        nsChangeHint_ReflowFrame);
+  return NS_STYLE_HINT_FRAMECHANGE;
 }
 #endif
 
 #ifdef MOZ_SVG
 // --------------------
 // nsStyleSVG
 //
 nsStyleSVG::nsStyleSVG() 
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -393,16 +393,23 @@ class nsCSSShadowArray {
 // Outline offset is rounded to the nearest integer number of pixels, but values
 // between zero and one device pixels are always rounded up to one device pixel.
 // Note that the offset can be negative.
 #define NS_ROUND_OFFSET_TO_PIXELS(l,tpp) \
   (((l) == 0) ? 0 : \
     ((l) > 0) ? PR_MAX( (tpp), ((l) + ((tpp) / 2)) / (tpp) * (tpp)) : \
                 PR_MIN(-(tpp), ((l) - ((tpp) / 2)) / (tpp) * (tpp)))
 
+// Returns if the given border style type is visible or not
+static PRBool IsVisibleBorderStyle(PRUint8 aStyle)
+{
+  return (aStyle != NS_STYLE_BORDER_STYLE_NONE &&
+          aStyle != NS_STYLE_BORDER_STYLE_HIDDEN);
+}
+
 struct nsStyleBorder {
   nsStyleBorder(nsPresContext* aContext);
   nsStyleBorder(const nsStyleBorder& aBorder);
   ~nsStyleBorder();
 
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW;
   void Destroy(nsPresContext* aContext);
 
@@ -440,19 +447,17 @@ struct nsStyleBorder {
 
   // Return whether aStyle is a visible style.  Invisible styles cause
   // the relevant computed border width to be 0.
   // Note that this does *not* consider the effects of 'border-image':
   // if border-style is none, but there is a loaded border image,
   // HasVisibleStyle will be false even though there *is* a border.
   PRBool HasVisibleStyle(PRUint8 aSide)
   {
-    PRUint8 style = GetBorderStyle(aSide);
-    return (style != NS_STYLE_BORDER_STYLE_NONE &&
-            style != NS_STYLE_BORDER_STYLE_HIDDEN);
+    return IsVisibleBorderStyle(GetBorderStyle(aSide));
   }
 
   // aBorderWidth is in twips
   void SetBorderWidth(PRUint8 aSide, nscoord aBorderWidth)
   {
     nscoord roundedWidth =
       NS_ROUND_BORDER_TO_PIXELS(aBorderWidth, mTwipsPerPixel);
     mBorder.side(aSide) = roundedWidth;
@@ -1299,17 +1304,17 @@ struct nsStyleXUL {
   PRUint8       mBoxAlign;              // [reset] see nsStyleConsts.h
   PRUint8       mBoxDirection;          // [reset] see nsStyleConsts.h
   PRUint8       mBoxOrient;             // [reset] see nsStyleConsts.h
   PRUint8       mBoxPack;               // [reset] see nsStyleConsts.h
   PRPackedBool  mStretchStack;          // [reset] see nsStyleConsts.h
 };
 
 struct nsStyleColumn {
-  nsStyleColumn();
+  nsStyleColumn(nsPresContext* aPresContext);
   nsStyleColumn(const nsStyleColumn& aSource);
   ~nsStyleColumn();
 
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->AllocateFromShell(sz);
   }
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleColumn();
@@ -1319,16 +1324,32 @@ struct nsStyleColumn {
   nsChangeHint CalcDifference(const nsStyleColumn& aOther) const;
 #ifdef DEBUG
   static nsChangeHint MaxDifference();
 #endif
 
   PRUint32     mColumnCount; // [reset] see nsStyleConsts.h
   nsStyleCoord mColumnWidth; // [reset]
   nsStyleCoord mColumnGap;   // [reset] coord
+
+  nscolor      mColumnRuleColor;  // [reset]
+  PRUint8      mColumnRuleStyle;  // [reset]
+  PRPackedBool mColumnRuleColorIsForeground;
+
+  void SetColumnRuleWidth(nscoord aWidth) {
+    mColumnRuleWidth = NS_ROUND_BORDER_TO_PIXELS(aWidth, mTwipsPerPixel);
+  }
+
+  nscoord GetComputedColumnRuleWidth() const {
+    return (IsVisibleBorderStyle(mColumnRuleStyle) ? mColumnRuleWidth : 0);
+  }
+
+protected:
+  nscoord mColumnRuleWidth;  // [reset] coord
+  nscoord mTwipsPerPixel;
 };
 
 #ifdef MOZ_SVG
 enum nsStyleSVGPaintType {
   eStyleSVGPaintType_None = 1,
   eStyleSVGPaintType_Color,
   eStyleSVGPaintType_Server
 };
--- a/layout/style/nsStyleStructList.h
+++ b/layout/style/nsStyleStructList.h
@@ -148,17 +148,17 @@ STYLE_STRUCT_RESET(XUL, nsnull, ())
   STYLE_STRUCT_TEST_CODE(  if (STYLE_STRUCT_TEST == 20) {)
 STYLE_STRUCT_INHERITED(SVG, nsnull, ())
   STYLE_STRUCT_TEST_CODE(  } else {)
 STYLE_STRUCT_RESET(SVGReset,nsnull, ())
   STYLE_STRUCT_TEST_CODE(  })
   STYLE_STRUCT_TEST_CODE(} else {)
   STYLE_STRUCT_TEST_CODE(  NS_ASSERTION(STYLE_STRUCT_TEST == 22, "out of range");)
 #endif
-  STYLE_STRUCT_RESET(Column, nsnull, ())
+  STYLE_STRUCT_RESET(Column, nsnull, (SSARG_PRESCONTEXT))
 STYLE_STRUCT_TEST_CODE(})
       
 #ifdef UNDEF_STYLE_STRUCT_INHERITED
 #undef STYLE_STRUCT_INHERITED
 #undef UNDEF_STYLE_STRUCT_INHERITED
 #endif
 
 #ifdef UNDEF_STYLE_STRUCT_RESET
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -356,16 +356,52 @@ var gCSSProperties = {
 	"-moz-column-width": {
 		domProp: "MozColumnWidth",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "auto" ],
 		other_values: [ "15px", "50%" ],
 		invalid_values: [ "20", "-1px" ]
 	},
+	"-moz-column-rule-width": {
+		domProp: "MozColumnRuleWidth",
+		inherited: false,
+		type: CSS_TYPE_LONGHAND,
+		prerequisites: { "-moz-column-rule-style": "solid" },
+		initial_values: [ "medium" ],
+		other_values: [ "thin", "15px" ],
+		invalid_values: [ "20", "-1px", "red", "50%" ]
+	},
+	"-moz-column-rule-style": {
+		domProp: "MozColumnRuleStyle",
+		inherited: false,
+		type: CSS_TYPE_LONGHAND,
+		initial_values: [ "none" ],
+		other_values: [ "solid", "hidden", "ridge", "groove", "inset", "outset", "double", "dotted", "dashed" ],
+		invalid_values: [ "20", "foo" ]
+	},
+	"-moz-column-rule-color": {
+		domProp: "MozColumnRuleColor",
+		inherited: false,
+		type: CSS_TYPE_LONGHAND,
+		prerequisites: { "color": "green" },
+		initial_values: [ "currentColor" ],
+		other_values: [ "red", "blue", "#ffff00" ],
+		invalid_values: [ ]
+	},
+	"-moz-column-rule": {
+		domProp: "MozColumnRule",
+		inherited: false,
+		type: CSS_TYPE_TRUE_SHORTHAND,
+		prerequisites: { "color": "green" },
+		subproperties: [ "-moz-column-rule-width", "-moz-column-rule-style", "-moz-column-rule-color" ],
+		initial_values: [ "medium none currentColor" ],
+		other_values: [ "2px blue solid", "red dotted 1px", "ridge 4px orange" ],
+		invalid_values: [ "2px 3px 4px red", "dotted dashed", "5px dashed green 3px" ]
+	},
 	"-moz-float-edge": {
 		domProp: "MozFloatEdge",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "content-box" ],
 		other_values: [ "margin-box" ],
 		invalid_values: [ "content", "padding", "border", "margin" ]
 	},
--- a/layout/style/test/test_dont_use_document_colors.html
+++ b/layout/style/test/test_dont_use_document_colors.html
@@ -4,17 +4,17 @@
 -->
 <head>
   <title>Test for preference not to use document colors</title>
   <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <style type="text/css">
 
-  #one, #three { background: blue; color: yellow; border: thin solid red; }
+  #one, #three { background: blue; color: yellow; border: thin solid red; -moz-column-rule: 2px solid green; }
   #two { background: transparent; border: thin solid; }
   #five, #six {border: thick solid red; -moz-border-start-color:green; -moz-border-end-color:blue}
 
   /* XXX also test rgba() */
 
   </style>
 </head>
 <body>
@@ -82,16 +82,18 @@ function part1()
           "border-top-color applies");
     is(cs1.borderTopColor, cs3.borderTopColor, "border-top-color applies");
     is(cs1.borderRightColor, cs3.borderRightColor,
        "border-right-color applies");
     is(cs1.borderLeftColor, cs3.borderLeftColor,
        "border-left-color applies");
     is(cs1.borderBottomColor, cs3.borderBottomColor, 
        "border-top-color applies");
+    is(cs1.MozColumnRuleColor, cs3.MozColumnRuleColor,
+       "-moz-column-rule-color applies");
     isnot(cs5.borderRightColor, cs2.borderRightColor,
           "-moz-border-end-color applies");
     isnot(cs5.borderLeftColor, cs2.borderLeftColor,
           "-moz-border-start-color applies");    
     isnot(cs6.borderRightColor, cs2.borderRightColor,
           "-moz-border-start-color applies");
     isnot(cs6.borderLeftColor, cs2.borderLeftColor,
           "-moz-border-end-color applies");
@@ -101,16 +103,18 @@ function part1()
     isnot(cs3.color, cs4.color, "color applies");
     isnot(cs3.borderTopColor, cs4.borderTopColor, "border-top-color applies");
     isnot(cs3.borderRightColor, cs4.borderRightColor,
           "border-right-color applies");
     isnot(cs3.borderLeftColor, cs4.borderLeftColor,
           "border-left-color applies");
     isnot(cs3.borderBottomColor, cs4.borderBottomColor,
           "border-bottom-color applies");
+    isnot(cs2.MozColumnRuleColor, cs3.MozColumnRuleColor,
+       "-moz-column-rule-color applies");
     transparentBackgroundColor = cs2.backgroundColor;
     inputBackgroundColor = cs4.backgroundColor;
     inputColor = cs4.color;
     inputBorderTopColor = cs4.borderTopColor;
     inputBorderRightColor = cs4.borderRightColor;
     inputBorderLeftColor = cs4.borderLeftColor;
     inputBorderBottomColor = cs4.borderBottomColor;
     set_pref(false);
@@ -132,16 +136,18 @@ function part2()
     is(cs5.borderLeftColor, cs2.borderLeftColor,
        "-moz-border-start-color is blocked");
     is(cs6.borderRightColor, cs2.borderRightColor,
        "-moz-border-start-color is blocked");
     is(cs6.borderLeftColor, cs2.borderLeftColor,
        "-moz-border-end-color is blocked");
     is(cs1.borderBottomColor, cs2.borderBottomColor,
        "border-bottom-color is blocked");
+    is(cs2.MozColumnRuleColor, cs3.MozColumnRuleColor,
+       "-moz-column-rule-color is blocked");
     is(cs3.backgroundColor, cs1.backgroundColor, "background-color transparency preserved (opaque)");
     is(cs3.color, cs4.color, "color is blocked");
     is(cs3.borderTopColor, cs4.borderTopColor, "border-top-color is blocked");
     is(cs3.borderRightColor, cs4.borderRightColor,
        "border-right-color is blocked");
     is(cs3.borderLeftColor, cs4.borderLeftColor,
        "border-left-color is blocked");
     is(cs3.borderBottomColor, cs4.borderBottomColor,
--- a/layout/style/test/test_inherit_storage.html
+++ b/layout/style/test/test_inherit_storage.html
@@ -25,16 +25,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 var gDeclaration = document.getElementById("testnode").style;
 
 var gKnownFails = {
   /* bug 377519: */
   "-moz-border-end": true,
   "-moz-border-radius": true,
   "-moz-border-start": true,
+  "-moz-column-rule": true,
   "-moz-outline-radius": true,
   "background": true,
   "border": true,
   "border-bottom": true,
   "border-color": true,
   "border-left": true,
   "border-right": true,
   "border-style": true,
@@ -48,16 +49,17 @@ var gKnownFails = {
   "padding": true,
   "pause": true
 };
 
 var gKnownFails2 = {
   "-moz-border-end": true,
   "-moz-border-radius": true,
   "-moz-border-start": true,
+  "-moz-column-rule": true,
   "-moz-outline-radius": true,
   "background": true,
   "border": true,
   "border-bottom": true,
   "border-left": true,
   "border-right": true,
   "border-top": true,
   "cue": true,
--- a/layout/style/test/test_initial_storage.html
+++ b/layout/style/test/test_initial_storage.html
@@ -25,16 +25,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 var gDeclaration = document.getElementById("testnode").style;
 
 var gKnownFails = {
   /* bug 377519: */
   "-moz-border-end": true,
   "-moz-border-radius": true,
   "-moz-border-start": true,
+  "-moz-column-rule": true,
   "-moz-outline-radius": true,
   "background": true,
   "border": true,
   "border-bottom": true,
   "border-color": true,
   "border-left": true,
   "border-right": true,
   "border-style": true,
@@ -48,16 +49,17 @@ var gKnownFails = {
   "padding": true,
   "pause": true
 };
 
 var gKnownFails2 = {
   "-moz-border-end": true,
   "-moz-border-radius": true,
   "-moz-border-start": true,
+  "-moz-column-rule": true,
   "-moz-outline-radius": true,
   "background": true,
   "border": true,
   "border-bottom": true,
   "border-left": true,
   "border-right": true,
   "border-top": true,
   "cue": true,