b=368247 (and others, see bug), rewrite border rendering for thebes, r=dbaron
authorvladimir@pobox.com
Mon, 30 Apr 2007 20:31:25 -0700
changeset 947 bb748f59fd7e934301f6590b4b44320de97fa90e
parent 946 06e97d56cc2de084ed8545661d40f6d87bad1a3b
child 948 e2aae2d605ca7b96e470533fbb17faad7b86e4fe
push idunknown
push userunknown
push dateunknown
reviewersdbaron
bugs368247
milestone1.9a5pre
b=368247 (and others, see bug), rewrite border rendering for thebes, r=dbaron
gfx/thebes/public/gfxContext.h
gfx/thebes/public/gfxRect.h
gfx/thebes/src/gfxContext.cpp
gfx/thebes/src/gfxRect.cpp
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
layout/reftests/pixel-rounding/border-left-10-ref.html
layout/reftests/pixel-rounding/reftest.list
--- a/gfx/thebes/public/gfxContext.h
+++ b/gfx/thebes/public/gfxContext.h
@@ -136,16 +136,22 @@ public:
     void ClosePath();
 
     /**
      * Moves the pen to a new point without drawing a line.
      */
     void MoveTo(const gfxPoint& pt);
 
     /**
+     * Creates a new subpath starting at the current point.
+     * Equivalent to MoveTo(CurrentPoint()).
+     */
+    void NewSubPath();
+
+    /**
      * Returns the current point in the current path.
      */
     gfxPoint CurrentPoint() const;
 
     /**
      * Draws a line from the current point to pt.
      *
      * @see MoveTo
--- a/gfx/thebes/public/gfxRect.h
+++ b/gfx/thebes/public/gfxRect.h
@@ -62,23 +62,30 @@ struct THEBES_API gfxRect {
     const gfxRect& MoveBy(const gfxPoint& aPt) {
         pos = pos + aPt;
         return *this;
     }
     gfxRect operator+(const gfxPoint& aPt) const {
         return gfxRect(pos + aPt, size);
     }
 
-    const gfxPoint& TopLeft() const { return pos; }
     gfxFloat Width() const { return size.width; }
     gfxFloat Height() const { return size.height; }
     gfxFloat X() const { return pos.x; }
     gfxFloat Y() const { return pos.y; }
     gfxFloat XMost() const { return pos.x + size.width; }
     gfxFloat YMost() const { return pos.y + size.height; }
 
     PRBool IsEmpty() const { return size.width <= 0 || size.height <= 0; }
     gfxRect Intersect(const gfxRect& aRect) const;
     gfxRect Union(const gfxRect& aRect) const;
     // XXX figure out what methods (intersect, union, etc) we use and add them.
+
+    void Round();
+
+    // grabbing specific points
+    gfxPoint TopLeft() const { return gfxPoint(pos); }
+    gfxPoint TopRight() const { return pos + gfxSize(size.width, 0.0); }
+    gfxPoint BottomLeft() const { return pos + gfxSize(0.0, size.height); }
+    gfxPoint BottomRight() const { return pos + size; }
 };
 
 #endif /* GFX_RECT_H */
--- a/gfx/thebes/src/gfxContext.cpp
+++ b/gfx/thebes/src/gfxContext.cpp
@@ -136,16 +136,22 @@ gfxContext::Fill()
 
 void
 gfxContext::MoveTo(const gfxPoint& pt)
 {
     cairo_move_to(mCairo, pt.x, pt.y);
 }
 
 void
+gfxContext::NewSubPath()
+{
+    cairo_new_sub_path(mCairo);
+}
+
+void
 gfxContext::LineTo(const gfxPoint& pt)
 {
     cairo_line_to(mCairo, pt.x, pt.y);
 }
 
 void
 gfxContext::CurveTo(const gfxPoint& pt1, const gfxPoint& pt2, const gfxPoint& pt3)
 {
--- a/gfx/thebes/src/gfxRect.cpp
+++ b/gfx/thebes/src/gfxRect.cpp
@@ -32,17 +32,20 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxRect.h"
 
-gfxRect gfxRect::Intersect(const gfxRect& aRect) const
+#include <math.h>
+
+gfxRect
+gfxRect::Intersect(const gfxRect& aRect) const
 {
   gfxRect result(0,0,0,0);
 
   gfxFloat x = PR_MAX(aRect.X(), X());
   gfxFloat xmost = PR_MIN(aRect.XMost(), XMost());
   if (x >= xmost)
     return result;
 
@@ -50,21 +53,37 @@ gfxRect gfxRect::Intersect(const gfxRect
   gfxFloat ymost = PR_MIN(aRect.YMost(), YMost());
   if (y >= ymost)
     return result;
 
   result = gfxRect(x, y, xmost - x, ymost - y);
   return result;
 }
 
-gfxRect gfxRect::Union(const gfxRect& aRect) const
+gfxRect
+gfxRect::Union(const gfxRect& aRect) const
 {
   if (IsEmpty())
     return aRect;
   if (aRect.IsEmpty())
     return *this;
 
   gfxFloat x = PR_MIN(aRect.X(), X());
   gfxFloat xmost = PR_MAX(aRect.XMost(), XMost());
   gfxFloat y = PR_MIN(aRect.Y(), Y());
   gfxFloat ymost = PR_MAX(aRect.YMost(), YMost());
   return gfxRect(x, y, xmost - x, ymost - y);
 }
+
+void
+gfxRect::Round()
+{
+    gfxFloat x0 = floor(X() + 0.5);
+    gfxFloat y0 = floor(Y() + 0.5);
+    gfxFloat x1 = floor(XMost() + 0.5);
+    gfxFloat y1 = floor(YMost() + 0.5);
+
+    pos.x = x0;
+    pos.y = y0;
+
+    size.width = x1 - x0;
+    size.height = y1 - y0;
+}
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -66,28 +66,33 @@
 #include "nsITheme.h"
 #include "nsThemeConstants.h"
 #include "nsIServiceManager.h"
 #include "nsIDOMHTMLBodyElement.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsLayoutUtils.h"
 #include "nsINameSpaceManager.h"
 
-#ifdef MOZ_CAIRO_GFX
 #include "gfxContext.h"
-#endif
 
 #define BORDER_FULL    0        //entire side
 #define BORDER_INSIDE  1        //inside half
 #define BORDER_OUTSIDE 2        //outside half
 
 //thickness of dashed line relative to dotted line
 #define DOT_LENGTH  1           //square
 #define DASH_LENGTH 3           //3 times longer than dot
 
+//some shorthand for side bits
+#define SIDE_BIT_TOP (1 << NS_SIDE_TOP)
+#define SIDE_BIT_RIGHT (1 << NS_SIDE_RIGHT)
+#define SIDE_BIT_BOTTOM (1 << NS_SIDE_BOTTOM)
+#define SIDE_BIT_LEFT (1 << NS_SIDE_LEFT)
+#define SIDE_BITS_ALL (SIDE_BIT_TOP|SIDE_BIT_RIGHT|SIDE_BIT_BOTTOM|SIDE_BIT_LEFT)
+
 
 /** The following classes are used by CSSRendering for the rounded rect implementation */
 #define MAXPATHSIZE 12
 #define MAXPOLYPATHSIZE 1000
 
 enum ePathTypes{
   eOutside =0,
   eInside,
@@ -359,296 +364,16 @@ nscolor nsCSSRendering::MakeBevelColor(P
 }
 
 // Maximum poly points in any of the polygons we generate below
 #define MAX_POLY_POINTS 4
 
 #define ACTUAL_THICKNESS(outside, inside, frac, tpp) \
   (NSToCoordRound(((outside) - (inside)) * (frac) / (tpp)) * (tpp))
 
-// a nifty helper function to create a polygon representing a
-// particular side of a border. This helps localize code for figuring
-// mitered edges. It is mainly used by the solid, inset, and outset
-// styles.
-//
-// If the side can be represented as a line segment (because the thickness
-// is one pixel), then a line with two endpoints is returned
-PRIntn nsCSSRendering::MakeSide(nsPoint aPoints[],
-                                nsIRenderingContext& aContext,
-                                PRIntn aWhichSide,
-                                const nsRect& aOutside, const nsRect& aInside,
-                                PRIntn aSkipSides,
-                                PRIntn aBorderPart, float aBorderFrac,
-                                nscoord aTwipsPerPixel)
-{
-  nscoord outsideEdge, insideEdge, outsideTL, insideTL, outsideBR, insideBR;
-
-  // Initialize the following six nscoord's:
-  // outsideEdge, insideEdge, outsideTL, insideTL, outsideBR, insideBR
-  // so that outsideEdge is the x or y of the outside edge, etc., and
-  // outsideTR is the y or x at the top or right end, etc., e.g.:
-  //
-  // outsideEdge ---  ----------------------------------------
-  //                  \                                      /
-  //                   \                                    /
-  //                    \                                  /
-  // insideEdge -------  ----------------------------------
-  //                 |   |                                |   |
-  //         outsideTL   insideTL                  insideBR   outsideBR       
-  //
-  // if we don't want the bevel, we'll get rid of it later by setting
-  // outsideXX to insideXX
-
-  switch (aWhichSide) {
-  case NS_SIDE_TOP:
-    // the TL points are the left end; the BR points are the right end
-    outsideEdge = aOutside.y;
-    insideEdge = aInside.y;
-    outsideTL = aOutside.x;
-    insideTL = aInside.x;
-    insideBR = aInside.XMost();
-    outsideBR = aOutside.XMost();
-    break;
-
-  case NS_SIDE_BOTTOM:
-    // the TL points are the left end; the BR points are the right end
-    outsideEdge = aOutside.YMost();
-    insideEdge = aInside.YMost();
-    outsideTL = aOutside.x;
-    insideTL = aInside.x;
-    insideBR = aInside.XMost();
-    outsideBR = aOutside.XMost();
-    break;
-
-  case NS_SIDE_LEFT:
-    // the TL points are the top end; the BR points are the bottom end
-    outsideEdge = aOutside.x;
-    insideEdge = aInside.x;
-    outsideTL = aOutside.y;
-    insideTL = aInside.y;
-    insideBR = aInside.YMost();
-    outsideBR = aOutside.YMost();
-    break;
-
-  default:
-    NS_ASSERTION(aWhichSide == NS_SIDE_RIGHT, "aWhichSide is not a valid side");
-    // the TL points are the top end; the BR points are the bottom end
-    outsideEdge = aOutside.XMost();
-    insideEdge = aInside.XMost();
-    outsideTL = aOutside.y;
-    insideTL = aInside.y;
-    insideBR = aInside.YMost();
-    outsideBR = aOutside.YMost();
-    break;
-  }
-
-  // Don't draw the bevels if an adjacent side is skipped
-
-  if ( (aWhichSide == NS_SIDE_TOP) || (aWhichSide == NS_SIDE_BOTTOM) ) {
-    // a top or bottom side
-    if ((1<<NS_SIDE_LEFT) & aSkipSides) {
-      insideTL = outsideTL;
-    }
-    if ((1<<NS_SIDE_RIGHT) & aSkipSides) {
-      insideBR = outsideBR;
-    }
-  } else {
-    // a right or left side
-    if ((1<<NS_SIDE_TOP) & aSkipSides) {
-      insideTL = outsideTL;
-    }
-    if ((1<<NS_SIDE_BOTTOM) & aSkipSides) {
-      insideBR = outsideBR;
-    }
-  }
-
-  nscoord fullThickness;
-  if (aWhichSide == NS_SIDE_TOP || aWhichSide == NS_SIDE_LEFT)
-    fullThickness = insideEdge - outsideEdge;
-  else
-    fullThickness = outsideEdge - insideEdge;
-  if (fullThickness != 0)
-    fullThickness = NS_MAX(fullThickness, aTwipsPerPixel);
-
-  nscoord thickness = fullThickness;
-  if (aBorderFrac != 1.0f && fullThickness != 0) {
-    thickness = aTwipsPerPixel *
-      NS_MAX(NSToCoordRound(fullThickness * aBorderFrac / aTwipsPerPixel), 1);
-    if ((aWhichSide == NS_SIDE_TOP) || (aWhichSide == NS_SIDE_LEFT)) {
-      if (aBorderPart == BORDER_INSIDE)
-        outsideEdge = insideEdge - thickness;
-      else if (aBorderPart == BORDER_OUTSIDE)
-        insideEdge = outsideEdge + thickness;
-    } else {
-      if (aBorderPart == BORDER_INSIDE)
-        outsideEdge = insideEdge + thickness;
-      else if (aBorderPart == BORDER_OUTSIDE)
-        insideEdge = outsideEdge - thickness;
-    }
-
-    float actualFrac = (float)thickness / (float)fullThickness;
-    if (aBorderPart == BORDER_INSIDE) {
-      outsideTL = insideTL +
-        ACTUAL_THICKNESS(outsideTL, insideTL, actualFrac, aTwipsPerPixel);
-      outsideBR = insideBR +
-        ACTUAL_THICKNESS(outsideBR, insideBR, actualFrac, aTwipsPerPixel);
-    } else if (aBorderPart == BORDER_OUTSIDE) {
-      insideTL = outsideTL -
-        ACTUAL_THICKNESS(outsideTL, insideTL, actualFrac, aTwipsPerPixel);
-      insideBR = outsideBR -
-        ACTUAL_THICKNESS(outsideBR, insideBR, actualFrac, aTwipsPerPixel);
-    }
-  }
-
-  // Base our thickness check on the segment being less than a pixel and 1/2
-  aTwipsPerPixel += aTwipsPerPixel >> 2;
-
-  // if returning a line, do it along inside edge for bottom or right borders
-  // so that it's in the same place as it would be with polygons (why?)
-  // XXX The previous version of the code shortened the right border too.
-  if ( !((thickness >= aTwipsPerPixel) || (aBorderPart != BORDER_FULL)) &&
-       ((aWhichSide == NS_SIDE_BOTTOM) || (aWhichSide == NS_SIDE_RIGHT))) {
-    outsideEdge = insideEdge;
-    }
-
-  // return the appropriate line or trapezoid
-  PRIntn np = 0;
-  if ((aWhichSide == NS_SIDE_TOP) || (aWhichSide == NS_SIDE_BOTTOM)) {
-    // top and bottom borders
-    aPoints[np++].MoveTo(outsideTL,outsideEdge);
-    aPoints[np++].MoveTo(outsideBR,outsideEdge);
-    // XXX Making this condition only (thickness >= aTwipsPerPixel) will
-    // improve double borders and some cases of groove/ridge,
-    //  but will cause problems with table borders.  See last and third
-    // from last tests in test4.htm
-    // Doing it this way emulates the old behavior.  It might be worth
-    // fixing.
-    if ((thickness >= aTwipsPerPixel) || (aBorderPart != BORDER_FULL)) {
-      aPoints[np++].MoveTo(insideBR,insideEdge);
-      aPoints[np++].MoveTo(insideTL,insideEdge);
-    }
-  } else {
-    // right and left borders
-    // XXX Ditto above
-    if ((thickness >= aTwipsPerPixel) || (aBorderPart != BORDER_FULL))  {
-      aPoints[np++].MoveTo(insideEdge,insideBR);
-      aPoints[np++].MoveTo(insideEdge,insideTL);
-    }
-    aPoints[np++].MoveTo(outsideEdge,outsideTL);
-    aPoints[np++].MoveTo(outsideEdge,outsideBR);
-  }
-  return np;
-}
-
-void nsCSSRendering::DrawSide(nsIRenderingContext& aContext,
-                              PRIntn whichSide,
-                              const PRUint8 borderStyle,  
-                              const nscolor borderColor,
-                              const nscolor aBackgroundColor,
-                              const nsRect& borderOutside,
-                              const nsRect& borderInside,
-                              PRIntn aSkipSides,
-                              nscoord twipsPerPixel,
-                              nsRect* aGap)
-{
-  nsPoint theSide[MAX_POLY_POINTS];
-  nscolor theColor = borderColor; 
-  PRUint8 theStyle = borderStyle; 
-  PRInt32 np;
-  switch (theStyle) {
-  case NS_STYLE_BORDER_STYLE_NONE:
-  case NS_STYLE_BORDER_STYLE_HIDDEN:
-    return;
-
-  case NS_STYLE_BORDER_STYLE_DOTTED:    //handled a special case elsewhere
-  case NS_STYLE_BORDER_STYLE_DASHED:    //handled a special case elsewhere
-    break; // That was easy...
-
-  case NS_STYLE_BORDER_STYLE_GROOVE:
-  case NS_STYLE_BORDER_STYLE_RIDGE:
-    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, aSkipSides,
-                   BORDER_INSIDE, 0.5f, twipsPerPixel);
-    aContext.SetColor ( MakeBevelColor (whichSide, 
-                                        ((theStyle == NS_STYLE_BORDER_STYLE_RIDGE) ?
-                                         NS_STYLE_BORDER_STYLE_GROOVE :
-                                         NS_STYLE_BORDER_STYLE_RIDGE), 
-                                         aBackgroundColor, theColor));
-    if (2 == np) {
-      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
-      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
-    } else {
-      //aContext.FillPolygon (theSide, np);
-      FillPolygon (aContext, theSide, np, aGap);
-    }
-    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
-                   BORDER_OUTSIDE, 0.5f, twipsPerPixel);
-    aContext.SetColor ( MakeBevelColor (whichSide, theStyle, aBackgroundColor, 
-                                        theColor));
-    if (2 == np) {
-      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
-      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
-    } else {
-      //aContext.FillPolygon (theSide, np);
-      FillPolygon (aContext, theSide, np, aGap);
-    }
-    break;
-
-  case NS_STYLE_BORDER_STYLE_AUTO:
-  case NS_STYLE_BORDER_STYLE_SOLID:
-    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
-                   BORDER_FULL, 1.0f, twipsPerPixel);
-    aContext.SetColor (borderColor);  
-    if (2 == np) {
-      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
-      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
-    } else {
-      //aContext.FillPolygon (theSide, np);
-      FillPolygon (aContext, theSide, np, aGap);
-    }
-    break;
-
-  case NS_STYLE_BORDER_STYLE_DOUBLE:
-    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
-                   BORDER_INSIDE, 0.333333f, twipsPerPixel);
-    aContext.SetColor (borderColor);
-    if (2 == np) {
-      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
-      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
-    } else {
-      //aContext.FillPolygon (theSide, np);
-      FillPolygon (aContext, theSide, np, aGap);
-   }
-    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
-                   BORDER_OUTSIDE, 0.333333f, twipsPerPixel);
-    if (2 == np) {
-      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
-      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
-    } else {
-      //aContext.FillPolygon (theSide, np);
-      FillPolygon (aContext, theSide, np, aGap);
-    }
-    break;
-
-  case NS_STYLE_BORDER_STYLE_OUTSET:
-  case NS_STYLE_BORDER_STYLE_INSET:
-    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
-                   BORDER_FULL, 1.0f, twipsPerPixel);
-    aContext.SetColor ( MakeBevelColor (whichSide, theStyle, aBackgroundColor, 
-                                        theColor));
-    if (2 == np) {
-      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
-      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
-    } else {
-      //aContext.FillPolygon (theSide, np);
-      FillPolygon (aContext, theSide, np, aGap);
-    }
-    break;
-  }
-}
-
 
 /**
  * Draw a dotted/dashed sides of a box
  */
 //XXX dashes which span more than two edges are not handled properly MMP
 void nsCSSRendering::DrawDashedSides(PRIntn startSide,
                                      nsIRenderingContext& aContext,
                    /* XXX unused */  const nsRect& aDirtyRect,
@@ -1098,435 +823,16 @@ PRBool  skippedSide = PR_FALSE;
         }
       break;
       }
     }
     skippedSide = PR_FALSE;
   }
 }
 
-/* draw the portions of the border described in aBorderEdges that are dashed.
- * a border has 4 edges.  Each edge has 1 or more segments. 
- * "inside edges" are drawn differently than "outside edges" so the shared edges will match up.
- * in the case of table collapsing borders, the table edge is the "outside" edge and
- * cell edges are always "inside" edges (so adjacent cells have 2 shared "inside" edges.)
- * There is a case for each of the four sides.  Only the left side is well documented.  The others
- * are very similar.
- */
-// XXX: doesn't do corners or junctions well at all.  Just uses logic stolen 
-//      from DrawDashedSides which is insufficient
-void nsCSSRendering::DrawDashedSegments(nsIRenderingContext& aContext,
-                                        const nsRect& aBounds,
-                                        nsBorderEdges * aBorderEdges,
-                                        PRIntn aSkipSides,
-                      /* XXX unused */  nsRect* aGap)
-{
-PRIntn dashLength;
-nsRect dashRect, currRect;
-
-PRBool  bSolid = PR_TRUE;
-float   over = 0.0f;
-PRBool  skippedSide = PR_FALSE;
-PRIntn  whichSide=0;
-
-
-  // do this just to set up initial condition for loop
-  // "segment" is the current portion of the edge we are computing
-  nsBorderEdge * segment =  (nsBorderEdge *)(aBorderEdges->mEdges[whichSide].ElementAt(0));
-  PRUint8 style = segment->mStyle;  
-  for ( ; whichSide < 4; whichSide++) 
-  {
-    if ((1<<whichSide) & aSkipSides) {
-      // Skipped side
-      skippedSide = PR_TRUE;
-      continue;
-    }
-    nscoord x=0;  nscoord y=0;
-    PRInt32 i;
-    PRInt32 segmentCount = aBorderEdges->mEdges[whichSide].Count();
-    nsBorderEdges * neighborBorderEdges=nsnull;
-    PRIntn neighborEdgeCount=0; // keeps track of which inside neighbor is shared with an outside segment
-    for (i=0; i<segmentCount; i++)
-    {
-      bSolid=PR_TRUE;
-      over = 0.0f;
-      segment =  (nsBorderEdge *)(aBorderEdges->mEdges[whichSide].ElementAt(i));
-      style = segment->mStyle;
-
-      // XXX units for dash & dot?
-      if (style == NS_STYLE_BORDER_STYLE_DASHED) {
-        dashLength = DASH_LENGTH;
-      } else {
-        dashLength = DOT_LENGTH;
-      }
-
-      aContext.SetColor(segment->mColor);  
-      switch (whichSide) {
-      case NS_SIDE_LEFT:
-      { // draw left segment i
-        nsBorderEdge * topEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(0));
-        if (0==y)
-        { // y is the offset to the top of this segment.  0 means its the topmost left segment
-          y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
-          if (PR_TRUE==aBorderEdges->mOutsideEdge)
-            y += topEdge->mWidth;
-        }
-        // the x offset is the x position offset by the max width of the left edge minus this segment's width
-        x = aBounds.x + (aBorderEdges->mMaxBorderWidth.left - segment->mWidth);
-        nscoord height = segment->mLength;
-        // the space between borderOutside and borderInside inclusive is the segment.
-        nsRect borderOutside(x, y, aBounds.width, height);
-        y += segment->mLength;  // keep track of the y offset for the next segment
-        if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
-            (style == NS_STYLE_BORDER_STYLE_DOTTED))
-        {
-          nsRect borderInside(borderOutside);
-          nsMargin outsideMargin(segment->mWidth, 0, 0, 0);
-          borderInside.Deflate(outsideMargin);
-          nscoord totalLength = segment->mLength; // the computed length of this segment
-          // outside edges need info from their inside neighbor.  The following code keeps track
-          // of which segment of the inside neighbor's shared edge we should use for this outside segment
-          if (PR_TRUE==aBorderEdges->mOutsideEdge)
-          {
-            if (segment->mInsideNeighbor == neighborBorderEdges)
-            {
-              neighborEdgeCount++;
-            }
-            else 
-            {
-              neighborBorderEdges = segment->mInsideNeighbor;
-              neighborEdgeCount=0;
-            }
-            nsBorderEdge * neighborLeft = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_LEFT].ElementAt(neighborEdgeCount));
-            totalLength = neighborLeft->mLength;
-          }
-          dashRect.width = borderInside.x - borderOutside.x;
-          dashRect.height = nscoord(dashRect.width * dashLength);
-          dashRect.x = borderOutside.x;
-          dashRect.y = borderOutside.y + (totalLength/2) - dashRect.height;
-          if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
-            dashRect.y -= topEdge->mWidth;  // account for the topmost left edge corner with the leftmost top edge
-          if (0)
-          {
-            printf("  L: totalLength = %d, borderOutside.y = %d, midpoint %d, dashRect.y = %d\n", 
-            totalLength, borderOutside.y, borderOutside.y +(totalLength/2), dashRect.y); 
-          }
-          currRect = dashRect;
-
-          // we draw the segment in 2 halves to get the inside and outside edges to line up on the
-          // centerline of the shared edge.
-
-          // draw the top half
-          while (currRect.YMost() > borderInside.y) {
-            //clip if necessary
-            if (currRect.y < borderInside.y) {
-              over = float(borderInside.y - dashRect.y) /
-                float(dashRect.height);
-              currRect.height = currRect.height - (borderInside.y - currRect.y);
-              currRect.y = borderInside.y;
-            }
-
-            //draw if necessary
-            if (0)
-            {
-              printf("DASHED LEFT: xywh in loop currRect = %d %d %d %d %s\n", 
-                   currRect.x, currRect.y, currRect.width, currRect.height, bSolid?"TRUE":"FALSE");
-            }
-            if (bSolid) {
-              aContext.FillRect(currRect);
-            }
-
-            //setup for next iteration
-            if (over == 0.0f) {
-              bSolid = PRBool(!bSolid);
-            }
-            dashRect.y = dashRect.y - currRect.height;
-            currRect = dashRect;
-          }
-
-          // draw the bottom half
-          dashRect.y = borderOutside.y + (totalLength/2) + dashRect.height;
-          if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
-            dashRect.y -= topEdge->mWidth;
-          currRect = dashRect;
-          bSolid=PR_TRUE;
-          over = 0.0f;
-          while (currRect.YMost() < borderInside.YMost()) {
-            //clip if necessary
-            if (currRect.y < borderInside.y) {
-              over = float(borderInside.y - dashRect.y) /
-                float(dashRect.height);
-              currRect.height = currRect.height - (borderInside.y - currRect.y);
-              currRect.y = borderInside.y;
-            }
-
-            //draw if necessary
-            if (0)
-            {
-              printf("DASHED LEFT: xywh in loop currRect = %d %d %d %d %s\n", 
-                   currRect.x, currRect.y, currRect.width, currRect.height, bSolid?"TRUE":"FALSE");
-            }
-            if (bSolid) {
-              aContext.FillRect(currRect);
-            }
-
-            //setup for next iteration
-            if (over == 0.0f) {
-              bSolid = PRBool(!bSolid);
-            }
-            dashRect.y = dashRect.y + currRect.height;
-            currRect = dashRect;
-          }
-        }
-      }
-      break;
-
-      case NS_SIDE_TOP:
-      { // draw top segment i
-        if (0==x)
-        {
-          nsBorderEdge * leftEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
-          x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
-        }
-        y = aBounds.y;
-        if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are bottom-aligned
-          y += aBorderEdges->mMaxBorderWidth.top - segment->mWidth;
-        nsRect borderOutside(x, y, segment->mLength, aBounds.height);
-        x += segment->mLength;
-        if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
-            (style == NS_STYLE_BORDER_STYLE_DOTTED))
-        {
-          nsRect borderInside(borderOutside);
-          nsBorderEdge * neighbor;
-          // XXX Adding check to make sure segment->mInsideNeighbor is not null
-          // so it will do the else part, at this point we are assuming this is an
-          // ok thing to do (Bug 52130)
-          if (PR_TRUE==aBorderEdges->mOutsideEdge && segment->mInsideNeighbor)
-            neighbor = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_LEFT].ElementAt(0));
-          else
-            neighbor = (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
-          nsMargin outsideMargin(neighbor->mWidth, segment->mWidth, 0, segment->mWidth);
-          borderInside.Deflate(outsideMargin);
-          nscoord firstRectWidth = 0;
-          if (PR_TRUE==aBorderEdges->mOutsideEdge && 0==i)
-          {
-            firstRectWidth = borderInside.x - borderOutside.x;
-            aContext.FillRect(borderOutside.x, borderOutside.y,
-                              firstRectWidth,
-                              borderInside.y - borderOutside.y);
-          }
-
-          dashRect.height = borderInside.y - borderOutside.y;
-          dashRect.width = dashRect.height * dashLength;
-          dashRect.x = borderOutside.x + firstRectWidth;
-          dashRect.y = borderOutside.y;
-          currRect = dashRect;
-
-          while (currRect.x < borderInside.XMost()) {
-            //clip if necessary
-            if (currRect.XMost() > borderInside.XMost()) {
-              over = float(dashRect.XMost() - borderInside.XMost()) /
-                float(dashRect.width);
-              currRect.width = currRect.width -
-                (currRect.XMost() - borderInside.XMost());
-            }
-
-            //draw if necessary
-            if (bSolid) {
-              aContext.FillRect(currRect);
-            }
-
-            //setup for next iteration
-            if (over == 0.0f) {
-              bSolid = PRBool(!bSolid);
-            }
-            dashRect.x = dashRect.x + currRect.width;
-            currRect = dashRect;
-          }
-        }
-      }
-      break;
-
-      case NS_SIDE_RIGHT:
-      { // draw right segment i
-        nsBorderEdge * topEdge =  (nsBorderEdge *)
-            (aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(aBorderEdges->mEdges[NS_SIDE_TOP].Count()-1));
-        if (0==y)
-        {
-          y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
-          if (PR_TRUE==aBorderEdges->mOutsideEdge)
-            y += topEdge->mWidth;
-        }
-        nscoord width;
-        if (PR_TRUE==aBorderEdges->mOutsideEdge)
-        {
-          width = aBounds.width - aBorderEdges->mMaxBorderWidth.right;
-          width += segment->mWidth;
-        }
-        else
-        {
-          width = aBounds.width;
-        }
-        nscoord height = segment->mLength;
-        nsRect borderOutside(aBounds.x, y, width, height);
-        y += segment->mLength;
-        if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
-            (style == NS_STYLE_BORDER_STYLE_DOTTED))
-        {
-          nsRect borderInside(borderOutside);
-          nsMargin outsideMargin(segment->mWidth, 0, (segment->mWidth), 0);
-          borderInside.Deflate(outsideMargin);
-          nscoord totalLength = segment->mLength;
-          if (PR_TRUE==aBorderEdges->mOutsideEdge)
-          {
-            if (segment->mInsideNeighbor == neighborBorderEdges)
-            {
-              neighborEdgeCount++;
-            }
-            else 
-            {
-              neighborBorderEdges = segment->mInsideNeighbor;
-              neighborEdgeCount=0;
-            }
-            nsBorderEdge * neighborRight = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_RIGHT].ElementAt(neighborEdgeCount));
-            totalLength = neighborRight->mLength;
-          }
-          dashRect.width = borderOutside.XMost() - borderInside.XMost();
-          dashRect.height = nscoord(dashRect.width * dashLength);
-          dashRect.x = borderInside.XMost();
-          dashRect.y = borderOutside.y + (totalLength/2) - dashRect.height;
-          if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
-            dashRect.y -= topEdge->mWidth;
-          currRect = dashRect;
-
-          // draw the top half
-          while (currRect.YMost() > borderInside.y) {
-            //clip if necessary
-            if (currRect.y < borderInside.y) {
-              over = float(borderInside.y - dashRect.y) /
-                float(dashRect.height);
-              currRect.height = currRect.height - (borderInside.y - currRect.y);
-              currRect.y = borderInside.y;
-            }
-
-            //draw if necessary
-            if (bSolid) {
-              aContext.FillRect(currRect);
-            }
-
-            //setup for next iteration
-            if (over == 0.0f) {
-              bSolid = PRBool(!bSolid);
-            }
-            dashRect.y = dashRect.y - currRect.height;
-            currRect = dashRect;
-          }
-
-          // draw the bottom half
-          dashRect.y = borderOutside.y + (totalLength/2) + dashRect.height;
-          if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
-            dashRect.y -= topEdge->mWidth;
-          currRect = dashRect;
-          bSolid=PR_TRUE;
-          over = 0.0f;
-          while (currRect.YMost() < borderInside.YMost()) {
-            //clip if necessary
-            if (currRect.y < borderInside.y) {
-              over = float(borderInside.y - dashRect.y) /
-                float(dashRect.height);
-              currRect.height = currRect.height - (borderInside.y - currRect.y);
-              currRect.y = borderInside.y;
-            }
-
-            //draw if necessary
-            if (bSolid) {
-              aContext.FillRect(currRect);
-            }
-
-            //setup for next iteration
-            if (over == 0.0f) {
-              bSolid = PRBool(!bSolid);
-            }
-            dashRect.y = dashRect.y + currRect.height;
-            currRect = dashRect;
-          }
-
-        }
-      }
-      break;
-
-      case NS_SIDE_BOTTOM:
-      {  // draw bottom segment i
-        if (0==x)
-        {
-          nsBorderEdge * leftEdge =  (nsBorderEdge *)
-            (aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(aBorderEdges->mEdges[NS_SIDE_LEFT].Count()-1));
-          x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
-        }
-        y = aBounds.y;
-        if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are top-aligned
-          y -= aBorderEdges->mMaxBorderWidth.bottom - segment->mWidth;
-        nsRect borderOutside(x, y, segment->mLength, aBounds.height);
-        x += segment->mLength;
-        if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
-            (style == NS_STYLE_BORDER_STYLE_DOTTED))
-        {
-          nsRect borderInside(borderOutside);
-          nsBorderEdge * neighbor;
-          if (PR_TRUE==aBorderEdges->mOutsideEdge)
-            neighbor = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_LEFT].ElementAt(0));
-          else
-            neighbor = (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
-          nsMargin outsideMargin(neighbor->mWidth, segment->mWidth, 0, segment->mWidth);
-          borderInside.Deflate(outsideMargin);
-          nscoord firstRectWidth = 0;
-          if (PR_TRUE==aBorderEdges->mOutsideEdge  &&  0==i)
-          {
-            firstRectWidth = borderInside.x - borderOutside.x;
-            aContext.FillRect(borderOutside.x, borderInside.YMost(),
-                              firstRectWidth,
-                              borderOutside.YMost() - borderInside.YMost());
-          }
-
-          dashRect.height = borderOutside.YMost() - borderInside.YMost();
-          dashRect.width = nscoord(dashRect.height * dashLength);
-          dashRect.x = borderOutside.x + firstRectWidth;
-          dashRect.y = borderInside.YMost();
-          currRect = dashRect;
-
-          while (currRect.x < borderInside.XMost()) {
-            //clip if necessary
-            if (currRect.XMost() > borderInside.XMost()) {
-              over = float(dashRect.XMost() - borderInside.XMost()) / 
-                float(dashRect.width);
-              currRect.width = currRect.width -
-                (currRect.XMost() - borderInside.XMost());
-            }
-
-            //draw if necessary
-            if (bSolid) {
-              aContext.FillRect(currRect);
-            }
-
-            //setup for next iteration
-            if (over == 0.0f) {
-              bSolid = PRBool(!bSolid);
-            }
-            dashRect.x = dashRect.x + currRect.width;
-            currRect = dashRect;
-          }
-        }
-      }
-      break;
-      }
-    }
-    skippedSide = PR_FALSE;
-  }
-}
-
 nscolor
 nsCSSRendering::TransformColor(nscolor  aMapColor,PRBool aNoBackGround)
 {
 PRUint16  hue,sat,value;
 nscolor   newcolor;
 
   newcolor = aMapColor;
   if (PR_TRUE == aNoBackGround){
@@ -1562,493 +868,1426 @@ PRBool GetBorderColor(const nsStyleColor
 
   aBorder.GetBorderColor(aSide, aColorVal, transparent, foreground);
   if (foreground)
     aColorVal = aColor->mColor;
 
   return !transparent;
 }
 
-// XXX improve this to constrain rendering to the damaged area
-void nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
-                                 nsIRenderingContext& aRenderingContext,
-                                 nsIFrame* aForFrame,
-                                 const nsRect& aDirtyRect,
-                                 const nsRect& aBorderArea,
-                                 const nsStyleBorder& aBorderStyle,
-                                 nsStyleContext* aStyleContext,
-                                 PRIntn aSkipSides,
-                                 nsRect* aGap,
-                                 nscoord aHardBorderSize,
-                                 PRBool  aShouldIgnoreRounded)
+
+//----------------------------------------------------------------------
+// Thebes Border Rendering Code Start
+
+#undef DEBUG_NEW_BORDERS
+
+#ifdef DEBUG_NEW_BORDERS
+#include <stdarg.h>
+
+static inline void S(const gfxPoint& p) {
+  fprintf (stderr, "[%f,%f]", p.x, p.y);
+}
+
+static inline void S(const gfxSize& s) {
+  fprintf (stderr, "[%f %f]", s.width, s.height);
+}
+
+static inline void S(const gfxRect& r) {
+  fprintf (stderr, "[%f %f %f %f]", r.pos.x, r.pos.y, r.size.width, r.size.height);
+}
+
+static inline void S(const gfxFloat f) {
+  fprintf (stderr, "%f", f);
+}
+
+static inline void S(const char *s) {
+  fprintf (stderr, "%s", s);
+}
+
+static inline void SN(const char *s = nsnull) {
+  if (s)
+    fprintf (stderr, "%s", s);
+  fprintf (stderr, "\n");
+  fflush (stderr);
+}
+
+static inline void SF(const char *fmt, ...) {
+  va_list vl;
+  va_start(vl, fmt);
+  vfprintf (stderr, fmt, vl);
+  va_end(vl);
+}
+#else
+static inline void S(const gfxPoint& p) {}
+static inline void S(const gfxSize& s) {}
+static inline void S(const gfxRect& r) {}
+static inline void S(const gfxFloat f) {}
+static inline void S(const char *s) {}
+static inline void SN(const char *s = nsnull) {}
+static inline void SF(const char *fmt, ...) {}
+#endif
+
+/*
+ * Figure out whether we need to draw using separate side rendering or
+ * not.
+ *
+ * The only case where we can draw the border in one shot is:
+ *  - the style is SOLID or DOUBLE
+ *  - the same color is used on all sides
+ *  - composite colors are not involved
+ *
+ * 
+ */
+static PRBool
+ShouldDoSeparateSides (const nsStyleBorder& aBorderStyle,
+                       const nsStyleColor *aOurColor)
+{
+  PRUint8 firstSideStyle;
+  nscolor firstSideColor;
+  nscolor sideColor;
+  nsBorderColors* compositeColors = nsnull;
+
+  static PRUint8 sideOrder[] = { NS_SIDE_BOTTOM, NS_SIDE_LEFT, NS_SIDE_TOP, NS_SIDE_RIGHT };
+
+  for (PRInt32 i = 0; i < 4; i++) {
+    PRUint8 side = sideOrder[i];
+    PRUint8 borderRenderStyle = aBorderStyle.GetBorderStyle(side);
+
+    // always do separate sides for borders where all 4 sides wouldn't
+    // be rendered in an identical way
+    if (borderRenderStyle != NS_STYLE_BORDER_STYLE_SOLID &&
+        borderRenderStyle != NS_STYLE_BORDER_STYLE_DOUBLE)
+      return PR_TRUE;
+
+    if (i == 0)
+      firstSideStyle = borderRenderStyle;
+    else if (borderRenderStyle != firstSideStyle)
+      return PR_TRUE;
+
+    if (GetBorderColor(aOurColor, aBorderStyle, side, sideColor, &compositeColors)) {
+      // always do separate sides with compositeColors
+      if (compositeColors)
+        return PR_TRUE;
+
+      // do separate sides if we have different colors on different sides
+      if (i == 0)
+        firstSideColor = sideColor;
+      else if (sideColor != firstSideColor)
+        return PR_TRUE;
+    }
+  }
+
+  return PR_FALSE;
+}
+
+#define C_TL 0
+#define C_TR 1
+#define C_BR 2
+#define C_BL 3
+
+#ifndef NS_PI
+#define NS_PI 3.14159265358979323846
+#endif
+
+// return the length of the given side of lRect, taking into
+// acount corner radii.
+static gfxFloat
+SideLength(gfxRect& oRect,
+           gfxRect& lRect,
+           PRUint8 side,
+           gfxFloat *radii)
+{
+  if (radii == nsnull) {
+    if (side == NS_SIDE_TOP || side == NS_SIDE_BOTTOM)
+      return oRect.size.width;
+
+    return oRect.size.height;
+  } else {
+    // XXX radii, don't fix this until DoSingleSideBorderPath
+    // does per-side borders with radius
+    if (side == NS_SIDE_TOP || side == NS_SIDE_BOTTOM)
+      return oRect.size.width;
+
+    return oRect.size.height;
+  }
+}
+
+//
+// draw the entire border path, as a single rectangle/etc.
+//
+
+static void
+DoAllSidesBorderPath(gfxContext *ctx,
+                     gfxRect& lRect,
+                     gfxFloat *radii)
+{
+  ctx->NewPath();
+
+  // if we don't have border radius, then this is easy
+  if (radii == nsnull) {
+    ctx->Rectangle(lRect);
+  } else {
+    // ok, we have at least one border radius.  The fun starts here!
+    // We have a potential radius at each corner, so draw lines in between
+    // corners, and arcs where there need to be arcs at the corners.
+    // The lines are offset by the radius in both directions.
+    //
+    // When we support CSS3 two-radius specification, this will have
+    // to change, as we'll need to do scaling tricks to get that to work.
+    // specifically, we need to pick one radius, and scale the other axis
+    // so that r1 * scale = r2, because we can't draw ellipses directly
+    // with cairo.
+    //
+    // The path that's created looks like this, with *'s indicating
+    // points along the path, and > the path direction:
+    //
+    //      v- start point
+    //      *--->----*
+    //     /          \
+    //     *          *
+    //     |          |
+    //     *          *
+    //     \          /
+    //      *--------*
+
+    gfxMatrix mat = ctx->CurrentMatrix();
+    ctx->Translate(lRect.pos);
+
+    ctx->MoveTo(gfxPoint(radii[C_TL], 0.0));
+
+    ctx->LineTo(gfxPoint(lRect.size.width - radii[C_TR], 0.0));
+
+    if (radii[C_TR]) {
+      ctx->Arc(gfxPoint(lRect.size.width - radii[C_TR], radii[C_TR]),
+               radii[C_TR],
+               3.0 * NS_PI / 2.0, 0.0);
+    }
+
+    ctx->LineTo(gfxPoint(lRect.size.width, lRect.size.height - radii[C_BR]));
+
+    if (radii[C_BR]) {
+      ctx->Arc(gfxPoint(lRect.size.width - radii[C_BR], lRect.size.height - radii[C_BR]),
+               radii[C_BR],
+               0.0, NS_PI / 2.0);
+    }
+
+    ctx->LineTo(gfxPoint(radii[C_BL], lRect.size.height));
+
+    if (radii[C_BL]) {
+      ctx->Arc(gfxPoint(radii[C_BL], lRect.size.height - radii[C_BL]),
+               radii[C_BL],
+               NS_PI / 2.0,
+               NS_PI);
+    }
+
+    ctx->LineTo(gfxPoint(0.0, 0.0 + radii[C_TL]));
+
+    if (radii[C_TL]) {
+      ctx->Arc(gfxPoint(radii[C_TL], radii[C_TL]),
+               radii[C_TL],
+               NS_PI,
+               3.0 * NS_PI / 2.0);
+    }
+
+    // don't close the path, since doing so can potentially give us artifacts
+    //ctx->ClosePath();
+
+    ctx->SetMatrix(mat);
+  }
+}
+
+
+static void
+DoSingleSideBorderPath(gfxContext *ctx,
+                       gfxRect& oRect,
+                       gfxRect& lRect,
+                       gfxFloat *radii,
+                       PRInt8 whichSide)
+{
+  // we are drawing one specific side.  We need to be very accurate here,
+  // because we can't just draw the rectangle and hope that clipping wins.
+  // If we do that, we'll have problems at the corners, especially if there
+  // are dashes involved.
+
+  // XXX this code doesn't handle radii yet, so when there is a border radius
+  // we just use the code above
+
+  // Make sure to draw these lines in the same order as the rectangle lines
+  // are drawn to avoid confusion.
+
+  ctx->NewPath();
+
+  if (whichSide == NS_SIDE_TOP) {
+    ctx->MoveTo(gfxPoint(oRect.pos.x, lRect.pos.y));
+    ctx->LineTo(gfxPoint(oRect.pos.x + oRect.size.width, lRect.pos.y));
+  } else if (whichSide == NS_SIDE_RIGHT) {
+    ctx->MoveTo(gfxPoint(lRect.pos.x + lRect.size.width, oRect.pos.y));
+    ctx->LineTo(gfxPoint(lRect.pos.x + lRect.size.width, oRect.pos.y + oRect.size.height));
+  } else if (whichSide == NS_SIDE_BOTTOM) {
+    ctx->MoveTo(gfxPoint(oRect.pos.x + oRect.size.width,  lRect.pos.y + lRect.size.height));
+    ctx->LineTo(gfxPoint(oRect.pos.x, lRect.pos.y + lRect.size.height));
+  } else if (whichSide == NS_SIDE_LEFT) {
+    ctx->MoveTo(gfxPoint(lRect.pos.x, oRect.pos.y + oRect.size.height));
+    ctx->LineTo(gfxPoint(lRect.pos.x, oRect.pos.y));
+  }
+}
+
+
+// Create a clip path for the wedge that this side of
+// the border should take up.  This is only called
+// when we're drawing separate border sides, so we know
+// that ADD compositing is taking place.
+//
+// This code needs to make sure that the individual pieces
+// don't ever (mathematically) overlap; the pixel overlap
+// is taken care of by the ADD compositing.
+//
+// The side border type and the adjacent border types are
+// examined and one of the different types of clipping (listed
+// below) is selected.
+
+typedef enum {
+  // clip to the trapezoid formed by the corners of the
+  // inner and outer rectangles for the given side
+  SIDE_CLIP_TRAPEZOID,
+
+  // clip to the trapezoid formed by the outer rectangle
+  // corners and the center of the region, making sure
+  // that diagonal lines all go directly from the outside
+  // corner to the inside corner, but that they then continue on
+  // to the middle.
+  //
+  // This is needed for correctly clipping rounded borders,
+  // which might extend past the SIDE_CLIP_TRAPEZOID trap.
+  SIDE_CLIP_TRAPEZOID_FULL,
+
+  // clip to the rectangle formed by the given side; a specific
+  // overlap algorithm is used; see the function for details.
+  // this is currently used for dashing.
+  SIDE_CLIP_RECTANGLE
+} SideClipType;
+
+static void
+DoSideClipPath(gfxContext *ctx,
+               gfxRect& iRect,
+               gfxRect& oRect,
+               gfxRect& lRect,
+               PRUint8 whichSide,
+               const nsStyleBorder& borderStyle,
+               const PRInt16 *borderRadii)
+{
+  // the clip proceeds clockwise from the top left corner;
+  // so "start" in each case is the start of the region from that side.
+  //
+  // the final path will be formed like:
+  // s0 ------- e0
+  // |         /
+  // s1 ----- e1
+  //
+  // that is, the second point will always be on the inside
+
+  gfxPoint start[2];
+  gfxPoint end[2];
+
+  PRUint8 style = borderStyle.GetBorderStyle(whichSide);
+  PRUint8 startAdjacentStyle = borderStyle.GetBorderStyle(((whichSide - 1) + 4) % 4);
+  PRUint8 endAdjacentStyle = borderStyle.GetBorderStyle((whichSide + 1) % 4);
+
+  PRBool isDashed =
+    (style == NS_STYLE_BORDER_STYLE_DASHED || style == NS_STYLE_BORDER_STYLE_DOTTED);
+  PRBool startIsDashed =
+    (startAdjacentStyle == NS_STYLE_BORDER_STYLE_DASHED || startAdjacentStyle == NS_STYLE_BORDER_STYLE_DOTTED);
+  PRBool endIsDashed =
+    (endAdjacentStyle == NS_STYLE_BORDER_STYLE_DASHED || endAdjacentStyle == NS_STYLE_BORDER_STYLE_DOTTED);
+
+  PRBool startHasRadius = PR_FALSE;
+  PRBool endHasRadius = PR_FALSE;
+
+  SideClipType startType = SIDE_CLIP_TRAPEZOID;
+  SideClipType endType = SIDE_CLIP_TRAPEZOID;
+
+  if (borderRadii) {
+    startHasRadius = borderRadii[whichSide] != 0;
+    endHasRadius = borderRadii[(whichSide+1) % 4] != 0;
+  }
+
+  if (startHasRadius) {
+    startType = SIDE_CLIP_TRAPEZOID_FULL;
+  } else if (startIsDashed && isDashed) {
+    startType = SIDE_CLIP_RECTANGLE;
+  }
+
+  if (endHasRadius) {
+    endType = SIDE_CLIP_TRAPEZOID_FULL;
+  } else if (endIsDashed && isDashed) {
+    endType = SIDE_CLIP_RECTANGLE;
+  }
+
+  if (startType == SIDE_CLIP_TRAPEZOID ||
+      startType == SIDE_CLIP_TRAPEZOID_FULL)
+  {
+    switch (whichSide) {
+      case NS_SIDE_TOP:
+        start[0] = oRect.TopLeft();
+        start[1] = iRect.TopLeft();
+        break;
+
+      case NS_SIDE_RIGHT:
+        start[0] = oRect.TopRight();
+        start[1] = iRect.TopRight();
+        break;
+
+      case NS_SIDE_BOTTOM:
+        start[0] = oRect.BottomRight();
+        start[1] = iRect.BottomRight();
+        break;
+
+      case NS_SIDE_LEFT:
+        start[0] = oRect.BottomLeft();
+        start[1] = iRect.BottomLeft();
+        break;
+    }
+
+    if (startType == SIDE_CLIP_TRAPEZOID_FULL) {
+      gfxFloat mx = iRect.pos.x + iRect.size.width / 2.0;
+      gfxFloat my = iRect.pos.y + iRect.size.height / 2.0;
+
+      gfxPoint ps, pc;
+
+      ps = start[1] - start[0];
+      if (ps.x == 0.0 && ps.y == 0.0) {
+        // do nothing; pc == start[1]
+      } else if (ps.x == 0.0) {
+        start[1] = start[0] + gfxSize(ps.y, ps.y);
+      } else if (ps.y == 0.0) {
+        start[1] = start[0] + gfxSize(ps.x, ps.x);
+      } else {
+        gfxFloat k = PR_MIN((mx - start[0].x) / ps.x,
+                            (my - start[0].y) / ps.y);
+        start[1] = start[0] + ps * k;
+      }
+    }
+  } else if (startType == SIDE_CLIP_RECTANGLE) {
+    switch (whichSide) {
+      case NS_SIDE_TOP:
+        start[0] = oRect.TopLeft();
+        start[1] = gfxPoint(start[0].x, iRect.TopLeft().y);
+        break;
+
+      case NS_SIDE_RIGHT:
+        start[0] = oRect.TopRight();
+        start[1] = gfxPoint(iRect.TopRight().x, start[0].y);
+        break;
+
+      case NS_SIDE_BOTTOM:
+        start[0] = oRect.BottomRight();
+        start[1] = gfxPoint(start[0].x, iRect.BottomRight().y);
+        break;
+
+      case NS_SIDE_LEFT:
+        start[0] = oRect.BottomLeft();
+        start[1] = gfxPoint(iRect.BottomLeft().x, start[0].y);
+        break;
+    }
+  }
+
+  if (endType == SIDE_CLIP_TRAPEZOID ||
+      endType == SIDE_CLIP_TRAPEZOID_FULL)
+  {
+    switch (whichSide) {
+      case NS_SIDE_TOP:
+        end[0] = oRect.TopRight();
+        end[1] = iRect.TopRight();
+        break;
+
+      case NS_SIDE_RIGHT:
+        end[0] = oRect.BottomRight();
+        end[1] = iRect.BottomRight();
+        break;
+
+      case NS_SIDE_BOTTOM:
+        end[0] = oRect.BottomLeft();
+        end[1] = iRect.BottomLeft();
+        break;
+
+      case NS_SIDE_LEFT:
+        end[0] = oRect.TopLeft();
+        end[1] = iRect.TopLeft();
+        break;
+    }
+
+    if (endType == SIDE_CLIP_TRAPEZOID_FULL) {
+      gfxFloat mx = iRect.pos.x + iRect.size.width / 2.0;
+      gfxFloat my = iRect.pos.y + iRect.size.height / 2.0;
+
+      gfxPoint ps, pc;
+
+      ps = end[1] - end[0];
+      if (ps.x == 0.0 && ps.y == 0.0) {
+        // do nothing; pc == end[1]
+      } else if (ps.x == 0.0) {
+        end[1] = end[0] + gfxSize(ps.y, ps.y);
+      } else if (ps.y == 0.0) {
+        end[1] = end[0] + gfxSize(ps.x, ps.x);
+      } else {
+        gfxFloat k = PR_MIN((mx - end[0].x) / ps.x,
+                            (my - end[0].y) / ps.y);
+        end[1] = end[0] + ps * k;
+      }
+    }
+  } else if (startType == SIDE_CLIP_RECTANGLE) {
+    switch (whichSide) {
+      case NS_SIDE_TOP:
+        end[0] = gfxPoint(iRect.TopRight().x, oRect.TopRight().y);
+        end[1] = iRect.TopRight();
+        break;
+
+      case NS_SIDE_RIGHT:
+        end[0] = gfxPoint(oRect.BottomRight().x, iRect.BottomRight().y);
+        end[1] = iRect.BottomRight();
+        break;
+
+      case NS_SIDE_BOTTOM:
+        end[0] = gfxPoint(iRect.BottomLeft().x, oRect.BottomLeft().y);
+        end[1] = iRect.BottomLeft();
+        break;
+
+      case NS_SIDE_LEFT:
+        end[0] = gfxPoint(oRect.TopLeft().x, iRect.TopLeft().y);
+        end[1] = iRect.TopLeft();
+        break;
+    }
+  }
+
+  ctx->NewPath();
+  ctx->MoveTo(start[0]);
+  ctx->LineTo(end[0]);
+  ctx->LineTo(end[1]);
+  ctx->LineTo(start[1]);
+  ctx->ClosePath();
+}
+
+typedef enum {
+  BorderColorStyleNone,
+  BorderColorStyleSolid,
+  BorderColorStyleLight,
+  BorderColorStyleDark
+} BorderColorStyle;
+
+static void
+MakeBorderColor(gfxRGBA& color, const gfxRGBA& backgroundColor, BorderColorStyle bpat)
 {
-  PRIntn              cnt;
+  nscolor colors[2];
+
+  switch (bpat) {
+    case BorderColorStyleNone:
+      color.r = 0.0;
+      color.g = 0.0;
+      color.b = 0.0;
+      color.a = 0.0;
+      break;
+
+    case BorderColorStyleSolid:
+      break;
+
+    case BorderColorStyleLight:
+      NS_GetSpecial3DColors(colors, backgroundColor.Packed(), color.Packed());
+      color.r = NS_GET_R(colors[1]) / 255.0;
+      color.g = NS_GET_G(colors[1]) / 255.0;
+      color.b = NS_GET_B(colors[1]) / 255.0;
+      color.a = 1.0;
+      break;
+
+    case BorderColorStyleDark:
+      NS_GetSpecial3DColors(colors, backgroundColor.Packed(), color.Packed());
+      color.r = NS_GET_R(colors[0]) / 255.0;
+      color.g = NS_GET_G(colors[0]) / 255.0;
+      color.b = NS_GET_B(colors[0]) / 255.0;
+      color.a = 1.0;
+      break;
+  }
+}
+
+static void
+ComputeColorForLine(PRUint32 lineIndex,
+                    PRUint32 borderWidth,
+                    BorderColorStyle* borderColorStyle,
+                    PRUint32 borderColorStyleCount,
+                    nsBorderColors* borderColors,
+                    PRUint32 borderColorCount,
+                    nscolor borderColor,
+                    nscolor backgroundColor,
+                    gfxRGBA& outColor)
+{
+  NS_ASSERTION(lineIndex < borderColorStyleCount, "Invalid lineIndex given");
+
+  if (borderColors) {
+    if (lineIndex >= borderColorCount) {
+      //outColor = gfxRGBA(borderColor);
+      //return;
+
+      // use the last color
+      lineIndex = borderColorCount - 1;
+    }
+
+    while (lineIndex--)
+      borderColors = borderColors->mNext;
+
+    if (borderColors->mTransparent)
+      outColor.r = outColor.g = outColor.b = outColor.a = 0.0;
+    else
+      outColor = gfxRGBA(borderColors->mColor);
+
+    return;
+  }
+
+  outColor = gfxRGBA(borderColor);
+
+  MakeBorderColor(outColor, gfxRGBA(backgroundColor), borderColorStyle[lineIndex]);
+}
+
+/**
+ ** This function ASSUMES that it can twiddle with the gfx state, and
+ ** expects to be called between a Save/Restore pair.
+ **/
+
+/*
+ * There are three different drawing styles:
+ *
+ * 1) solid
+ * 2) dotted/dashed
+ * 3) split, where split is a diagonal [/] slice, with left and top being the same,
+ *    and bottom and right being the same
+ */
+
+
+static void
+DrawBorderSides(gfxContext *ctx,
+                PRUint32 borderWidth,
+                PRUint8 borderRenderStyle,
+                nscolor borderRenderColor,
+                nsBorderColors *compositeColors,
+                gfxRect& iRect,
+                gfxRect& oRect,
+                gfxRect& lRect,
+                nscolor fgColor,
+                nscolor bgColor,
+                PRBool doSeparateSides,
+                PRUint8 side,
+                nscoord twipsPerPixel,
+                PRInt16 *borderRadii)
+{
+  PRBool dashedRendering = PR_FALSE;
+  gfxFloat dash[2];
+  gfxFloat radii[4];
+  gfxFloat *radiiPtr = nsnull;
+  gfxFloat dashWidth;
+
+  PRUint32 borderColorStyleCount = 0;
+  BorderColorStyle borderColorStyleTopLeft[3], borderColorStyleBottomRight[3];
+  BorderColorStyle *borderColorStyle = nsnull;
+  PRUint32 compositeColorCount = 0;
+
+  PRBool useSpecialDotDashSeparateSides = doSeparateSides;
+
+  if (borderRadii) {
+    for (int i = 0; i < 4; i++) {
+      radii[i] = gfxFloat(borderRadii[i]) / twipsPerPixel;
+    }
+
+    radiiPtr = &radii[0];
+  }
+
+  // disable pretty drawing of dotted/dashed borders if
+  // we have a border radius
+  if (radiiPtr)
+    useSpecialDotDashSeparateSides = PR_FALSE;
+
+  // if we're not doing compositeColors, we can calculate the borderColorStyle based
+  // on the specified style.  The borderColorStyle array goes from the outer to the inner
+  // style.
+
+  if (!compositeColors) {
+    // if the border width is 1, we need to change the borderRenderStyle a bit to make sure
+    // that we get the right colors -- e.g. 'ridge' with a 1px border needs to look like
+    // solid, not like 'outset'.
+    if (borderWidth == 1) {
+      if (borderRenderStyle == NS_STYLE_BORDER_STYLE_RIDGE ||
+          borderRenderStyle == NS_STYLE_BORDER_STYLE_GROOVE ||
+          borderRenderStyle == NS_STYLE_BORDER_STYLE_DOUBLE)
+        borderRenderStyle = NS_STYLE_BORDER_STYLE_SOLID;
+    }
+
+    switch (borderRenderStyle) {
+      case NS_STYLE_BORDER_STYLE_SOLID:
+      case NS_STYLE_BORDER_STYLE_DASHED:
+      case NS_STYLE_BORDER_STYLE_DOTTED:
+        borderColorStyleTopLeft[0] = BorderColorStyleSolid;
+        borderColorStyleBottomRight[0] = BorderColorStyleSolid;
+        borderColorStyleCount = 1;
+
+        // We always want the dash to start on an integer pixel boundary; so if
+        // the path will start on a boundary between pixels, we need to shift the
+        // dash by half a pixel backwards (into the white space) so that the
+        // actual dash starts in the right spot.
+        if (borderRenderStyle == NS_STYLE_BORDER_STYLE_DASHED) {
+          dashWidth = gfxFloat(borderWidth * DOT_LENGTH * DASH_LENGTH);
+          dashedRendering = PR_TRUE;
+
+          dash[0] = dashWidth;
+          dash[1] = dashWidth;
+        } else if (borderRenderStyle == NS_STYLE_BORDER_STYLE_DOTTED) {
+          dashWidth = gfxFloat(borderWidth * DOT_LENGTH);
+          dashedRendering = PR_TRUE;
+
+          // do circles when the border is > 2 in size
+          if (borderWidth > 2) {
+            dash[0] = 0;
+            dash[1] = dashWidth * 2;
+
+            ctx->SetLineCap(gfxContext::LINE_CAP_ROUND);
+          } else {
+            dash[0] = dashWidth;
+            dash[1] = dashWidth;
+          }
+        }
+
+        if (dashedRendering) {
+          gfxFloat dashOffset = 0.0;
+          gfxFloat sideLen = SideLength(oRect, lRect, side, radiiPtr);
+          gfxFloat sideOffset = 0.0;
+
+          // we want to make sure that the side starts and ends on a dash.  If
+          // the side is super short, then we can't do much.
+          //
+          // XXX the dashed/dotted rendering is still voodoo; this needs to be
+          // improved.
+#if 0
+          if (sideLen > dashWidth) {
+            gfxFloat rep = sideLen / (dashWidth * 2.0);
+            gfxFloat rem = sideLen - dashWidth * 2.0 * floor(rep);
+            gfxFloat offsetrem = sideOffset - floor(sideOffset / (dashWidth * 2.0)) * (dashWidth * 20);
+
+            if (rem < dashWidth) {
+              // it will end with a dash of 'rem' width; distribute space.
+              dashOffset = (dashWidth - (dashWidth + rem)) / 2.0;
+            } else {
+              // it will end with empty space
+              dashOffset = (dashWidth + (dashWidth - rem)) / 2.0;
+            }
+
+            // clamp dashOffset to a multiple of the borderWidth
+            dashOffset = floor(dashOffset * borderWidth) / borderWidth;
+          }
+#else
+          if (sideLen > dashWidth) {
+            gfxFloat rep = sideLen / (dashWidth * 2.0);
+            gfxFloat rem = sideLen - dashWidth * 2.0 * floor(rep);
+
+            if (rem < dashWidth) {
+              // it will end with a dash of 'rem' width; distribute space.
+              dashOffset = dashWidth - (rem / 2.0);
+            } else {
+              // it will end with empty space, push it forward
+              dashOffset = rem / 2.0;
+            }
+
+            dashOffset = floor(dashOffset);
+          }
+#endif
+
+          SF("sideLen: %f dashWidth: %f dashOffset: %f final: %f\n", sideLen, dashWidth, dashOffset, (borderWidth & 1) ? dashOffset-0.5 : dashOffset);
+          ctx->SetDash(dash, 2, dashOffset /*(borderWidth & 1) ? dashOffset-0.5 : dashOffset*/);
+        }
+
+        break;
+
+      case NS_STYLE_BORDER_STYLE_GROOVE:
+        borderColorStyleTopLeft[0] = BorderColorStyleDark;
+        borderColorStyleTopLeft[1] = BorderColorStyleLight;
+
+        borderColorStyleBottomRight[0] = BorderColorStyleLight;
+        borderColorStyleBottomRight[1] = BorderColorStyleDark;
+
+        borderColorStyleCount = 2;
+        break;
+
+      case NS_STYLE_BORDER_STYLE_RIDGE:
+        borderColorStyleTopLeft[0] = BorderColorStyleLight;
+        borderColorStyleTopLeft[1] = BorderColorStyleDark;
+
+        borderColorStyleBottomRight[0] = BorderColorStyleDark;
+        borderColorStyleBottomRight[1] = BorderColorStyleLight;
+
+        borderColorStyleCount = 2;
+        break;
+
+      case NS_STYLE_BORDER_STYLE_DOUBLE:
+        borderColorStyleTopLeft[0] = BorderColorStyleSolid;
+        borderColorStyleTopLeft[1] = BorderColorStyleNone;
+        borderColorStyleTopLeft[2] = BorderColorStyleSolid;
+
+        borderColorStyleBottomRight[0] = BorderColorStyleSolid;
+        borderColorStyleBottomRight[1] = BorderColorStyleNone;
+        borderColorStyleBottomRight[2] = BorderColorStyleSolid;
+
+        borderColorStyleCount = 3;
+        break;
+
+      case NS_STYLE_BORDER_STYLE_INSET:
+        borderColorStyleTopLeft[0] = BorderColorStyleDark;
+        borderColorStyleBottomRight[0] = BorderColorStyleLight;
+
+        borderColorStyleCount = 1;
+        break;
+
+      case NS_STYLE_BORDER_STYLE_OUTSET:
+        borderColorStyleTopLeft[0] = BorderColorStyleLight;
+        borderColorStyleBottomRight[0] = BorderColorStyleDark;
+
+        borderColorStyleCount = 1;
+        break;
+
+      default:
+        break;
+    }
+
+    if (side == NS_SIDE_BOTTOM || side == NS_SIDE_RIGHT)
+      borderColorStyle = borderColorStyleBottomRight;
+    else
+      borderColorStyle = borderColorStyleTopLeft;
+  } else {
+    // composite colors; we need to calculate borderColorStyle differently --
+    // all borders are rendered as "solid", but we might need an arbitrary number
+    // of them.
+    borderColorStyle = new BorderColorStyle[borderWidth];
+    borderColorStyleCount = borderWidth;
+
+    nsBorderColors *tmp = compositeColors;
+    do {
+      compositeColorCount++;
+      tmp = tmp->mNext;
+    } while (tmp);
+
+    for (unsigned int i = 0; i < borderColorStyleCount; i++) {
+      borderColorStyle[i] = BorderColorStyleSolid;
+    }
+  }
+
+  SF("borderWidth: %d lRect: ", borderWidth), S(lRect), SN(), SF(" borderColorStyleCount: %d special: %d\n", borderColorStyleCount, useSpecialDotDashSeparateSides);
+
+  // -moz-border-colors is a hack; if we have it for a border, then
+  // it's always drawn solid, and each color is given 1px.  The last
+  // color is used for the remainder of the border's size.
+  //
+  // Otherwise, we distribute the border across the available space.
+
+  if (compositeColorCount == 0) {
+    if (borderColorStyleCount == 1) {
+      gfxRGBA color;
+      ComputeColorForLine(0, borderWidth,
+                          borderColorStyle, borderColorStyleCount,
+                          compositeColors, compositeColorCount,
+                          borderRenderColor, bgColor, color);
+
+      ctx->SetLineWidth(borderWidth);
+      ctx->SetColor(color);
+
+      SF("borderColorStyle: %d color: %f %f %f %f\n", borderColorStyle[0], color.r, color.g, color.b, color.a);
+
+      // add the path to the context; if we're drawing dashed,
+      // we need to use the special path that will stroke the
+      // entire side.
+      if (useSpecialDotDashSeparateSides)
+        DoSingleSideBorderPath(ctx, oRect, lRect, radiiPtr, side);
+      else
+        DoAllSidesBorderPath(ctx, lRect, radiiPtr);
+
+      ctx->Stroke();
+    } else if (borderColorStyleCount == 2) {
+      // with 2 color styles, any extra pixel goes to the outside
+
+      PRInt32 outerBorderWidth, innerBorderWidth;
+      outerBorderWidth = (borderWidth / 2) + (borderWidth % 2);
+      innerBorderWidth = (borderWidth / 2);
+
+      gfxRGBA color;
+      gfxRect sRect;
+
+      // draw outer rect
+      if (outerBorderWidth != 0 && borderColorStyle[1] != BorderColorStyleNone) {
+        ComputeColorForLine(0, borderWidth,
+                            borderColorStyle, borderColorStyleCount,
+                            compositeColors, compositeColorCount,
+                            borderRenderColor, bgColor, color);
+
+        sRect = lRect;
+        sRect.pos.x -= innerBorderWidth / 2.0;
+        sRect.pos.y -= innerBorderWidth / 2.0;
+        sRect.size.width += innerBorderWidth;
+        sRect.size.height += innerBorderWidth;
+
+        ctx->SetLineWidth(outerBorderWidth);
+        ctx->SetColor(color);
+        DoAllSidesBorderPath(ctx, sRect, radiiPtr);
+        ctx->Stroke();
+      }
+
+      // draw inner rect
+      if (innerBorderWidth != 0 && borderColorStyle[0] != BorderColorStyleNone) {
+        ComputeColorForLine(1, borderWidth,
+                            borderColorStyle, borderColorStyleCount,
+                            compositeColors, compositeColorCount,
+                            borderRenderColor, bgColor, color);
+
+        sRect = lRect;
+        sRect.pos.x += outerBorderWidth / 2.0;
+        sRect.pos.y += outerBorderWidth / 2.0;
+        sRect.size.width -= outerBorderWidth;
+        sRect.size.height -= outerBorderWidth;
+
+        ctx->SetLineWidth(innerBorderWidth);
+        ctx->SetColor(color);
+        DoAllSidesBorderPath(ctx, sRect, radiiPtr);
+
+        ctx->Stroke();
+      }
+    } else if (borderColorStyleCount == 3) {
+      // with 3 color styles, any extra pixel (or lack of extra pixel)
+      // goes to the middle
+
+      PRInt32 outerBorderWidth, middleBorderWidth, innerBorderWidth;
+
+      if (borderWidth == 1) {
+        outerBorderWidth = 1;
+        middleBorderWidth = innerBorderWidth = 0;
+      } else {
+        PRInt32 rest = borderWidth % 3;
+        outerBorderWidth = innerBorderWidth = middleBorderWidth = (borderWidth - rest) / 3;
+        if (rest == 1) {
+          middleBorderWidth++;
+        } else if (rest == 2) {
+          outerBorderWidth++;
+          innerBorderWidth++;
+        }
+      }
+
+      gfxRGBA color;
+      gfxRect sRect;
+
+      // draw outer rect
+      if (outerBorderWidth != 0 && borderColorStyle[2] != BorderColorStyleNone) {
+        ComputeColorForLine(0, borderWidth,
+                            borderColorStyle, borderColorStyleCount,
+                            compositeColors, compositeColorCount,
+                            borderRenderColor, bgColor, color);
+
+        sRect = lRect;
+        sRect.pos.x -= (innerBorderWidth + middleBorderWidth) / 2.0;
+        sRect.pos.y -= (innerBorderWidth + middleBorderWidth) / 2.0;
+        sRect.size.width += (innerBorderWidth + middleBorderWidth);
+        sRect.size.height += (innerBorderWidth + middleBorderWidth);
+
+        ctx->SetLineWidth(outerBorderWidth);
+        ctx->SetColor(color);
+        DoAllSidesBorderPath(ctx, sRect, radiiPtr);
+        ctx->Stroke();
+      }
+
+      // draw middle rect
+      if (middleBorderWidth != 0 && borderColorStyle[1] != BorderColorStyleNone) {
+        ComputeColorForLine(1, borderWidth,
+                            borderColorStyle, borderColorStyleCount,
+                            compositeColors, compositeColorCount,
+                            borderRenderColor, bgColor, color);
+
+        // the middle rect will always be the odd one out, so
+        // lRect should run straight down the middle of it
+        // to begin with.
+        sRect = lRect;
+
+        ctx->SetLineWidth(middleBorderWidth);
+        ctx->SetColor(color);
+        DoAllSidesBorderPath(ctx, sRect, radiiPtr);
+        ctx->Stroke();
+      }
+
+      // draw inner rect
+      if (innerBorderWidth != 0 && borderColorStyle[0] != BorderColorStyleNone) {
+        ComputeColorForLine(2, borderWidth,
+                            borderColorStyle, borderColorStyleCount,
+                            compositeColors, compositeColorCount,
+                            borderRenderColor, bgColor, color);
+
+        sRect = lRect;
+        sRect.pos.x += (outerBorderWidth + middleBorderWidth) / 2.0;
+        sRect.pos.y += (outerBorderWidth + middleBorderWidth) / 2.0;
+        sRect.size.width -= (outerBorderWidth + middleBorderWidth);
+        sRect.size.height -= (outerBorderWidth + middleBorderWidth);
+
+        ctx->SetLineWidth(innerBorderWidth);
+        ctx->SetColor(color);
+        DoAllSidesBorderPath(ctx, sRect, radiiPtr);
+        ctx->Stroke();
+      }
+    } else {
+      // The only way to get to here is by having a
+      // borderColorStyleCount < 1 or > 3; this should never happen,
+      // since -moz-border-colors doesn't get handled here.
+      NS_ERROR("Non-border-colors case with borderColorStyleCount < 1 or > 3; what happened?");
+    }
+  } else {
+    // the generic composite colors path; each border is 1px in size, except for the
+    // last one which has all the remaining
+    gfxRect sRect = oRect;
+
+    // offset the top-left so that it starts in the right place
+    // in the pixel
+    sRect.pos.x += 0.5;
+    sRect.pos.y += 0.5;
+    sRect.size.width -= 1.0;
+    sRect.size.height -= 1.0;
+
+    for (PRUint32 i = 0; i < borderColorStyleCount; i++) {
+      gfxRGBA lineColor;
+
+      ComputeColorForLine(i, borderWidth,
+                          borderColorStyle, borderColorStyleCount,
+                          compositeColors, compositeColorCount,
+                          borderRenderColor, bgColor, lineColor);
+
+      ctx->SetLineWidth(1.0);
+      ctx->SetColor(lineColor);
+      DoAllSidesBorderPath(ctx, sRect, radiiPtr);
+      ctx->Stroke();
+
+      sRect.pos.x += 1.0;
+      sRect.pos.y += 1.0;
+      sRect.size.width -= 2.0;
+      sRect.size.height -= 2.0;
+    }
+  }
+
+  if (compositeColors) {
+    delete [] borderColorStyle;
+  }
+
+#if 0
+  ctx->SetOperator(gfxContext::OPERATOR_OVER);
+  // debug; draw a line on the outside and inside edge
+  // of the border.
+  ctx->SetLineWidth(1.0);
+  ctx->SetDash(nsnull, 0, 0.0);
+  ctx->SetColor(gfxRGBA(1.0, 0.0, 0.0, 1.0));
+  ctx->NewPath();
+  ctx->Rectangle(oRect);
+  ctx->Stroke();
+  ctx->NewPath();
+  ctx->Rectangle(iRect);
+  ctx->Stroke();
+#endif
+}
+
+void
+nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
+                            nsIRenderingContext& aRenderingContext,
+                            nsIFrame* aForFrame,
+                            const nsRect& aDirtyRect,
+                            const nsRect& aBorderArea,
+                            const nsStyleBorder& aBorderStyle,
+                            nsStyleContext* aStyleContext,
+                            PRIntn aSkipSides,
+                            nsRect* aGap,
+                            nscoord aHardBorderSize,
+                            PRBool  aShouldIgnoreRounded)
+{
   nsMargin            border;
   nsStyleCoord        bordStyleRadius[4];
-  PRInt16             borderRadii[4],i;
+  PRInt16             borderRadii[4], i;
   float               percent;
   nsCompatibility     compatMode = aPresContext->CompatibilityMode();
-  PRBool              forceSolid;
+  PRBool              haveBorderRadius = PR_FALSE;
+
+  SN("++ PaintBorder");
 
   // Check to see if we have an appearance defined.  If so, we let the theme
   // renderer draw the border.  DO not get the data from aForFrame, since the passed in style context
   // may be different!  Always use |aStyleContext|!
   const nsStyleDisplay* displayData = aStyleContext->GetStyleDisplay();
   if (displayData->mAppearance) {
     nsITheme *theme = aPresContext->GetTheme();
     if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame, displayData->mAppearance))
       return; // Let the theme handle it.
   }
+
   // Get our style context's color struct.
   const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
 
-  // in NavQuirks mode we want to use the parent's context as a starting point 
+  // in NavQuirks mode we want to use the parent's context as a starting point
   // for determining the background color
-  const nsStyleBackground* bgColor = 
-    nsCSSRendering::FindNonTransparentBackground(aStyleContext, 
-                                            compatMode == eCompatibility_NavQuirks ? PR_TRUE : PR_FALSE); 
+  const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground
+    (aStyleContext, compatMode == eCompatibility_NavQuirks ? PR_TRUE : PR_FALSE);
 
   if (aHardBorderSize > 0) {
     border.SizeTo(aHardBorderSize, aHardBorderSize, aHardBorderSize, aHardBorderSize);
   } else {
     border = aBorderStyle.GetBorder();
   }
+
   if ((0 == border.left) && (0 == border.right) &&
       (0 == border.top) && (0 == border.bottom)) {
     // Empty border area
     return;
   }
 
-
   // get the radius for our border
   aBorderStyle.mBorderRadius.GetTop(bordStyleRadius[0]);      //topleft
   aBorderStyle.mBorderRadius.GetRight(bordStyleRadius[1]);    //topright
   aBorderStyle.mBorderRadius.GetBottom(bordStyleRadius[2]);   //bottomright
   aBorderStyle.mBorderRadius.GetLeft(bordStyleRadius[3]);     //bottomleft
 
-  for(i=0;i<4;i++) {
+  // convert percentage values
+  for(i = 0; i < 4; i++) {
     borderRadii[i] = 0;
-    switch ( bordStyleRadius[i].GetUnit()) {
-    case eStyleUnit_Percent:
-      percent = bordStyleRadius[i].GetPercentValue();
-      borderRadii[i] = (nscoord)(percent * aForFrame->GetSize().width);
-      break;
-    case eStyleUnit_Coord:
-      borderRadii[i] = bordStyleRadius[i].GetCoordValue();
-      break;
-    default:
-      break;
+
+    switch (bordStyleRadius[i].GetUnit()) {
+      case eStyleUnit_Percent:
+        percent = bordStyleRadius[i].GetPercentValue();
+        borderRadii[i] = (nscoord)(percent * aForFrame->GetSize().width);
+        break;
+
+      case eStyleUnit_Coord:
+        borderRadii[i] = bordStyleRadius[i].GetCoordValue();
+        break;
+
+      default:
+        break;
     }
-  }
-
-  // rounded version of the outline
-  // check for any corner that is rounded
-  for(i=0;i<4;i++){
-    if(borderRadii[i] > 0 && !aBorderStyle.mBorderColors){
-      PaintRoundedBorder(aPresContext,aRenderingContext,aForFrame,aDirtyRect,aBorderArea,&aBorderStyle,nsnull,aStyleContext,aSkipSides,borderRadii,aGap,PR_FALSE);
-      return;
-    }
+
+    if (borderRadii[i])
+      haveBorderRadius = PR_TRUE;
   }
 
   // Turn off rendering for all of the zero sized sides
-  if (0 == border.top) aSkipSides |= (1 << NS_SIDE_TOP);
-  if (0 == border.right) aSkipSides |= (1 << NS_SIDE_RIGHT);
-  if (0 == border.bottom) aSkipSides |= (1 << NS_SIDE_BOTTOM);
-  if (0 == border.left) aSkipSides |= (1 << NS_SIDE_LEFT);
+  if (border.top == 0) aSkipSides |= SIDE_BIT_TOP;
+  if (border.right == 0) aSkipSides |= SIDE_BIT_RIGHT;
+  if (border.bottom == 0) aSkipSides |= SIDE_BIT_BOTTOM;
+  if (border.left == 0) aSkipSides |= SIDE_BIT_LEFT;
+
+  if (aSkipSides & SIDE_BIT_TOP) border.top = 0;
+  if (aSkipSides & SIDE_BIT_RIGHT) border.right = 0;
+  if (aSkipSides & SIDE_BIT_BOTTOM) border.bottom = 0;
+  if (aSkipSides & SIDE_BIT_LEFT) border.left = 0;
 
   // get the inside and outside parts of the border
-  nsRect outerRect(aBorderArea);
-  nsRect innerRect(outerRect);
+  nsRect outerRect(aBorderArea), innerRect(aBorderArea);
   innerRect.Deflate(border);
 
+  SF(" innerRect: %d %d %d %d\n", innerRect.x, innerRect.y, innerRect.width, innerRect.height);
+  SF(" outerRect: %d %d %d %d\n", outerRect.x, outerRect.y, outerRect.width, outerRect.height);
+
+  // if the border size is more than the appropriate dimension of the area,
+  // then... do what?
+  // XXX what is this?  according to bug 62245, this check might not be
+  // needed any more
   if (border.left + border.right > aBorderArea.width) {
     innerRect.x = outerRect.x;
     innerRect.width = outerRect.width;
   }
   if (border.top + border.bottom > aBorderArea.height) {
     innerRect.y = outerRect.y;
     innerRect.height = outerRect.height;
   }
 
-
-
   // If the dirty rect is completely inside the border area (e.g., only the
   // content is being painted), then we can skip out now
+  // XXX this isn't exactly true for rounded borders, where the inner curves may
+  // encroach into the content area.  A safer calculation would be to
+  // shorten innerRect by the radius one each side before performing this test.
   if (innerRect.Contains(aDirtyRect)) {
     return;
   }
- 
-  //see if any sides are dotted or dashed
-  for (cnt = 0; cnt < 4; cnt++) {
-    if ((aBorderStyle.GetBorderStyle(cnt) == NS_STYLE_BORDER_STYLE_DOTTED) || 
-        (aBorderStyle.GetBorderStyle(cnt) == NS_STYLE_BORDER_STYLE_DASHED))  {
-      break;
-    }
-  }
-  if (cnt < 4) {
-    DrawDashedSides(cnt, aRenderingContext,aDirtyRect, ourColor, &aBorderStyle,nsnull, PR_FALSE,
-                    outerRect, innerRect, aSkipSides, aGap);
+
+  // The border radius has to be equal to or less than half the length
+  // of the two sides that form the corner.  I think this is what trunk does;
+  // without this check, the result is still well defined: the center of the
+  // arc created by the corner is always inset by (radius,radius) from the
+  // relevant corner, even if that causes it to go into another quadrant.
+  if (haveBorderRadius) {
+    borderRadii[0] = PR_MIN(borderRadii[0], (innerRect.width + border.left) / 2);
+    borderRadii[0] = PR_MIN(borderRadii[0], (innerRect.height + border.top) / 2);
+
+    borderRadii[1] = PR_MIN(borderRadii[1], (innerRect.width + border.right) / 2);
+    borderRadii[1] = PR_MIN(borderRadii[1], (innerRect.height + border.top) / 2);
+
+    borderRadii[2] = PR_MIN(borderRadii[2], (innerRect.width + border.right) / 2);
+    borderRadii[2] = PR_MIN(borderRadii[2], (innerRect.height + border.bottom) / 2);
+
+    borderRadii[3] = PR_MIN(borderRadii[3], (innerRect.width + border.left) / 2);
+    borderRadii[3] = PR_MIN(borderRadii[3], (innerRect.height + border.bottom) / 2);
   }
 
-  // dont clip the borders for composite borders, they use the inner and 
-  // outer rect to compute the diagonale to cross the border radius
-  nsRect compositeInnerRect(innerRect);
-  nsRect compositeOuterRect(outerRect);
-
-  // Draw all the other sides
-  if (!aDirtyRect.Contains(outerRect)) {
-    // Border leaks out of the dirty rectangle - lets clip it but with care
-    if (innerRect.y < aDirtyRect.y) {
-      aSkipSides |= (1 << NS_SIDE_TOP);
-      PRUint32 shortenBy =
-        PR_MIN(innerRect.height, aDirtyRect.y - innerRect.y);
-      innerRect.y += shortenBy;
-      innerRect.height -= shortenBy;
-      outerRect.y += shortenBy;
-      outerRect.height -= shortenBy;
-    }
-    if (aDirtyRect.YMost() < innerRect.YMost()) {
-      aSkipSides |= (1 << NS_SIDE_BOTTOM);
-      PRUint32 shortenBy =
-        PR_MIN(innerRect.height, innerRect.YMost() - aDirtyRect.YMost());
-      innerRect.height -= shortenBy;
-      outerRect.height -= shortenBy;
-    }
-    if (innerRect.x < aDirtyRect.x) {
-      aSkipSides |= (1 << NS_SIDE_LEFT);
-      PRUint32 shortenBy =
-        PR_MIN(innerRect.width, aDirtyRect.x - innerRect.x);
-      innerRect.x += shortenBy;
-      innerRect.width -= shortenBy;
-      outerRect.x += shortenBy;
-      outerRect.width -= shortenBy;
-    }
-    if (aDirtyRect.XMost() < innerRect.XMost()) {
-      aSkipSides |= (1 << NS_SIDE_RIGHT);
-      PRUint32 shortenBy =
-        PR_MIN(innerRect.width, innerRect.XMost() - aDirtyRect.XMost());
-      innerRect.width -= shortenBy;
-      outerRect.width -= shortenBy;
-    }
-  }
+  // we can assume that we're already clipped to aDirtyRect -- I think? (!?)
+
   /* Get our conversion values */
   nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
 
   static PRUint8 sideOrder[] = { NS_SIDE_BOTTOM, NS_SIDE_LEFT, NS_SIDE_TOP, NS_SIDE_RIGHT };
-  nscolor sideColor;
-  nsBorderColors* compositeColors = nsnull;
-
-#ifdef MOZ_CAIRO_GFX
-  gfxContext *ctx = (gfxContext*) aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
-  gfxContext::AntialiasMode oldMode = ctx->CurrentAntialiasMode();
-  ctx->SetAntialiasMode(gfxContext::MODE_ALIASED);
-#endif
-
-  for (cnt = 0; cnt < 4; cnt++) {
-    PRUint8 side = sideOrder[cnt];
-
-    // If a side needs a double/groove/ridge border but will be less than two
-    // pixels, force it to be solid (see bug 1781 and bug 310124).
-    if (aBorderStyle.GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_DOUBLE ||
-        aBorderStyle.GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_GROOVE ||
-        aBorderStyle.GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_RIDGE) {
-      nscoord widths[] = { border.top, border.right, border.bottom, border.left };
-      forceSolid = (widths[side]/twipsPerPixel < 2);
-    } else 
-      forceSolid = PR_FALSE;
-
-    if (0 == (aSkipSides & (1<<side))) {
-      if (GetBorderColor(ourColor, aBorderStyle, side, sideColor, &compositeColors)) {
-        if (compositeColors)
-          DrawCompositeSide(aRenderingContext, side, compositeColors, compositeOuterRect, 
-                            compositeInnerRect, borderRadii, twipsPerPixel, aGap);
-        else
-          DrawSide(aRenderingContext, side,
-                   forceSolid ? NS_STYLE_BORDER_STYLE_SOLID : aBorderStyle.GetBorderStyle(side),
-                   sideColor,
-                   bgColor->mBackgroundColor,
-                   outerRect,innerRect, aSkipSides,
-                   twipsPerPixel, aGap);
-      }
-    }
+
+  nsRefPtr<gfxContext> ctx = (gfxContext*)
+    aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
+
+  PRBool doSeparateSides = PR_FALSE;
+
+  // If we have to skip some sides, we have to draw separate sides.
+  // Otherwise, examine the border style to figure out if we can
+  // draw it in one go or not.
+  if (aSkipSides ||
+      border.left != border.right ||
+      border.left != border.top ||
+      border.left != border.bottom)
+  {
+    doSeparateSides = PR_TRUE;
+  } else {
+    doSeparateSides = ShouldDoSeparateSides (aBorderStyle, ourColor);
   }
 
-#ifdef MOZ_CAIRO_GFX
-  ctx->SetAntialiasMode(oldMode);
+  SF("doSeparateSides: %d skipsides: t:%d l:%d r:%d b:%d\n", doSeparateSides,
+     (aSkipSides & SIDE_BIT_TOP) ? 1 : 0,
+     (aSkipSides & SIDE_BIT_LEFT) ? 1 : 0,
+     (aSkipSides & SIDE_BIT_RIGHT) ? 1 : 0,
+     (aSkipSides & SIDE_BIT_BOTTOM) ? 1 : 0);
+
+  // the outside border rect
+  gfxRect oRect(gfxFloat(outerRect.x) / twipsPerPixel,
+                gfxFloat(outerRect.y) / twipsPerPixel,
+                gfxFloat(outerRect.width) / twipsPerPixel,
+                gfxFloat(outerRect.height) / twipsPerPixel);
+
+  // the inside border rect
+  gfxRect iRect(gfxFloat(innerRect.x) / twipsPerPixel,
+                gfxFloat(innerRect.y) / twipsPerPixel,
+                gfxFloat(innerRect.width) / twipsPerPixel,
+                gfxFloat(innerRect.height) / twipsPerPixel);
+
+
+  // round oRect and iRect; they're already an integer
+  // number of pixels apart and should stay that way after
+  // rounding.
+  oRect.Round();
+  iRect.Round();
+
+  // the border "line", right down the middle of each border edge
+  // lRect must NOT be rounded
+  gfxRect lRect(oRect.pos.x + border.left / (2.0 * twipsPerPixel),
+                oRect.pos.y + border.top / (2.0 * twipsPerPixel),
+                oRect.size.width - (border.left + border.right) / (2.0 * twipsPerPixel),
+                oRect.size.height - (border.top + border.bottom) / (2.0 * twipsPerPixel));
+
+
+  S(" oRect: "), S(oRect), SN();
+  S(" iRect: "), S(iRect), SN();
+  S(" lRect: "), S(lRect), SN();
+
+  ctx->Save();
+
+#if 0
+  // this will draw a transparent red backround underneath the area between iRect and oRect
+  ctx->Save();
+  ctx->Rectangle(iRect);
+  ctx->Clip();
+  ctx->NewPath();
+
+  ctx->Rectangle(oRect);
+  ctx->SetColor(gfxRGBA(1.0, 0.0, 0.0, 0.5));
+  ctx->Fill();
+  ctx->Restore();
 #endif
-}
-
-void nsCSSRendering::DrawCompositeSide(nsIRenderingContext& aRenderingContext,
-                                       PRIntn aWhichSide,
-                                       nsBorderColors* aCompositeColors,
-                                       const nsRect& aOuterRect,
-                                       const nsRect& aInnerRect,
-                                       PRInt16* aBorderRadii,
-                                       nscoord twipsPerPixel,
-                                       nsRect* aGap)
-
-{
-  // Loop over each color and at each iteration shrink the length of the
-  // lines that we draw.
-  nsRect currOuterRect(aOuterRect);
-
-  // XXXdwh This border radius code is rather hacky and will only work for
-  // small radii, but it will be sufficient to get a major performance
-  // improvement in themes with small curvature (like Modern).
-  // Still, this code should be rewritten if/when someone chooses to pick
-  // up the -moz-border-radius gauntlet.
-  // Alternatively we could add support for a -moz-border-diagonal property, which is
-  // what this code actually draws (instead of a curve).
-
-  // determine the number of pixels we need to draw for this side
-  // and the start and end radii
-  nscoord shrinkage, startRadius, endRadius;
-  if (aWhichSide == NS_SIDE_TOP) {
-    shrinkage = aInnerRect.y - aOuterRect.y;
-    startRadius = aBorderRadii[0];
-    endRadius = aBorderRadii[1];
-  } else if (aWhichSide == NS_SIDE_BOTTOM) {
-    shrinkage = (aOuterRect.height+aOuterRect.y) - (aInnerRect.height+aInnerRect.y);
-    startRadius = aBorderRadii[3];
-    endRadius = aBorderRadii[2];
-  } else if (aWhichSide == NS_SIDE_RIGHT) {
-    shrinkage = (aOuterRect.width+aOuterRect.x) - (aInnerRect.width+aInnerRect.x);
-    startRadius = aBorderRadii[1];
-    endRadius = aBorderRadii[2];
-  } else {
-    NS_ASSERTION(aWhichSide == NS_SIDE_LEFT, "incorrect aWhichSide");
-    shrinkage = aInnerRect.x - aOuterRect.x;
-    startRadius = aBorderRadii[0];
-    endRadius = aBorderRadii[3];
+
+  // Clamp the CTM to be pixel-aligned; we do this only
+  // for translation-only matrices now, but we could do it
+  // if the matrix has just a scale as well.  We should not
+  // do it if there's a rotation.
+  gfxMatrix mat = ctx->CurrentMatrix();
+  if (!mat.HasNonTranslation()) {
+    mat.x0 = floor(mat.x0 + 0.5);
+    mat.y0 = floor(mat.y0 + 0.5);
+    ctx->SetMatrix(mat);
   }
 
-  while (shrinkage > 0) {
-    nscoord xshrink = 0;
-    nscoord yshrink = 0;
-    nscoord widthshrink = 0;
-    nscoord heightshrink = 0;
-
-    if (startRadius || endRadius) {
-      if (aWhichSide == NS_SIDE_TOP || aWhichSide == NS_SIDE_BOTTOM) {
-        xshrink = startRadius;
-        widthshrink = startRadius + endRadius;
-      }
-      else if (aWhichSide == NS_SIDE_LEFT || aWhichSide == NS_SIDE_RIGHT) {
-        yshrink = startRadius-1;
-        heightshrink = yshrink + endRadius;
-      }
-    }
-
-    // subtract any rounded pixels from the outer rect
-    nsRect newOuterRect(currOuterRect);
-    newOuterRect.x += xshrink;
-    newOuterRect.y += yshrink;
-    newOuterRect.width -= widthshrink;
-    newOuterRect.height -= heightshrink;
-
-    nsRect borderInside(currOuterRect);
-    
-    // try to subtract one pixel from each side of the outer rect, but only if 
-    // that side has any extra space left to shrink
-    if (aInnerRect.x > borderInside.x) { // shrink left
-      borderInside.x += twipsPerPixel;
-      borderInside.width -= twipsPerPixel;
-    }
-    if (borderInside.x+borderInside.width > aInnerRect.x+aInnerRect.width) // shrink right
-      borderInside.width -= twipsPerPixel;
-    
-    if (aInnerRect.y > borderInside.y) { // shrink top
-      borderInside.y += twipsPerPixel;
-      borderInside.height -= twipsPerPixel;
+  // if we're going to do separate sides, we need to do it as
+  // a temporary surface group
+  if (doSeparateSides) {
+    // clip to oRect to define the size of the temporary surface
+    ctx->NewPath();
+    ctx->Rectangle(oRect);
+
+    if (aGap) {
+      gfxRect gapRect(gfxFloat(aGap->x) / twipsPerPixel,
+                      gfxFloat(aGap->y) / twipsPerPixel,
+                      gfxFloat(aGap->width) / twipsPerPixel,
+                      gfxFloat(aGap->height) / twipsPerPixel);
+      ctx->Rectangle(gapRect);
+      ctx->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
+      ctx->Clip();
+      ctx->SetFillRule(gfxContext::FILL_RULE_WINDING);
+    } else {
+      ctx->Clip();
     }
-    if (borderInside.y+borderInside.height > aInnerRect.y+aInnerRect.height) // shrink bottom
-      borderInside.height -= twipsPerPixel;
-
-    if (!aCompositeColors->mTransparent) {
-      nsPoint theSide[MAX_POLY_POINTS];
-      PRInt32 np = MakeSide(theSide, aRenderingContext, aWhichSide, newOuterRect, borderInside, 0,
-                            BORDER_FULL, 1.0f, twipsPerPixel);
-      NS_ASSERTION(np == 2, "Composite border should always be single pixel!");
-      aRenderingContext.SetColor(aCompositeColors->mColor);
-      DrawLine(aRenderingContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
-    
-      if (aWhichSide == NS_SIDE_TOP) {
-        if (startRadius) {
-          // Connecting line between top/left
-          nscoord distance = (startRadius+twipsPerPixel)/2;
-          nscoord remainder = distance%twipsPerPixel;
-          if (remainder) 
-            distance += twipsPerPixel - remainder;
-          DrawLine(aRenderingContext,
-                   currOuterRect.x+startRadius,
-                   currOuterRect.y, 
-                   currOuterRect.x+startRadius-distance,
-                   currOuterRect.y+distance,
-                   aGap);
-        }
-        if (endRadius) {
-          // Connecting line between top/right
-          nscoord distance = (endRadius+twipsPerPixel)/2;
-          nscoord remainder = distance%twipsPerPixel;
-          if (remainder) 
-            distance += twipsPerPixel - remainder;
-          DrawLine(aRenderingContext,
-                   currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel,
-                   currOuterRect.y, 
-                   currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel+distance,
-                   currOuterRect.y+distance,
-                   aGap);
-        }
-      }
-      else if (aWhichSide == NS_SIDE_BOTTOM) {
-        if (startRadius) {
-          // Connecting line between bottom/left
-          nscoord distance = (startRadius+twipsPerPixel)/2;
-          nscoord remainder = distance%twipsPerPixel;
-          if (remainder) 
-            distance += twipsPerPixel - remainder;
-          DrawLine(aRenderingContext,
-                   currOuterRect.x+startRadius, 
-                   currOuterRect.y+currOuterRect.height-twipsPerPixel,
-                   currOuterRect.x+startRadius-distance, 
-                   currOuterRect.y+currOuterRect.height-twipsPerPixel-distance,
-                   aGap);
-        }
-        if (endRadius) {
-          // Connecting line between bottom/right
-          nscoord distance = (endRadius+twipsPerPixel)/2;
-          nscoord remainder = distance%twipsPerPixel;
-          if (remainder) 
-            distance += twipsPerPixel - remainder;
-          DrawLine(aRenderingContext,
-                   currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel, 
-                   currOuterRect.y+currOuterRect.height-twipsPerPixel, 
-                   currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel+distance, 
-                   currOuterRect.y+currOuterRect.height-twipsPerPixel-distance,
-                   aGap);
-        }
-      }
-      else if (aWhichSide == NS_SIDE_LEFT) {
-        if (startRadius) {
-          // Connecting line between left/top
-          nscoord distance = (startRadius-twipsPerPixel)/2;
-          nscoord remainder = distance%twipsPerPixel;
-          if (remainder)
-            distance -= remainder;
-          DrawLine(aRenderingContext,
-                   currOuterRect.x+distance,
-                   currOuterRect.y+startRadius-distance, 
-                   currOuterRect.x,
-                   currOuterRect.y+startRadius,
-                   aGap);
-        }
-        if (endRadius) {
-          // Connecting line between left/bottom
-          nscoord distance = (endRadius-twipsPerPixel)/2;
-          nscoord remainder = distance%twipsPerPixel;
-          if (remainder)
-            distance -= remainder;
-          DrawLine(aRenderingContext,
-                   currOuterRect.x+distance,
-                   currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius+distance,
-                   currOuterRect.x,
-                   currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius,
-                   aGap);
-        }
-      }
-      else if (aWhichSide == NS_SIDE_RIGHT) {
-       if (startRadius) {
-          // Connecting line between right/top
-          nscoord distance = (startRadius-twipsPerPixel)/2;
-          nscoord remainder = distance%twipsPerPixel;
-          if (remainder)
-            distance -= remainder;
-          DrawLine(aRenderingContext,
-                   currOuterRect.x+currOuterRect.width-twipsPerPixel-distance,
-                   currOuterRect.y+startRadius-distance, 
-                   currOuterRect.x+currOuterRect.width-twipsPerPixel,
-                   currOuterRect.y+startRadius,
-                   aGap);
-        }
-        if (endRadius) {
-          // Connecting line between right/bottom
-          nscoord distance = (endRadius-twipsPerPixel)/2;
-          nscoord remainder = distance%twipsPerPixel;
-          if (remainder)
-            distance -= remainder;
-          DrawLine(aRenderingContext,
-                   currOuterRect.x+currOuterRect.width-twipsPerPixel-distance, 
-                   currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius+distance,
-                   currOuterRect.x+currOuterRect.width-twipsPerPixel, 
-                   currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius,
-                   aGap);
-        }
-      }
+
+    // start a compositing group and render using ADD so that
+    // we get correct behaviour at the joins
+    ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
+    ctx->SetOperator(gfxContext::OPERATOR_ADD);
+  } else if (aGap) {
+    gfxRect gapRect(gfxFloat(aGap->x) / twipsPerPixel,
+                    gfxFloat(aGap->y) / twipsPerPixel,
+                    gfxFloat(aGap->width) / twipsPerPixel,
+                    gfxFloat(aGap->height) / twipsPerPixel);
+    ctx->Rectangle(gapRect);
+    ctx->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
+    ctx->Clip();
+    ctx->SetFillRule(gfxContext::FILL_RULE_WINDING);
+  }
+
+  // If we're doing separateSides, then do all 4 sides.
+  // Otherwise, we can just use the style of the first side
+  // (since all 4 are identical) and not set any clip so that
+  // DrawBorderSides draws the entire border in one go.
+  int numSides = doSeparateSides ? 4 : 1;
+  for (PRInt32 i = 0; i < numSides; i++) {
+    PRUint8 side = sideOrder[i];
+
+    // skip this side if it's, well, skipped
+    if (doSeparateSides) {
+      if (aSkipSides & (1 << side))
+        continue;
+
+      ctx->Save();
+
+      PRUint8 style = aBorderStyle.GetBorderStyle(side);
+
+      // Figure out how to clip to this side.  We have three options; see
+      // the comments for DoSideClipPath for more details.
+      //
+      // TRAPEZOID_FULL: used when we have a border radius to get the curve
+      // that's inside iRect to appear and not get clipped out.  It's technically
+      // a triangle.
+      //
+      // RECTANGLE: used for dotted/dashed borders so that we can draw the right
+      // sides correctly.
+      //
+      // TRAPEZOID: used in all other cases.  The trapezoid formed by the relevant
+      // corners of iRect and oRect.
+      DoSideClipPath(ctx, iRect, oRect, lRect, side, aBorderStyle, borderRadii);
+      ctx->Clip();
     }
-    
-    if (aCompositeColors->mNext)
-      aCompositeColors = aCompositeColors->mNext;
-
-    currOuterRect = borderInside;
-    shrinkage -= twipsPerPixel;
-    
-    startRadius -= twipsPerPixel;
-    if (startRadius < 0) startRadius = 0;
-    endRadius -= twipsPerPixel;
-    if (endRadius < 0) endRadius = 0;
+
+    // Draw the whole border along lRect.  If we're not doing doSeparateSides,
+    // then sides are identical and no clip was set -- this will draw the entire border.
+    // Otherwise, this will still draw the entire border in the style of this side, but it
+    // will be clipped by the above code.  We do this to get the joins looking correct.
+
+    nscolor borderRenderColor;
+    PRBool transparent, foreground;
+    nsBorderColors *compositeColors = nsnull;
+
+    aBorderStyle.GetBorderColor(side, borderRenderColor, transparent, foreground);
+    aBorderStyle.GetCompositeColors(side, &compositeColors);
+
+    if (!transparent || compositeColors) {
+      if (foreground)
+        borderRenderColor = ourColor->mColor;
+
+      PRUint32 borderWidth = border.side(side) / twipsPerPixel;
+      NS_ASSERTION(borderWidth * twipsPerPixel == border.side(side), "Border size from style system was not an integer number of pixels!");
+      DrawBorderSides(ctx,
+                      borderWidth,
+                      aBorderStyle.GetBorderStyle(side),
+                      borderRenderColor,
+                      compositeColors,
+                      iRect, oRect, lRect,
+                      ourColor->mColor, bgColor->mBackgroundColor,
+                      doSeparateSides, side,
+                      twipsPerPixel,
+                      haveBorderRadius ? borderRadii : nsnull);
+    }
+
+    if (doSeparateSides)
+      ctx->Restore();
   }
+
+  if (doSeparateSides) {
+    ctx->PopGroupToSource();
+    ctx->Paint();
+  }
+
+  ctx->Restore();
+
+  SN();
 }
 
-// XXX improve this to constrain rendering to the damaged area
-void nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
-                                 nsIRenderingContext& aRenderingContext,
-                                 nsIFrame* aForFrame,
-                                 const nsRect& aDirtyRect,
-                                 const nsRect& aBorderArea,
-                                 const nsStyleBorder& aBorderStyle,
-                                 const nsStyleOutline& aOutlineStyle,
-                                 nsStyleContext* aStyleContext,
-                                 PRIntn aSkipSides,
-                                 nsRect* aGap)
+void
+nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
+                             nsIRenderingContext& aRenderingContext,
+                             nsIFrame* aForFrame,
+                             const nsRect& aDirtyRect,
+                             const nsRect& aBorderArea,
+                             const nsStyleBorder& aBorderStyle,
+                             const nsStyleOutline& aOutlineStyle,
+                             nsStyleContext* aStyleContext,
+                             nsRect* aGap)
 {
-nsStyleCoord        bordStyleRadius[4];
-PRInt16             borderRadii[4],i;
-float               percent;
-const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
-nscoord width, offset;
+  nsStyleCoord        bordStyleRadius[4];
+  PRInt16             borderRadii[4],i;
+
+  PRBool haveBorderRadius = PR_FALSE;
 
   // Get our style context's color struct.
   const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
 
+  nscoord width, offset;
+  float percent;
+
   aOutlineStyle.GetOutlineWidth(width);
 
-  if (0 == width) {
+  if (width == 0) {
     // Empty outline
     return;
   }
 
+  const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground
+    (aStyleContext, PR_FALSE);
+
   // get the radius for our outline
   aOutlineStyle.mOutlineRadius.GetTop(bordStyleRadius[0]);      //topleft
   aOutlineStyle.mOutlineRadius.GetRight(bordStyleRadius[1]);    //topright
   aOutlineStyle.mOutlineRadius.GetBottom(bordStyleRadius[2]);   //bottomright
   aOutlineStyle.mOutlineRadius.GetLeft(bordStyleRadius[3]);     //bottomleft
 
-  for(i=0;i<4;i++) {
+  // convert percentage values
+  for (i = 0; i < 4; i++) {
     borderRadii[i] = 0;
-    switch ( bordStyleRadius[i].GetUnit()) {
-    case eStyleUnit_Percent:
-      percent = bordStyleRadius[i].GetPercentValue();
-      borderRadii[i] = (nscoord)(percent * aBorderArea.width);
-      break;
-    case eStyleUnit_Coord:
-      borderRadii[i] = bordStyleRadius[i].GetCoordValue();
-      break;
-    default:
-      break;
+
+    switch (bordStyleRadius[i].GetUnit()) {
+      case eStyleUnit_Percent:
+        percent = bordStyleRadius[i].GetPercentValue();
+        borderRadii[i] = (nscoord)(percent * aBorderArea.width);
+        break;
+
+      case eStyleUnit_Coord:
+        borderRadii[i] = bordStyleRadius[i].GetCoordValue();
+        break;
+
+      default:
+        break;
     }
+
+    if (borderRadii[i])
+      haveBorderRadius = PR_TRUE;
   }
 
   nsRect overflowArea = aForFrame->GetOverflowRect();
 
   // get the offset for our outline
   aOutlineStyle.GetOutlineOffset(offset);
   nsRect outside(overflowArea + aBorderArea.TopLeft());
   nsRect inside(outside);
@@ -2061,239 +2300,201 @@ nscoord width, offset;
     inside.Deflate(-offset, -offset);
     if (inside.width < 0 || inside.height < 0) {
       return; // Protect against negative outline sizes
     }
     outside = inside;
     outside.Inflate(width, width);
   }
 
-  // rounded version of the border
-  for(i=0;i<4;i++){
-    if(borderRadii[i] > 0){
-      PaintRoundedBorder(aPresContext, aRenderingContext, aForFrame, aDirtyRect,
-                         outside, nsnull, &aOutlineStyle, aStyleContext, 
-                         aSkipSides, borderRadii, aGap, PR_TRUE);
-      return;
-    }
-  }
-
-
-  PRUint8 outlineStyle = aOutlineStyle.GetOutlineStyle();
-  //see if any sides are dotted or dashed
-  if ((outlineStyle == NS_STYLE_BORDER_STYLE_DOTTED) || 
-      (outlineStyle == NS_STYLE_BORDER_STYLE_DASHED))  {
-    DrawDashedSides(0, aRenderingContext, aDirtyRect, ourColor, nsnull, &aOutlineStyle, PR_TRUE,
-                    outside, inside, aSkipSides, aGap);
+  // If the dirty rect is completely inside the border area (e.g., only the
+  // content is being painted), then we can skip out now
+  // XXX this isn't exactly true for rounded borders, where the inside curves may
+  // encroach into the content area.  A safer calculation would be to
+  // shorten insideRect by the radius one each side before performing this test.
+  if (inside.Contains(aDirtyRect)) {
     return;
   }
 
-  // Draw all the other sides
-
-  PRInt32 appUnitsPerPixel = aPresContext->DevPixelsToAppUnits(1);
+  // The border radius has to be equal to or less than half the length
+  // of the two sides that form the corner.  I think this is what trunk does;
+  // without this check, the result is still well defined: the center of the
+  // arc created by the corner is always inset by (radius,radius) from the
+  // relevant corner, even if that causes it to go into another quadrant.
+  if (haveBorderRadius) {
+    borderRadii[0] = PR_MIN(borderRadii[0], (inside.width + width) / 2);
+    borderRadii[0] = PR_MIN(borderRadii[0], (inside.height + width) / 2);
+
+    borderRadii[1] = PR_MIN(borderRadii[1], (inside.width + width) / 2);
+    borderRadii[1] = PR_MIN(borderRadii[1], (inside.height + width) / 2);
+
+    borderRadii[2] = PR_MIN(borderRadii[2], (inside.width + width) / 2);
+    borderRadii[2] = PR_MIN(borderRadii[2], (inside.height + width) / 2);
+
+    borderRadii[3] = PR_MIN(borderRadii[3], (inside.width + width) / 2);
+    borderRadii[3] = PR_MIN(borderRadii[3], (inside.height + width) / 2);
+  }
+
+  /* Get our conversion values */
+  nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
+
+  gfxRect oRect(gfxFloat(outside.x) / twipsPerPixel,
+                gfxFloat(outside.y) / twipsPerPixel,
+                gfxFloat(outside.width) / twipsPerPixel,
+                gfxFloat(outside.height) / twipsPerPixel);
+
+  gfxRect iRect(gfxFloat(inside.x) / twipsPerPixel,
+                gfxFloat(inside.y) / twipsPerPixel,
+                gfxFloat(inside.width) / twipsPerPixel,
+                gfxFloat(inside.height) / twipsPerPixel);
+
+  oRect.Round();
+  iRect.Round();
+
+  // the border "line", right down the middle of each border edge
+  // lRect must NOT be rounded
+  gfxRect lRect(oRect.pos.x + width / (2.0 * twipsPerPixel),
+                oRect.pos.y + width / (2.0 * twipsPerPixel),
+                oRect.size.width - (2*width) / (2.0 * twipsPerPixel),
+                oRect.size.height - (2*width) / (2.0 * twipsPerPixel));
 
   // default to current color in case it is invert color
   // and the platform does not support that
   nscolor outlineColor(ourColor->mColor);
-  PRBool  canDraw = PR_FALSE;
-#ifdef GFX_HAS_INVERT
-  PRBool  modeChanged=PR_FALSE;
-#endif
-
-  // see if the outline color is special color.
-  if (aOutlineStyle.GetOutlineInitialColor()) {
-    canDraw = PR_TRUE;
-#ifdef GFX_HAS_INVERT
-    if( NS_SUCCEEDED(aRenderingContext.SetPenMode(nsPenMode_kInvert)) ) {
-      modeChanged=PR_TRUE;
-    }
-#endif
-  } else {
-    canDraw = aOutlineStyle.GetOutlineColor(outlineColor);
+
+  // grab the thebes context
+  nsRefPtr<gfxContext> ctx = (gfxContext*)
+    aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
+
+  PRUint8 outlineStyle = aOutlineStyle.GetOutlineStyle();
+  if (!aOutlineStyle.GetOutlineColor(outlineColor))
+    return;
+
+  ctx->Save();
+
+  // Clamp the CTM to be pixel-aligned; we do this only
+  // for translation-only matrices now, but we could do it
+  // if the matrix has just a scale as well.  We should not
+  // do it if there's a rotation.
+  gfxMatrix mat = ctx->CurrentMatrix();
+  if (!mat.HasNonTranslation()) {
+    mat.x0 = floor(mat.x0 + 0.5);
+    mat.y0 = floor(mat.y0 + 0.5);
+    ctx->SetMatrix(mat);
+  }
+
+  PRBool doSeparateSides = PR_FALSE;
+  if (outlineStyle == NS_STYLE_BORDER_STYLE_DASHED ||
+      outlineStyle == NS_STYLE_BORDER_STYLE_DOTTED)
+  {
+    doSeparateSides = PR_TRUE;
   }
 
-  if (PR_TRUE == canDraw) {
-    DrawSide(aRenderingContext, NS_SIDE_BOTTOM,
-             outlineStyle,
-             outlineColor,
-             bgColor->mBackgroundColor, outside, inside, aSkipSides,
-             appUnitsPerPixel, aGap);
-
-    DrawSide(aRenderingContext, NS_SIDE_LEFT,
-             outlineStyle, 
-             outlineColor,
-             bgColor->mBackgroundColor,outside, inside,aSkipSides,
-             appUnitsPerPixel, aGap);
-
-    DrawSide(aRenderingContext, NS_SIDE_TOP,
-             outlineStyle,
-             outlineColor,
-             bgColor->mBackgroundColor,outside, inside,aSkipSides,
-             appUnitsPerPixel, aGap);
-
-    DrawSide(aRenderingContext, NS_SIDE_RIGHT,
-             outlineStyle,
-             outlineColor,
-             bgColor->mBackgroundColor,outside, inside,aSkipSides,
-             appUnitsPerPixel, aGap);
-#ifdef GFX_HAS_INVERT
-    if(modeChanged ) {
-      aRenderingContext.SetPenMode(nsPenMode_kNone);
+  // if we're going to do separate sides, we need to do it as
+  // a temporary surface group
+  if (doSeparateSides) {
+    // clip to oRect to define the size of the temporary surface
+    ctx->NewPath();
+    ctx->Rectangle(oRect);
+
+    if (aGap) {
+      gfxRect gapRect(gfxFloat(aGap->x) / twipsPerPixel,
+                      gfxFloat(aGap->y) / twipsPerPixel,
+                      gfxFloat(aGap->width) / twipsPerPixel,
+                      gfxFloat(aGap->height) / twipsPerPixel);
+      ctx->Rectangle(gapRect);
+      ctx->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
+      ctx->Clip();
+      ctx->SetFillRule(gfxContext::FILL_RULE_WINDING);
+    } else {
+      ctx->Clip();
     }
-#endif
-  }
-}
-
-/* draw the edges of the border described in aBorderEdges one segment at a time.
- * a border has 4 edges.  Each edge has 1 or more segments. 
- * "inside edges" are drawn differently than "outside edges" so the shared edges will match up.
- * in the case of table collapsing borders, the table edge is the "outside" edge and
- * cell edges are always "inside" edges (so adjacent cells have 2 shared "inside" edges.)
- * dashed segments are drawn by DrawDashedSegments().
- */
-// XXX: doesn't do corners or junctions well at all.  Just uses logic stolen 
-//      from PaintBorder which is insufficient
-
-void nsCSSRendering::PaintBorderEdges(nsPresContext* aPresContext,
-                                      nsIRenderingContext& aRenderingContext,
-                                      nsIFrame* aForFrame,
-                                      const nsRect& aDirtyRect,
-                                      const nsRect& aBorderArea,
-                                      nsBorderEdges * aBorderEdges,
-                                      nsStyleContext* aStyleContext,
-                                      PRIntn aSkipSides,
-                                      nsRect* aGap)
-{
-  const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
-  
-  if (nsnull==aBorderEdges) {  // Empty border segments
-    return;
+
+    // start a compositing group and render using ADD so that
+    // we get correct behaviour at the joins
+    ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
+    ctx->SetOperator(gfxContext::OPERATOR_ADD);
+  } else if (aGap) {
+    gfxRect gapRect(gfxFloat(aGap->x) / twipsPerPixel,
+                    gfxFloat(aGap->y) / twipsPerPixel,
+                    gfxFloat(aGap->width) / twipsPerPixel,
+                    gfxFloat(aGap->height) / twipsPerPixel);
+    ctx->Rectangle(gapRect);
+    ctx->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
+    ctx->Clip();
+    ctx->SetFillRule(gfxContext::FILL_RULE_WINDING);
   }
 
-  // Turn off rendering for all of the zero sized sides
-  if (0 == aBorderEdges->mMaxBorderWidth.top) 
-    aSkipSides |= (1 << NS_SIDE_TOP);
-  if (0 == aBorderEdges->mMaxBorderWidth.right) 
-    aSkipSides |= (1 << NS_SIDE_RIGHT);
-  if (0 == aBorderEdges->mMaxBorderWidth.bottom) 
-    aSkipSides |= (1 << NS_SIDE_BOTTOM);
-  if (0 == aBorderEdges->mMaxBorderWidth.left) 
-    aSkipSides |= (1 << NS_SIDE_LEFT);
-
-  // Draw any dashed or dotted segments separately
-  DrawDashedSegments(aRenderingContext, aBorderArea, aBorderEdges, aSkipSides, aGap);
-
-  // Draw all the other sides
-  nscoord appUnitsPerPixel = nsPresContext::AppUnitsPerCSSPixel();
-
-  if (0 == (aSkipSides & (1<<NS_SIDE_TOP))) {
-    PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_TOP].Count();
-    PRInt32 i;
-    nsBorderEdge * leftEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
-    nscoord x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
-    for (i=0; i<segmentCount; i++)
-    {
-      nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(i));
-      nscoord y = aBorderArea.y;
-      if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are bottom-aligned
-        y += aBorderEdges->mMaxBorderWidth.top - borderEdge->mWidth;
-      nsRect inside(x, y, borderEdge->mLength, aBorderArea.height);
-      x += borderEdge->mLength;
-      nsRect outside(inside);
-      nsMargin outsideMargin(0, borderEdge->mWidth, 0, 0);
-      outside.Deflate(outsideMargin);
-      DrawSide(aRenderingContext, NS_SIDE_TOP,
-               borderEdge->mStyle,
-               borderEdge->mColor,
-               bgColor->mBackgroundColor,
-               inside, outside,aSkipSides,
-               appUnitsPerPixel, aGap);
+  // If we're doing separateSides, then do all 4 sides.
+  // Otherwise, we can just use the style of the first side
+  // (since all 4 are identical) and not set any clip so that
+  // DrawBorderSides draws the entire border in one go.
+
+  static PRUint8 sideOrder[] = { NS_SIDE_BOTTOM, NS_SIDE_LEFT, NS_SIDE_TOP, NS_SIDE_RIGHT };
+
+  int numSides = doSeparateSides ? 4 : 1;
+  for (PRInt32 i = 0; i < numSides; i++) {
+    PRUint8 side = sideOrder[i];
+
+    // skip this side if it's, well, skipped
+    if (doSeparateSides) {
+      ctx->Save();
+
+      PRUint8 style = outlineStyle;
+
+      // Figure out how to clip to this side.  We have three options; see
+      // the comments for DoSideClipPath for more details.
+      //
+      // TRAPEZOID_FULL: used when we have a border radius to get the curve
+      // that's inside iRect to appear and not get clipped out.  It's technically
+      // a triangle.
+      //
+      // RECTANGLE: used for dotted/dashed borders so that we can draw the right
+      // sides correctly.
+      //
+      // TRAPEZOID: used in all other cases.  The trapezoid formed by the relevant
+      // corners of iRect and oRect.
+      DoSideClipPath(ctx, iRect, oRect, lRect, side, aBorderStyle, borderRadii);
+      ctx->Clip();
     }
+
+    // Draw the whole border along lRect.  If we're not doing doSeparateSides,
+    // then sides are identical and no clip was set -- this will draw the entire border.
+    // Otherwise, this will still draw the entire border in the style of this side, but it
+    // will be clipped by the above code.  We do this to get the joins looking correct.
+
+    PRUint32 outlineWidth = NSToCoordRound(float(gfxFloat(width) / twipsPerPixel));
+    DrawBorderSides(ctx,
+                    outlineWidth,
+                    outlineStyle,
+                    outlineColor,
+                    nsnull,
+                    iRect, oRect, lRect,
+                    outlineColor, bgColor->mBackgroundColor,
+                    doSeparateSides, side,
+                    twipsPerPixel,
+                    haveBorderRadius ? borderRadii : nsnull);
+
+    if (doSeparateSides)
+      ctx->Restore();
   }
-  if (0 == (aSkipSides & (1<<NS_SIDE_LEFT))) {
-    PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_LEFT].Count();
-    PRInt32 i;
-    nsBorderEdge * topEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(0));
-    nscoord y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
-    for (i=0; i<segmentCount; i++)
-    {
-      nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(i));
-      nscoord x = aBorderArea.x + (aBorderEdges->mMaxBorderWidth.left - borderEdge->mWidth);
-      nsRect inside(x, y, aBorderArea.width, borderEdge->mLength);
-      y += borderEdge->mLength;
-      nsRect outside(inside);
-      nsMargin outsideMargin(borderEdge->mWidth, 0, 0, 0);
-      outside.Deflate(outsideMargin);
-      DrawSide(aRenderingContext, NS_SIDE_LEFT,
-               borderEdge->mStyle,
-               borderEdge->mColor,
-               bgColor->mBackgroundColor,
-               inside, outside, aSkipSides,
-               appUnitsPerPixel, aGap);
-    }
+
+  if (doSeparateSides) {
+    ctx->PopGroupToSource();
+    ctx->Paint();
   }
-  if (0 == (aSkipSides & (1<<NS_SIDE_BOTTOM))) {
-    PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_BOTTOM].Count();
-    PRInt32 i;
-    nsBorderEdge * leftEdge =  (nsBorderEdge *)
-      (aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(aBorderEdges->mEdges[NS_SIDE_LEFT].Count()-1));
-    nscoord x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
-    for (i=0; i<segmentCount; i++)
-    {
-      nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_BOTTOM].ElementAt(i));
-      nscoord y = aBorderArea.y;
-      if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are top-aligned
-        y -= (aBorderEdges->mMaxBorderWidth.bottom - borderEdge->mWidth);
-      nsRect inside(x, y, borderEdge->mLength, aBorderArea.height);
-      x += borderEdge->mLength;
-      nsRect outside(inside);
-      nsMargin outsideMargin(0, 0, 0, borderEdge->mWidth);
-      outside.Deflate(outsideMargin);
-      DrawSide(aRenderingContext, NS_SIDE_BOTTOM,
-               borderEdge->mStyle,
-               borderEdge->mColor,
-               bgColor->mBackgroundColor,
-               inside, outside,aSkipSides,
-               appUnitsPerPixel, aGap);
-    }
-  }
-  if (0 == (aSkipSides & (1<<NS_SIDE_RIGHT))) {
-    PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_RIGHT].Count();
-    PRInt32 i;
-    nsBorderEdge * topEdge =  (nsBorderEdge *)
-      (aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(aBorderEdges->mEdges[NS_SIDE_TOP].Count()-1));
-    nscoord y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
-    for (i=0; i<segmentCount; i++)
-    {
-      nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_RIGHT].ElementAt(i));
-      nscoord width;
-      if (PR_TRUE==aBorderEdges->mOutsideEdge)
-      {
-        width = aBorderArea.width - aBorderEdges->mMaxBorderWidth.right;
-        width += borderEdge->mWidth;
-      }
-      else
-      {
-        width = aBorderArea.width;
-      }
-      nsRect inside(aBorderArea.x, y, width, borderEdge->mLength);
-      y += borderEdge->mLength;
-      nsRect outside(inside);
-      nsMargin outsideMargin(0, 0, (borderEdge->mWidth), 0);
-      outside.Deflate(outsideMargin);
-      DrawSide(aRenderingContext, NS_SIDE_RIGHT,
-               borderEdge->mStyle,
-               borderEdge->mColor,
-               bgColor->mBackgroundColor,
-               inside, outside,aSkipSides,
-               appUnitsPerPixel, aGap);
-    }
-  }
+
+  ctx->Restore();
+
+  SN();
 }
 
+// Thebes Border Rendering Code End
+//----------------------------------------------------------------------
+
 
 //----------------------------------------------------------------------
 
 // Returns the anchor point to use for the background image. The
 // anchor point is the (x, y) location where the first tile should
 // be placed
 //
 // For repeated tiling, the anchor values are normalized wrt to the upper-left
@@ -3380,327 +3581,16 @@ nsCSSRendering::PaintRoundedBackground(n
   thePath[np++].MoveTo(cr1.mAnc1.x, cr1.mAnc1.y);
   thePath[np++].MoveTo(cr1.mCon.x, cr1.mCon.y);
   thePath[np++].MoveTo(cr1.mAnc2.x, cr1.mAnc2.y);
   GetPath(thePath,polyPath,&curIndex,eOutside,c1Index);
 
   aRenderingContext.FillPolygon(polyPath,curIndex); 
 }
 
-
-/** ---------------------------------------------------
- *  See documentation in nsCSSRendering.h
- *  @update 3/26/99 dwc
- */
-void 
-nsCSSRendering::PaintRoundedBorder(nsPresContext* aPresContext,
-                                 nsIRenderingContext& aRenderingContext,
-                                 nsIFrame* aForFrame,
-                                 const nsRect& aDirtyRect,
-                                 const nsRect& aBorderArea,
-                                 const nsStyleBorder* aBorderStyle,
-                                 const nsStyleOutline* aOutlineStyle,
-                                 nsStyleContext* aStyleContext,
-                                 PRIntn aSkipSides,
-                                 PRInt16 aBorderRadius[4],
-                                 nsRect* aGap,
-                                 PRBool aIsOutline)
-{
-  RoundedRect   outerPath;
-  QBCurve       UL,LL,UR,LR;
-  QBCurve       IUL,ILL,IUR,ILR;
-  QBCurve       cr1,cr2,cr3,cr4;
-  QBCurve       Icr1,Icr2,Icr3,Icr4;
-  nsFloatPoint  thePath[MAXPATHSIZE];
-  PRInt16       np;
-  nsMargin      border;
-
-  NS_ASSERTION((aIsOutline && aOutlineStyle) || (!aIsOutline && aBorderStyle), "null params not allowed");
-  if (!aIsOutline) {
-    border = aBorderStyle->GetBorder();
-    if ((0 == border.left) && (0 == border.right) &&
-        (0 == border.top) && (0 == border.bottom)) {
-      return;
-    }
-  } else {
-    nscoord width;
-    if (!aOutlineStyle->GetOutlineWidth(width)) {
-      return;
-    }
-    border.left   = width;
-    border.right  = width;
-    border.top    = width;
-    border.bottom = width;
-  }
-
-  // needed for our border thickness
-  nscoord appUnitsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-  nscoord quarterPixel = appUnitsPerPixel / 4;
-
-  outerPath.Set(aBorderArea.x, aBorderArea.y, aBorderArea.width,
-                aBorderArea.height, aBorderRadius, appUnitsPerPixel);
-  outerPath.GetRoundedBorders(UL,UR,LL,LR);
-  outerPath.CalcInsetCurves(IUL,IUR,ILL,ILR,border);
-
-  // TOP LINE -- construct and divide the curves first, then put together our top and bottom paths
-  UL.MidPointDivide(&cr1,&cr2);
-  UR.MidPointDivide(&cr3,&cr4);
-  IUL.MidPointDivide(&Icr1,&Icr2);
-  IUR.MidPointDivide(&Icr3,&Icr4);
-  if(0!=border.top){
-    np=0;
-    thePath[np++].MoveTo(cr2.mAnc1.x,cr2.mAnc1.y);
-    thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
-    thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
-    thePath[np++].MoveTo(cr3.mAnc1.x, cr3.mAnc1.y);
-    thePath[np++].MoveTo(cr3.mCon.x, cr3.mCon.y);
-    thePath[np++].MoveTo(cr3.mAnc2.x, cr3.mAnc2.y);
- 
-    thePath[np++].MoveTo(Icr3.mAnc2.x,Icr3.mAnc2.y);
-    thePath[np++].MoveTo(Icr3.mCon.x, Icr3.mCon.y);
-    thePath[np++].MoveTo(Icr3.mAnc1.x, Icr3.mAnc1.y);
-    thePath[np++].MoveTo(Icr2.mAnc2.x, Icr2.mAnc2.y);
-    thePath[np++].MoveTo(Icr2.mCon.x, Icr2.mCon.y);
-    thePath[np++].MoveTo(Icr2.mAnc1.x, Icr2.mAnc1.y);
-    RenderSide(thePath, aRenderingContext, aBorderStyle, aOutlineStyle,
-               aStyleContext, NS_SIDE_TOP, border, quarterPixel, aIsOutline);
-  }
-  // RIGHT  LINE ----------------------------------------------------------------
-  LR.MidPointDivide(&cr2,&cr3);
-  ILR.MidPointDivide(&Icr2,&Icr3);
-  if(0!=border.right){
-    np=0;
-    thePath[np++].MoveTo(cr4.mAnc1.x,cr4.mAnc1.y);
-    thePath[np++].MoveTo(cr4.mCon.x, cr4.mCon.y);
-    thePath[np++].MoveTo(cr4.mAnc2.x,cr4.mAnc2.y);
-    thePath[np++].MoveTo(cr2.mAnc1.x,cr2.mAnc1.y);
-    thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
-    thePath[np++].MoveTo(cr2.mAnc2.x,cr2.mAnc2.y);
-
-    thePath[np++].MoveTo(Icr2.mAnc2.x,Icr2.mAnc2.y);
-    thePath[np++].MoveTo(Icr2.mCon.x, Icr2.mCon.y);
-    thePath[np++].MoveTo(Icr2.mAnc1.x,Icr2.mAnc1.y);
-    thePath[np++].MoveTo(Icr4.mAnc2.x,Icr4.mAnc2.y);
-    thePath[np++].MoveTo(Icr4.mCon.x, Icr4.mCon.y);
-    thePath[np++].MoveTo(Icr4.mAnc1.x,Icr4.mAnc1.y);
-    RenderSide(thePath, aRenderingContext, aBorderStyle, aOutlineStyle,
-               aStyleContext, NS_SIDE_RIGHT, border, quarterPixel, aIsOutline);
-  }
-
-  // bottom line ----------------------------------------------------------------
-  LL.MidPointDivide(&cr2,&cr4);
-  ILL.MidPointDivide(&Icr2,&Icr4);
-  if(0!=border.bottom){
-    np=0;
-    thePath[np++].MoveTo(cr3.mAnc1.x,cr3.mAnc1.y);
-    thePath[np++].MoveTo(cr3.mCon.x, cr3.mCon.y);
-    thePath[np++].MoveTo(cr3.mAnc2.x, cr3.mAnc2.y);
-    thePath[np++].MoveTo(cr2.mAnc1.x, cr2.mAnc1.y);
-    thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
-    thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
-
-    thePath[np++].MoveTo(Icr2.mAnc2.x,Icr2.mAnc2.y);
-    thePath[np++].MoveTo(Icr2.mCon.x, Icr2.mCon.y);
-    thePath[np++].MoveTo(Icr2.mAnc1.x, Icr2.mAnc1.y);
-    thePath[np++].MoveTo(Icr3.mAnc2.x, Icr3.mAnc2.y);
-    thePath[np++].MoveTo(Icr3.mCon.x, Icr3.mCon.y);
-    thePath[np++].MoveTo(Icr3.mAnc1.x, Icr3.mAnc1.y);
-    RenderSide(thePath, aRenderingContext, aBorderStyle, aOutlineStyle,
-               aStyleContext, NS_SIDE_BOTTOM, border, quarterPixel, aIsOutline);
-  }
-  // left line ----------------------------------------------------------------
-  if(0==border.left)
-    return;
-  np=0;
-  thePath[np++].MoveTo(cr4.mAnc1.x,cr4.mAnc1.y);
-  thePath[np++].MoveTo(cr4.mCon.x, cr4.mCon.y);
-  thePath[np++].MoveTo(cr4.mAnc2.x, cr4.mAnc2.y);
-  thePath[np++].MoveTo(cr1.mAnc1.x, cr1.mAnc1.y);
-  thePath[np++].MoveTo(cr1.mCon.x, cr1.mCon.y);
-  thePath[np++].MoveTo(cr1.mAnc2.x, cr1.mAnc2.y);
-
-
-  thePath[np++].MoveTo(Icr1.mAnc2.x,Icr1.mAnc2.y);
-  thePath[np++].MoveTo(Icr1.mCon.x, Icr1.mCon.y);
-  thePath[np++].MoveTo(Icr1.mAnc1.x, Icr1.mAnc1.y);
-  thePath[np++].MoveTo(Icr4.mAnc2.x, Icr4.mAnc2.y);
-  thePath[np++].MoveTo(Icr4.mCon.x, Icr4.mCon.y);
-  thePath[np++].MoveTo(Icr4.mAnc1.x, Icr4.mAnc1.y);
-
-  RenderSide(thePath, aRenderingContext, aBorderStyle, aOutlineStyle,
-             aStyleContext, NS_SIDE_LEFT, border, quarterPixel, aIsOutline);
-}
-
-
-/** ---------------------------------------------------
- *  See documentation in nsCSSRendering.h
- *  @update 3/26/99 dwc
- */
-void 
-nsCSSRendering::RenderSide(nsFloatPoint aPoints[],nsIRenderingContext& aRenderingContext,
-                        const nsStyleBorder* aBorderStyle,const nsStyleOutline* aOutlineStyle,nsStyleContext* aStyleContext,
-                        PRUint8 aSide,nsMargin  &aBorThick,nscoord aTwipsPerPixel,
-                        PRBool aIsOutline)
-{
-  QBCurve   thecurve;
-  nscolor   sideColor = NS_RGB(0,0,0);
-  static nsPoint   polypath[MAXPOLYPATHSIZE];
-  PRInt32   curIndex,c1Index,c2Index,junk;
-  PRInt8    border_Style;
-  PRInt16   thickness;
-
-  // Get our style context's color struct.
-  const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
-
-  NS_ASSERTION((aIsOutline && aOutlineStyle) || (!aIsOutline && aBorderStyle), "null params not allowed");
-  // set the style information
-  if (!aIsOutline) {
-    if (!GetBorderColor(ourColor, *aBorderStyle, aSide, sideColor)) {
-      return;
-    }
-  } else {
-    aOutlineStyle->GetOutlineColor(sideColor);
-  }
-  aRenderingContext.SetColor ( sideColor );
-
-  thickness = 0;
-  switch(aSide){
-    case  NS_SIDE_LEFT:
-      thickness = aBorThick.left;
-      break;
-    case  NS_SIDE_TOP:
-      thickness = aBorThick.top;
-      break;
-    case  NS_SIDE_RIGHT:
-      thickness = aBorThick.right;
-      break;
-    case  NS_SIDE_BOTTOM:
-      thickness = aBorThick.bottom;
-      break;
-  }
-
-  // if the border is thin, just draw it 
-  if (thickness<=aTwipsPerPixel) {
-    // NOTHING FANCY JUST DRAW OUR OUTSIDE BORDER
-    thecurve.SetPoints(aPoints[0].x,aPoints[0].y,aPoints[1].x,aPoints[1].y,aPoints[2].x,aPoints[2].y);
-    thecurve.SubDivide((nsIRenderingContext*)&aRenderingContext,nsnull,nsnull);
-    aRenderingContext.DrawLine((nscoord)aPoints[2].x,(nscoord)aPoints[2].y,(nscoord)aPoints[3].x,(nscoord)aPoints[3].y);
-    thecurve.SetPoints(aPoints[3].x,aPoints[3].y,aPoints[4].x,aPoints[4].y,aPoints[5].x,aPoints[5].y);
-    thecurve.SubDivide((nsIRenderingContext*)&aRenderingContext,nsnull,nsnull);
-  } else {
-    
-    if (!aIsOutline) {
-      border_Style = aBorderStyle->GetBorderStyle(aSide);
-    } else {
-      border_Style = aOutlineStyle->GetOutlineStyle();
-    }
-    switch (border_Style){
-      case NS_STYLE_BORDER_STYLE_OUTSET:
-      case NS_STYLE_BORDER_STYLE_INSET:
-        {
-          const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
-          aRenderingContext.SetColor(MakeBevelColor(aSide, border_Style,
-                                       bgColor->mBackgroundColor, sideColor));
-        }
-      case NS_STYLE_BORDER_STYLE_DOTTED:
-      case NS_STYLE_BORDER_STYLE_DASHED:
-        // break; XXX This is here until dotted and dashed are supported.  It is ok to have
-        // dotted and dashed render in solid until this style is supported.  This code should
-        // be moved when it is supported so that the above outset and inset will fall into the 
-        // solid code below....
-      case NS_STYLE_BORDER_STYLE_AUTO:
-      case NS_STYLE_BORDER_STYLE_SOLID:
-        polypath[0].x = NSToCoordRound(aPoints[0].x);
-        polypath[0].y = NSToCoordRound(aPoints[0].y);
-        curIndex = 1;
-        GetPath(aPoints,polypath,&curIndex,eOutside,c1Index);
-        c2Index = curIndex;
-        if (curIndex >= MAXPOLYPATHSIZE)
-          return;
-        polypath[curIndex].x = NSToCoordRound(aPoints[6].x);
-        polypath[curIndex].y = NSToCoordRound(aPoints[6].y);
-        curIndex++;
-        GetPath(aPoints,polypath,&curIndex,eInside,junk);
-        if (curIndex >= MAXPOLYPATHSIZE)
-          return;
-        polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
-        polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
-        curIndex++;
-        aRenderingContext.FillPolygon(polypath,curIndex);
-
-       break;
-      case NS_STYLE_BORDER_STYLE_DOUBLE:
-        polypath[0].x = NSToCoordRound(aPoints[0].x);
-        polypath[0].y = NSToCoordRound(aPoints[0].y);
-        curIndex = 1;
-        GetPath(aPoints,polypath,&curIndex,eOutside,c1Index);
-        aRenderingContext.DrawPolyline(polypath,curIndex);
-        polypath[0].x = NSToCoordRound(aPoints[6].x);
-        polypath[0].y = NSToCoordRound(aPoints[6].y);
-        curIndex = 1;
-        GetPath(aPoints,polypath,&curIndex,eInside,c1Index);
-        aRenderingContext.DrawPolyline(polypath,curIndex);
-        break;
-      case NS_STYLE_BORDER_STYLE_NONE:
-      case NS_STYLE_BORDER_STYLE_HIDDEN:
-        break;
-      case NS_STYLE_BORDER_STYLE_RIDGE:
-      case NS_STYLE_BORDER_STYLE_GROOVE:
-        {
-        const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
-        aRenderingContext.SetColor(MakeBevelColor(aSide, border_Style,
-                                     bgColor->mBackgroundColor,sideColor));
-
-        polypath[0].x = NSToCoordRound(aPoints[0].x);
-        polypath[0].y = NSToCoordRound(aPoints[0].y);
-        curIndex = 1;
-        GetPath(aPoints,polypath,&curIndex,eOutside,c1Index);
-        if (curIndex >= MAXPOLYPATHSIZE)
-          return;
-        polypath[curIndex].x = NSToCoordRound((aPoints[5].x + aPoints[6].x)/2.0f);
-        polypath[curIndex].y = NSToCoordRound((aPoints[5].y + aPoints[6].y)/2.0f);
-        curIndex++;
-        GetPath(aPoints,polypath,&curIndex,eCalcRev,c1Index,.5);
-        if (curIndex >= MAXPOLYPATHSIZE)
-          return;
-        polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
-        polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
-        curIndex++;
-        aRenderingContext.FillPolygon(polypath,curIndex);
-
-        aRenderingContext.SetColor ( MakeBevelColor (aSide, 
-                                                ((border_Style == NS_STYLE_BORDER_STYLE_RIDGE) ?
-                                                NS_STYLE_BORDER_STYLE_GROOVE :
-                                                NS_STYLE_BORDER_STYLE_RIDGE), 
-                                                bgColor->mBackgroundColor,sideColor));
-       
-        polypath[0].x = NSToCoordRound((aPoints[0].x + aPoints[11].x)/2.0f);
-        polypath[0].y = NSToCoordRound((aPoints[0].y + aPoints[11].y)/2.0f);
-        curIndex = 1;
-        GetPath(aPoints,polypath,&curIndex,eCalc,c1Index,.5);
-        if (curIndex >= MAXPOLYPATHSIZE)
-          return;
-        polypath[curIndex].x = NSToCoordRound(aPoints[6].x) ;
-        polypath[curIndex].y = NSToCoordRound(aPoints[6].y);
-        curIndex++;
-        GetPath(aPoints,polypath,&curIndex,eInside,c1Index);
-        if (curIndex >= MAXPOLYPATHSIZE)
-          return;
-        polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
-        polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
-        curIndex++;
-        aRenderingContext.FillPolygon(polypath,curIndex);
-        }
-        break;
-      default:
-        break;
-    }
-  }
-}
-
 /** ---------------------------------------------------
  *  See documentation in nsCSSRendering.h
  *  @update 3/26/99 dwc
  */
 void 
 RoundedRect::CalcInsetCurves(QBCurve &aULCurve,QBCurve &aURCurve,QBCurve &aLLCurve,QBCurve &aLRCurve,nsMargin &aBorder)
 {
 PRInt32   nLeft,nTop,nRight,nBottom;
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -88,42 +88,19 @@ public:
   static void PaintOutline(nsPresContext* aPresContext,
                           nsIRenderingContext& aRenderingContext,
                           nsIFrame* aForFrame,
                           const nsRect& aDirtyRect,
                           const nsRect& aBorderArea,
                           const nsStyleBorder& aBorderStyle,
                           const nsStyleOutline& aOutlineStyle,
                           nsStyleContext* aStyleContext,
-                          PRIntn aSkipSides,
                           nsRect* aGap = 0);
 
   /**
-   * Just like PaintBorder, but takes as input a list of border segments
-   * rather than a single border style.  Useful for any object that needs to
-   * draw a border where an edge is not necessarily homogenous.
-   * Render the border for an element using css rendering rules
-   * for borders. aSkipSides is a bitmask of the sides to skip
-   * when rendering. If 0 then no sides are skipped.
-   *
-   * Both aDirtyRect and aBorderArea are in the local coordinate space
-   * of aForFrame
-   */
-  static void PaintBorderEdges(nsPresContext* aPresContext,
-                               nsIRenderingContext& aRenderingContext,
-                               nsIFrame* aForFrame,
-                               const nsRect& aDirtyRect,
-                               const nsRect& aBorderArea,
-                               nsBorderEdges * aBorderEdges,
-                               nsStyleContext* aStyleContext,
-                               PRIntn aSkipSides,
-                               nsRect* aGap = 0);
-
-
-  /**
    * Fill in an nsStyleBackground to be used to paint the background for
    * an element.  The nsStyleBackground should first be initialized
    * using the pres context.  This applies the rules for propagating
    * backgrounds between BODY, the root element, and the canvas.
    * @return PR_TRUE if there is some meaningful background.
    */
   static PRBool FindBackground(nsPresContext* aPresContext,
                                nsIFrame* aForFrame,
@@ -197,25 +174,16 @@ public:
                               const nsStyleBorder* aBorderStyle,  
                               const nsStyleOutline* aOutlineStyle,  
                               PRBool aDoOutline,
                               const nsRect& borderOutside,
                               const nsRect& borderInside,
                               PRIntn aSkipSides,
                               nsRect* aGap);
 
-  /** draw the dashed segements of a segmented border */
-  //XXX: boy is it annoying that we have 3 methods to draw dashed sides!
-  //     they clearly can be factored.
-  static void DrawDashedSegments(nsIRenderingContext& aContext,
-                                 const nsRect& aBounds,
-                                 nsBorderEdges * aBorderEdges,
-                                 PRIntn aSkipSides,
-                                 nsRect* aGap);
-
   // Draw a border segment in the table collapsing border model without beveling corners
   static void DrawTableBorderSegment(nsIRenderingContext&     aContext,
                                      PRUint8                  aBorderStyle,  
                                      nscolor                  aBorderColor,
                                      const nsStyleBackground* aBGColor,
                                      const nsRect&            aBorderRect,
                                      PRInt32                  aAppUnitsPerCSSPixel,
                                      PRUint8                  aStartBevelSide = 0,
@@ -226,39 +194,16 @@ public:
    * transform a color to a color that will show up on a printer if needed
    * aMapColor - color to evaluate
    * aIsPrinter - Is this a printing device
    * return - the transformed color
    */
   static nscolor TransformColor(nscolor  aMapColor,PRBool aNoBackGround);
 
 protected:
-  /**
-   * Render the border for an element using css rendering rules
-   * for borders. aSkipSides is a bitmask of the sides to skip
-   * when rendering. If 0 then no sides are skipped.
-   * Both aDirtyRect and aBorderArea are in the local coordinate space
-   * of aForFrame
-   */
-  static void PaintRoundedBorder(nsPresContext* aPresContext,
-                          nsIRenderingContext& aRenderingContext,
-                          nsIFrame* aForFrame,
-                          const nsRect& aDirtyRect,
-                          const nsRect& aBorderArea,
-                          const nsStyleBorder* aBorderStyle,
-                          const nsStyleOutline* aOutlineStyle,
-                          nsStyleContext* aStyleContext,
-                          PRIntn aSkipSides,
-                          PRInt16 aBorderRadius[4],nsRect* aGap = 0,
-                          PRBool aIsOutline=PR_FALSE);
-
-  static void RenderSide(nsFloatPoint aPoints[],nsIRenderingContext& aRenderingContext,
-                        const nsStyleBorder* aBorderStyle,const nsStyleOutline* aOutlineStyle,nsStyleContext* aStyleContext,
-                        PRUint8 aSide,nsMargin  &aBorThick,nscoord aTwipsPerPixel,
-                        PRBool aIsOutline=PR_FALSE);
 
   static void PaintBackgroundColor(nsPresContext* aPresContext,
                                    nsIRenderingContext& aRenderingContext,
                                    nsIFrame* aForFrame,
                                    const nsRect& aBgClipArea,
                                    const nsStyleBackground& aColor,
                                    const nsStyleBorder& aBorder,
                                    const nsStylePadding& aPadding,
@@ -272,45 +217,16 @@ protected:
                                      const nsStyleBorder& aBorder,
                                      PRInt16 aTheRadius[4],
                                      PRBool aCanPaintNonWhite);
 
   static nscolor MakeBevelColor(PRIntn whichSide, PRUint8 style,
                                 nscolor aBackgroundColor,
                                 nscolor aBorderColor);
 
-  static PRIntn MakeSide(nsPoint aPoints[],
-                         nsIRenderingContext& aContext,
-                         PRIntn whichSide,
-                         const nsRect& outside, const nsRect& inside,
-                         PRIntn aSkipSides,
-                         PRIntn borderPart, float borderFrac,
-                         nscoord twipsPerPixel);
-
-  static void DrawSide(nsIRenderingContext& aContext,
-                       PRIntn whichSide,
-                       const PRUint8 borderStyle,
-                       const nscolor borderColor,
-                       const nscolor aBackgroundColor, 
-                       const nsRect& borderOutside,
-                       const nsRect& borderInside,
-                       PRIntn aSkipSides,
-                       nscoord twipsPerPixel,
-                       nsRect* aGap = 0);
-
-
-  static void DrawCompositeSide(nsIRenderingContext& aContext,
-                                PRIntn aWhichSide,
-                                nsBorderColors* aCompositeColors,
-                                const nsRect& aOuterRect,
-                                const nsRect& aInnerRect,
-                                PRInt16* aBorderRadii,
-                                nscoord aTwipsPerPixel,
-                                nsRect* aGap);
-
   static void DrawLine (nsIRenderingContext& aContext, 
                         nscoord aX1, nscoord aY1, nscoord aX2, nscoord aY2,
                         nsRect* aGap);
 
   static void FillPolygon (nsIRenderingContext& aContext, 
                            const nsPoint aPoints[],
                            PRInt32 aNumPoints,
                            nsRect* aGap);
--- a/layout/reftests/pixel-rounding/border-left-10-ref.html
+++ b/layout/reftests/pixel-rounding/border-left-10-ref.html
@@ -28,14 +28,14 @@ div { background: green; }
 <div style="left: 251px"></div>
 <div style="left: 271px"></div>
 <div style="left: 291px"></div>
 <div style="left: 311px"></div>
 <div style="left: 331px"></div>
 <div style="left: 351px"></div>
 <div style="left: 371px"></div>
 
-<div style="top: 30px; left: 11px; width: 31px; height: 30px">
+<div style="top: 30px; left: 11px; width: 30px; height: 30px">
   <div style="background:white; top: 10px; left: 10px"></div>
 </div>
 
 </body>
 </html>
--- a/layout/reftests/pixel-rounding/reftest.list
+++ b/layout/reftests/pixel-rounding/reftest.list
@@ -27,32 +27,33 @@ random == check-image.html check-image-r
 == background-color-height-top-4.html background-color-height-4.html
 == background-color-height-top-5.html background-color-height-5.html
 == background-color-height-top-6.html background-color-height-6.html
 == background-color-width-left-4.html background-color-width-4.html
 == background-color-width-left-5.html background-color-width-5.html
 == background-color-width-left-6.html background-color-width-6.html
 
 
+# The cocoa failures are due to bug 379317
 != border-base-ref.html border-height-10-ref.html
-fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-height-4.html border-base-ref.html # bug 361523
-fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-height-5.html border-height-10-ref.html # bug 361523
-fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-height-6.html border-height-10-ref.html # bug 361523
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-height-4.html border-base-ref.html
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-height-5.html border-height-10-ref.html
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-height-6.html border-height-10-ref.html
 != border-base-ref.html border-width-10-ref.html
-fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-width-4.html border-base-ref.html # bug 361523
-fails == border-width-5.html border-width-10-ref.html # bug 363220; bug 361523 on Mac
-fails == border-width-6.html border-width-10-ref.html # bug 363220; bug 361523 on Mac
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-width-4.html border-base-ref.html
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-width-5.html border-width-10-ref.html
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-width-6.html border-width-10-ref.html
 != border-base-ref.html border-left-10-ref.html
-fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-left-4.html border-base-ref.html # bug 361523
-fails == border-left-5.html border-left-10-ref.html # bug 363220; bug 361523 on Mac
-fails == border-left-6.html border-left-10-ref.html # bug 363220; bug 361523 on Mac
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-left-4.html border-base-ref.html
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-left-5.html border-left-10-ref.html
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-left-6.html border-left-10-ref.html
 != border-base-ref.html border-top-10-ref.html
-fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-top-4.html border-base-ref.html # bug 361523
-fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-top-5.html border-top-10-ref.html # bug 361523
-fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-top-6.html border-top-10-ref.html # bug 361523
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-top-4.html border-base-ref.html
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-top-5.html border-top-10-ref.html
+fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == border-top-6.html border-top-10-ref.html
 
 
 != background-image-base.html background-image-height-10-ref.html
 == background-image-height-4.html background-image-base.html
 == background-image-height-5.html background-image-height-10-ref.html
 == background-image-height-6.html background-image-height-10-ref.html
 != background-image-base.html background-image-top-10-ref.html
 == background-image-top-4.html background-image-base.html