b=424423, border rendering is slow: Part 1; r+sr=roc
authorVladimir Vukicevic <vladimir@pobox.com>
Wed, 23 Jul 2008 10:25:23 -0700
changeset 16150 f34a9f851cd157f61e7e2c642a2b6c5610741800
parent 16149 7afdded71629633aafc53e73766a6a98c34172cd
child 16151 aeef0397faa9d4fed32905072f2b6ef716f4bc81
push id800
push uservladimir@mozilla.com
push dateWed, 23 Jul 2008 17:26:48 +0000
treeherdermozilla-central@aeef0397faa9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs424423
milestone1.9.1a2pre
b=424423, border rendering is slow: Part 1; r+sr=roc
gfx/thebes/public/gfxPoint.h
layout/base/Makefile.in
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRenderingBorders.cpp
layout/base/nsCSSRenderingBorders.h
--- a/gfx/thebes/public/gfxPoint.h
+++ b/gfx/thebes/public/gfxPoint.h
@@ -61,16 +61,19 @@ struct THEBES_API gfxIntSize {
         return ((width != s.width) || (height != s.height));
     }
     gfxIntSize operator+(const gfxIntSize& s) const {
         return gfxIntSize(width + s.width, height + s.height);
     }
     gfxIntSize operator-() const {
         return gfxIntSize(- width, - height);
     }
+    gfxIntSize operator-(const gfxIntSize& s) const {
+        return gfxIntSize(width - s.width, height - s.height);
+    }
     gfxIntSize operator*(const PRInt32 v) const {
         return gfxIntSize(width * v, height * v);
     }
     gfxIntSize operator/(const PRInt32 v) const {
         return gfxIntSize(width / v, height / v);
     }
 };
 
@@ -90,16 +93,19 @@ struct THEBES_API gfxSize {
         return ((width != s.width) || (height != s.height));
     }
     gfxSize operator+(const gfxSize& s) const {
         return gfxSize(width + s.width, height + s.height);
     }
     gfxSize operator-() const {
         return gfxSize(- width, - height);
     }
+    gfxSize operator-(const gfxSize& s) const {
+        return gfxSize(width - s.width, height - s.height);
+    }
     gfxSize operator*(const gfxFloat v) const {
         return gfxSize(width * v, height * v);
     }
     gfxSize operator/(const gfxFloat v) const {
         return gfxSize(width / v, height / v);
     }
 };
 
--- a/layout/base/Makefile.in
+++ b/layout/base/Makefile.in
@@ -115,16 +115,17 @@ EXPORTS		= \
 		nsStyleChangeList.h \
 		nsStyleConsts.h \
 		$(NULL)
 
 CPPSRCS		= \
 		nsCSSColorUtils.cpp \
 		nsCSSFrameConstructor.cpp \
 		nsCSSRendering.cpp \
+		nsCSSRenderingBorders.cpp \
 		nsCaret.cpp \
 		nsChildIterator.cpp \
 		nsCounterManager.cpp \
 		nsDisplayList.cpp \
 		nsDocumentViewer.cpp \
 		nsFrameManager.cpp \
 		nsFrameTraversal.cpp \
 		nsGenConList.cpp \
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -74,42 +74,17 @@
 #include "nsINameSpaceManager.h"
 #include "nsBlockFrame.h"
 #include "gfxContext.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "gfxPlatform.h"
 #include "gfxImageSurface.h"
 #include "nsStyleStructInlines.h"
 
-#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,
-  eCalc,
-  eCalcRev
-};
+#include "nsCSSRenderingBorders.h"
 
 // To avoid storing this data on nsInlineFrame (bloat) and to avoid
 // recalculating this for each frame in a continuation (perf), hold
 // a cache of various coordinate information that we need in order
 // to paint inline backgrounds.
 struct InlineBackgroundData
 {
   InlineBackgroundData()
@@ -926,1344 +901,41 @@ nscolor   newcolor;
     }
   }
   return newcolor;
 }
 
 //----------------------------------------------------------------------
 // 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);
-}
-
-static inline void SX(gfxContext *ctx) {
-  gfxPoint p = ctx->CurrentPoint();
-  fprintf (stderr, "p: %f %f\n", p.x, p.y);
-  return;
-  ctx->MoveTo(p + gfxPoint(-2, -2)); ctx->LineTo(p + gfxPoint(2, 2));
-  ctx->MoveTo(p + gfxPoint(-2, 2)); ctx->LineTo(p + gfxPoint(2, -2));
-  ctx->MoveTo(p);
-}
-
-
-#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, ...) {}
-static inline void SX(gfxContext *ctx) {}
-#endif
-
-// the static order in which we paint sides
-static const PRUint8 gBorderSideOrder[] = { NS_SIDE_TOP, NS_SIDE_RIGHT, NS_SIDE_BOTTOM, NS_SIDE_LEFT };
-
-// little helper function to check if the array of 4 floats given are
-// equal to the given value
-static PRBool
-CheckFourFloatsEqual(const gfxFloat *vals, gfxFloat k)
-{
-  if (vals[0] == k &&
-      vals[1] == k &&
-      vals[2] == k &&
-      vals[3] == k)
-    return PR_TRUE;
-
-  return PR_FALSE;
-}
-
-// another helper function to convert a nsRect to a gfxRect
+// helper function to convert a nsRect to a gfxRect
 static gfxRect
 RectToGfxRect(const nsRect& rect, nscoord twipsPerPixel)
 {
   return gfxRect(gfxFloat(rect.x) / twipsPerPixel,
                  gfxFloat(rect.y) / twipsPerPixel,
                  gfxFloat(rect.width) / twipsPerPixel,
                  gfxFloat(rect.height) / twipsPerPixel);
 }
 
-
-/*
- * Figure out whether we need to draw using separate side rendering or
- * not.
- *
- * The only case where we can draw the border in one pass if, for all sides:
- *  - the same style is used, and it is SOLID, DOUBLE, DASHED, or DOTTED
- *  - the same color is used
- *
- * We can draw the border in two passes if, for all sides:
- *  - the same style is used, and it is INSET, OUTSET, GROOVE, or RIDGE
- *  - the same color is used
- * 
- * Otherwise, we have do all 4 sides separately.  Generally this only
- * happens if we have different colors on the different sides.
- */
-static PRUint8
-NumBorderPasses (PRUint8 *borderStyles,
-                 nscolor *borderColors,
-                 nsBorderColors **compositeColors)
-{
-  PRUint8 numBorderPasses = 1;
-  PRUint8 firstSideStyle = borderStyles[0];
-  nscolor firstSideColor = borderColors[0];
-
-  for (int i = 0; i < 4; i++) {
-    PRUint8 borderRenderStyle = borderStyles[i];
-
-    // split into 4 if:
-    // - the styles don't match
-    // - the colors don't match
-    // - there are any compositeColors
-    if (borderRenderStyle != firstSideStyle ||
-        borderColors[i] != firstSideColor ||
-        compositeColors[i])
-      return 4;
-
-    switch (borderRenderStyle) {
-      case NS_STYLE_BORDER_STYLE_INSET:
-      case NS_STYLE_BORDER_STYLE_OUTSET:
-      case NS_STYLE_BORDER_STYLE_GROOVE:
-      case NS_STYLE_BORDER_STYLE_RIDGE:
-        numBorderPasses = 2;
-        break;
-
-      case NS_STYLE_BORDER_STYLE_SOLID:
-      case NS_STYLE_BORDER_STYLE_DOUBLE:
-      case NS_STYLE_BORDER_STYLE_DASHED:
-      case NS_STYLE_BORDER_STYLE_DOTTED:
-        // we can do this as 1, if everything else is ok
-        break;
-
-      default:
-        return 4;
-    }
-  }
-
-  // everything's transparent
-  if (firstSideColor == 0x0)
-    return 0;
-
-  return numBorderPasses;
-}
-
-#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 dimensions of the corners of the border area, taking
- * into account any border radius.  The width and height of each
- * corner (in order of TL, TR, BR, BL) is returned in oDims, which
- * should be a 4-element array of gfxSize.
- */
-
-// How much of the actual corner size to call the "corner" for the
-// dimensions.  Must be >= 1.0; anything over 1.0 will give more of a
-// corner in dotted/dashed rendering cases.  It's not clear whether >=
-// 1.0 looks better.
-#define CORNER_FACTOR 1.0
-
-static void
-GetBorderCornerDimensions(const gfxRect& oRect,
-                          const gfxRect& iRect,
-                          const gfxFloat *radii,
-                          gfxSize *oDims)
-{
-  gfxFloat topWidth = iRect.pos.y - oRect.pos.y;
-  gfxFloat leftWidth = iRect.pos.x - oRect.pos.x;
-  gfxFloat rightWidth = oRect.size.width - iRect.size.width - leftWidth;
-  gfxFloat bottomWidth = oRect.size.height - iRect.size.height - topWidth;
-
-  if (radii) {
-    leftWidth = PR_MAX(leftWidth, PR_MAX(radii[C_TL], radii[C_BL]));
-    topWidth = PR_MAX(topWidth, PR_MAX(radii[C_TL], radii[C_TR]));
-    rightWidth = PR_MAX(rightWidth, PR_MAX(radii[C_TR], radii[C_BR]));
-    bottomWidth = PR_MAX(bottomWidth, PR_MAX(radii[C_BR], radii[C_BL]));
-  }
-
-  oDims[C_TL] = gfxSize(leftWidth, topWidth);
-  oDims[C_TR] = gfxSize(rightWidth, topWidth);
-  oDims[C_BL] = gfxSize(leftWidth, bottomWidth);
-  oDims[C_BR] = gfxSize(rightWidth, bottomWidth);
-}
-
-/* Set up a path for rendering just the corners of the path.  Executed
- * by computing the corner dimensions, and then drawing rectangles for
- * each corner.
- * 
- * Because this function is used mainly for dashed rendering, the
- * sides that don't have a dotted/dashed styles are also included.
- */
-
-static void
-DoCornerClipSubPath(gfxContext *ctx,
-                    const gfxRect& oRect,
-                    const gfxRect& iRect,
-                    const gfxFloat *radii,
-                    PRIntn dashedSides = 0xff)
-{
-  gfxSize dims[4];
-
-  GetBorderCornerDimensions(oRect, iRect, radii, dims);
-
-  gfxRect tl(oRect.pos.x,
-             oRect.pos.y,
-             dims[C_TL].width,
-             dims[C_TL].height);
-
-  gfxRect tr(oRect.pos.x + oRect.size.width - dims[C_TR].width,
-             oRect.pos.y,
-             dims[C_TR].width,
-             dims[C_TR].height);
-
-  gfxRect br(oRect.pos.x + oRect.size.width - dims[C_BR].width,
-             oRect.pos.y + oRect.size.height - dims[C_BR].height,
-             dims[C_BR].width,
-             dims[C_BR].height);
-
-  gfxRect bl(oRect.pos.x,
-             oRect.pos.y + oRect.size.height - dims[C_BL].height,
-             dims[C_BL].width,
-             dims[C_BL].height);
-
-  ctx->Rectangle(tl);
-  ctx->Rectangle(tr);
-  ctx->Rectangle(br);
-  ctx->Rectangle(bl);
-
-  // Now if any of the sides are not dashed, include that full side.
-  if (!(dashedSides & SIDE_BIT_TOP)) {
-    ctx->Rectangle(gfxRect(tl.pos.x,
-                           tl.pos.y,
-                           oRect.size.width,
-                           dims[C_TL].height));
-  }
-
-  if (!(dashedSides & SIDE_BIT_RIGHT)) {
-    ctx->Rectangle(gfxRect(tr.pos.x,
-                           tr.pos.y,
-                           dims[C_TR].width,
-                           oRect.size.height));
-  }
-
-  if (!(dashedSides & SIDE_BIT_BOTTOM)) {
-    ctx->Rectangle(gfxRect(oRect.pos.x,
-                           br.pos.y,
-                           oRect.size.width,
-                           dims[C_BR].height));
-  }
-
-  if (!(dashedSides & SIDE_BIT_LEFT)) {
-    ctx->Rectangle(gfxRect(oRect.pos.x,
-                           oRect.pos.y,
-                           dims[C_BL].width,
-                           oRect.size.height));
-  }
-}
-
-// Draw a path for a rounded rectangle with the corners rounded by the
-// given radii, with the path going clockwise.
-static void
-DoRoundedRectCWSubPath(gfxContext *ctx,
-                       const gfxRect& sRect,
-                       const gfxFloat *radii)
-{
-  ctx->Translate(sRect.pos);
-
-  ctx->MoveTo(gfxPoint(sRect.size.width - radii[C_TR], 0.0));
-  SX(ctx);
-            
-  if (radii[C_TR]) {
-    ctx->Arc(gfxPoint(sRect.size.width - radii[C_TR], radii[C_TR]),
-             radii[C_TR],
-             3.0 * NS_PI / 2.0,
-             0.0);
-    SX(ctx);
-  }
-
-  ctx->LineTo(gfxPoint(sRect.size.width, sRect.size.height - radii[C_BR]));
-  SX(ctx);
-
-  if (radii[C_BR]) {
-    ctx->Arc(gfxPoint(sRect.size.width - radii[C_BR], sRect.size.height - radii[C_BR]),
-             radii[C_BR],
-             0.0,
-             NS_PI / 2.0);
-    SX(ctx);
-  }
-
-  ctx->LineTo(gfxPoint(radii[C_BL], sRect.size.height));
-  SX(ctx);
-      
-  if (radii[C_BL]) {
-    ctx->Arc(gfxPoint(radii[C_BL], sRect.size.height - radii[C_BL]),
-             radii[C_BL],
-             NS_PI / 2.0,
-             NS_PI);
-    SX(ctx);
-  }
-
-  ctx->LineTo(gfxPoint(0.0, radii[C_TL]));
-  SX(ctx);
-
-  if (radii[C_TL]) {
-    ctx->Arc(gfxPoint(radii[C_TL], radii[C_TL]),
-             radii[C_TL],
-             NS_PI,
-             3.0 * NS_PI / 2.0);
-    SX(ctx);
-  }
-
-  ctx->ClosePath();
-
-  ctx->Translate(-sRect.pos);
-}
-
-// Draw a path for a rounded rectangle with the corners rounded by the
-// given radii, with the path going counterclockwise.
-static void
-DoRoundedRectCCWSubPath(gfxContext *ctx,
-                        const gfxRect& sRect,
-                        const gfxFloat *radii)
-{
-  ctx->Translate(sRect.pos);
-
-  ctx->MoveTo(gfxPoint(radii[C_TL], 0.0));
-
-  if (radii[C_TL]) {
-    ctx->NegativeArc(gfxPoint(radii[C_TL], radii[C_TL]),
-                     radii[C_TL],
-                     3.0 * NS_PI / 2.0,
-                     NS_PI);
-    SX(ctx);
-  }
-
-  ctx->LineTo(gfxPoint(0.0, sRect.size.height - radii[C_BL]));
-
-  if (radii[C_BL]) {
-    ctx->NegativeArc(gfxPoint(radii[C_BL], sRect.size.height - radii[C_BL]),
-                     radii[C_BL],
-                     NS_PI,
-                     NS_PI / 2.0);
-    SX(ctx);
-  }
-
-  ctx->LineTo(gfxPoint(sRect.size.width - radii[C_BR], sRect.size.height));
-
-  if (radii[C_BR]) {
-    ctx->NegativeArc(gfxPoint(sRect.size.width - radii[C_BR], sRect.size.height - radii[C_BR]),
-                     radii[C_BR],
-                     NS_PI / 2.0,
-                     0.0);
-    SX(ctx);
-  }
-
-  ctx->LineTo(gfxPoint(sRect.size.width, radii[C_TR]));
-
-  if (radii[C_TR]) {
-    ctx->NegativeArc(gfxPoint(sRect.size.width - radii[C_TR], radii[C_TR]),
-                     radii[C_TR],
-                     0.0,
-                     3.0 * NS_PI / 2.0);
-    SX(ctx);
-  }
-
-  ctx->ClosePath();
-
-  ctx->Translate(-sRect.pos);
-}
-
-// Calculate the inner radii from the outer and the border sizes.
-static void
-CalculateInnerRadii(const gfxFloat *radii,
-                    const gfxFloat *borderSizes,
-                    gfxFloat *innerRadii)
-{
-  innerRadii[C_TL] = PR_MAX(0.0, radii[C_TL] - PR_MAX(borderSizes[NS_SIDE_TOP], borderSizes[NS_SIDE_LEFT]));
-  innerRadii[C_TR] = PR_MAX(0.0, radii[C_TR] - PR_MAX(borderSizes[NS_SIDE_TOP], borderSizes[NS_SIDE_RIGHT]));
-  innerRadii[C_BR] = PR_MAX(0.0, radii[C_BR] - PR_MAX(borderSizes[NS_SIDE_BOTTOM], borderSizes[NS_SIDE_RIGHT]));
-  innerRadii[C_BL] = PR_MAX(0.0, radii[C_BL] - PR_MAX(borderSizes[NS_SIDE_BOTTOM], borderSizes[NS_SIDE_LEFT]));
-}
-
-// Draw the entire border path.  Intended to be filled with the
-// (default) WINDING rule.
-static void
-DoAllSidesBorderPath(gfxContext *ctx,
-                     const gfxRect &oRect,
-                     const gfxRect &iRect,
-                     const gfxFloat *radii,
-                     const gfxFloat *borderSizes)
-{
-  gfxFloat innerRadii[4];
-  CalculateInnerRadii(radii, borderSizes, innerRadii);
-
-  ctx->NewPath();
-
-  // do the outer border
-  DoRoundedRectCWSubPath(ctx, oRect, radii);
-
-  // then do the inner border
-  DoRoundedRectCCWSubPath(ctx, iRect, innerRadii);
-}
-
-// Draw the top left piece of the border path.  Intended to be filled
-// with the (default) WINDING rule.
-static void
-DoTopLeftSidesBorderPath(gfxContext *ctx,
-                         const gfxRect &oRect,
-                         const gfxRect &iRect,
-                         const gfxFloat *radii,
-                         const gfxFloat *borderSizes)
-{
-  gfxFloat innerRadii[4];
-  CalculateInnerRadii(radii, borderSizes, innerRadii);
-
-  ctx->NewPath();
-
-  // start drawing counterclockwise on the outside,
-  // in the first left-side straightway
-  ctx->MoveTo(oRect.BottomLeft() + gfxPoint(0.0, - radii[C_BL]));
-
-  if (radii[C_BL]) {
-    ctx->NegativeArc(oRect.BottomLeft() + gfxPoint(radii[C_BL], - radii[C_BL]),
-                     radii[C_BL],
-                     NS_PI,
-                     NS_PI * 3.0 / 4.0);
-  }
-
-  // flip here; start drawing clockwise; line between arc endpoints will
-  // be filled in by cairo
-
-  if (innerRadii[C_BL]) {
-    ctx->Arc(iRect.BottomLeft() + gfxPoint(innerRadii[C_BL], - innerRadii[C_BL]),
-             innerRadii[C_BL],
-             NS_PI * 3.0 / 4.0,
-             NS_PI);
-  } else {
-    ctx->LineTo(iRect.BottomLeft());
-  }
-
-  ctx->LineTo(iRect.TopLeft() + gfxPoint(0.0, innerRadii[C_TL]));
-
-  if (innerRadii[C_TL]) {
-    ctx->Arc(iRect.TopLeft() + gfxPoint(innerRadii[C_TL], innerRadii[C_TL]),
-             innerRadii[C_TL],
-             NS_PI,
-             NS_PI * 3.0 / 2.0);
-  }
-
-  ctx->LineTo(iRect.TopRight() + gfxPoint(- innerRadii[C_TR], 0.0));
-
-  if (innerRadii[C_TR]) {
-    ctx->Arc(iRect.TopRight() + gfxPoint( - innerRadii[C_TR], innerRadii[C_TR]),
-             innerRadii[C_TR],
-             NS_PI * 6.0 / 4.0,
-             NS_PI * 7.0 / 4.0);
-  }
-
-  // now go back
-
-  if (radii[C_TR]) {
-    ctx->NegativeArc(oRect.TopRight() + gfxPoint(- radii[C_TR], radii[C_TR]),
-                     radii[C_TR],
-                     NS_PI * 7.0 / 4.0,
-                     NS_PI * 6.0 / 4.0);
-
-  } else {
-    ctx->LineTo(oRect.TopRight());
-  }
-
-  ctx->LineTo(oRect.TopLeft() + gfxPoint(radii[C_TL], 0.0));
-
-  if (radii[C_TL]) {
-    ctx->NegativeArc(oRect.TopLeft() + gfxPoint(radii[C_TL], radii[C_TL]),
-                     radii[C_TL],
-                     NS_PI * 3.0 / 2.0,
-                     NS_PI);
-  }
-
-  ctx->ClosePath();
-}
-
-// Draw the bottom right piece of the border path.  Intended to be
-// filled with the (default) WINDING rule.
-static void
-DoBottomRightSidesBorderPath(gfxContext *ctx,
-                             const gfxRect &oRect,
-                             const gfxRect &iRect,
-                             const gfxFloat *radii,
-                             const gfxFloat *borderSizes)
-{
-  gfxFloat innerRadii[4];
-  CalculateInnerRadii(radii, borderSizes, innerRadii);
-
-  ctx->NewPath();
-
-  // start drawing counterclockwise on the outside,
-  // in the first right-side straightway
-  ctx->MoveTo(oRect.TopRight() + gfxPoint(0.0, radii[C_TR]));
-
-  if (radii[C_TR]) {
-    ctx->NegativeArc(oRect.TopRight() + gfxPoint(- radii[C_TR], radii[C_TR]),
-                     radii[C_TR],
-                     0.0,
-                     NS_PI * 7.0 / 4.0);
-  }
-
-  // flip
-
-  if (innerRadii[C_TR]) {
-    ctx->Arc(iRect.TopRight() + gfxPoint(- innerRadii[C_TR], innerRadii[C_TR]),
-             innerRadii[C_TR],
-             NS_PI * 7.0 / 4.0,
-             0.0);
-  } else {
-    ctx->LineTo(iRect.TopRight());
-  }
-
-  ctx->LineTo(iRect.BottomRight() + gfxPoint(0.0, - innerRadii[C_BR]));
-
-  if (innerRadii[C_BR]) {
-    ctx->Arc(iRect.BottomRight() + gfxPoint(- innerRadii[C_BR], - innerRadii[C_BR]),
-             innerRadii[C_BR],
-             0.0,
-             NS_PI / 2.0);
-  }
-
-  ctx->LineTo(iRect.BottomLeft() + gfxPoint(innerRadii[C_BL], 0.0));
-
-  if (innerRadii[C_BL]) {
-    ctx->Arc(iRect.BottomLeft() + gfxPoint(innerRadii[C_BL], - innerRadii[C_BL]),
-             innerRadii[C_BL],
-             NS_PI / 2.0,
-             NS_PI * 3.0 / 4.0);
-  }
-
-  // and flip
-
-  if (radii[C_BL]) {
-    ctx->NegativeArc(oRect.BottomLeft() + gfxPoint(radii[C_BL], - radii[C_BL]),
-                     radii[C_BL],
-                     NS_PI * 3.0 / 4.0,
-                     NS_PI / 2.0);
-  } else {
-    ctx->LineTo(oRect.BottomLeft());
-  }
-
-  ctx->LineTo(oRect.BottomRight() + gfxPoint(- radii[C_BR], 0.0));
-
-  if (radii[C_BR]) {
-    ctx->NegativeArc(oRect.BottomRight() + gfxPoint(- radii[C_BR], - radii[C_BR]),
-                     radii[C_BR],
-                     NS_PI / 2.0,
-                     0.0);
-  }
-
-  ctx->ClosePath();
-}
-
-// Given a set of sides to fill and a color, do so in the fastest way.
-//
-// Stroke tends to be faster for smaller borders because it doesn't go
-// through the tessellator, which has initialization overhead.  If
-// we're rendering all sides, we can use stroke at any thickness; we
-// also do TL/BR pairs at 1px thickness using stroke.
-//
-// If we can't stroke, then if it's a TL/BR pair, we use the specific
-// TL/BR paths.  Otherwise, we do the full path and fill.
-//
-// Calling code is expected to only set up a clip as necessary; no
-// clip is needed if we can render the entire border in 1 or 2 passes.
-static void
-FillFastBorderPath(gfxContext *ctx,
-                   const gfxRect &oRect,
-                   const gfxRect &iRect,
-                   const gfxFloat *radii,
-                   const gfxFloat *borderSizes,
-                   PRIntn sides,
-                   const gfxRGBA& color)
-{
-  ctx->SetColor(color);
-
-  if (CheckFourFloatsEqual(radii, 0.0) &&
-      CheckFourFloatsEqual(borderSizes, borderSizes[0]))
-  {
-    if (sides == SIDE_BITS_ALL) {
-      ctx->NewPath();
-
-      gfxRect r(oRect);
-      r.Inset(borderSizes[0] / 2.0);
-      ctx->Rectangle(r);
-      ctx->SetLineWidth(borderSizes[0]);
-      ctx->Stroke();
-
-      return;
-    }
-
-    if (sides == (SIDE_BIT_TOP | SIDE_BIT_LEFT) &&
-               borderSizes[0] == 1.0 &&
-               color.a == 1.0)
-    {
-      ctx->SetLineWidth(1.0);
-
-      ctx->NewPath();
-      ctx->MoveTo(oRect.BottomLeft() + gfxSize(0.5, 0.0));
-      ctx->LineTo(oRect.TopLeft() + gfxSize(0.5, 0.5));
-      ctx->LineTo(oRect.TopRight() + gfxSize(0.0, 0.5));
-      ctx->Stroke();
-      return;
-    }
-
-    if (sides == (SIDE_BIT_BOTTOM | SIDE_BIT_RIGHT) &&
-               borderSizes[0] == 1.0 &&
-               color.a == 1.0)
-    {
-      ctx->SetLineWidth(1.0);
-
-      ctx->NewPath();
-      ctx->MoveTo(oRect.BottomLeft() + gfxSize(0.0, -0.5));
-      ctx->LineTo(oRect.BottomRight() + gfxSize(-0.5, -0.5));
-      ctx->LineTo(oRect.TopRight() + gfxSize(-0.5, 0.0));
-      ctx->Stroke();
-      return;
-    }
-  }
-
-  // we weren't able to render using stroke; do paths and fill.
-  if (sides == (SIDE_BIT_TOP | SIDE_BIT_LEFT)) {
-    DoTopLeftSidesBorderPath(ctx, oRect, iRect, radii, borderSizes);
-  } else if (sides == (SIDE_BIT_BOTTOM | SIDE_BIT_RIGHT)) {
-    DoBottomRightSidesBorderPath(ctx, oRect, iRect, radii, borderSizes);
-  } else {
-    DoAllSidesBorderPath(ctx, oRect, iRect, radii, borderSizes);
-  }
-
-  ctx->Fill();
-}
-
-// 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
-DoSideClipSubPath(gfxContext *ctx,
-                  const gfxRect& iRect,
-                  const gfxRect& oRect,
-                  PRUint8 whichSide,
-                  const PRUint8 *borderStyles,
-                  const gfxFloat *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 = borderStyles[whichSide];
-  PRUint8 startAdjacentStyle = borderStyles[((whichSide - 1) + 4) % 4];
-  PRUint8 endAdjacentStyle = borderStyles[(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.0;
-    endHasRadius = borderRadii[(whichSide+1) % 4] != 0.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 (endType == 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->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)
-{
-  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;
-  }
-}
-
-// Given a line index (an index starting from the outside of the
-// border going inwards) and an array of line styles, calculate the
-// color that that stripe of the border should be rendered in.
-static void
-ComputeColorForLine(PRUint32 lineIndex,
-                    const BorderColorStyle* borderColorStyle,
-                    PRUint32 borderColorStyleCount,
-                    const 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.
- **/
-
-static void
-DrawBorderSides(gfxContext *ctx,           // The content to render to
-                const gfxFloat *borderWidths,    // The widths of the border sides; top-right-bottom-left
-                PRIntn sides,              // The specific sides we're actually rendering (bits)
-                PRUint8 borderRenderStyle, // The style the border is to be rendered in
-                const gfxRect& oRect,            // The outside rectangle that encompasses the entire border
-                const gfxRect& iRect,            // The inner rectangle of the border
-                nscolor borderRenderColor, // The base color the border is to be rendered in
-                const nsBorderColors *compositeColors, // Composite colors, nsnull if none
-                nscolor bgColor,           // The background color; used for computing the actual color for some styles
-                nscoord twipsPerPixel,     // The current twips-per-pixel ratio
-                const gfxFloat *borderRadii)     // The border radii; TL, TR, BR, BL -- nsnull if none
-{
-  gfxFloat radii[4];
-  gfxFloat *radiiPtr = nsnull;
-
-  PRUint32 borderColorStyleCount = 0;
-  BorderColorStyle borderColorStyleTopLeft[3], borderColorStyleBottomRight[3];
-  BorderColorStyle *borderColorStyle = nsnull;
-  PRUint32 compositeColorCount = 0;
-
-  if (borderRadii) {
-    // make a copy, because we munge this during this function
-    for (int i = 0; i < 4; i++)
-      radii[i] = borderRadii[i];
-
-    radiiPtr = &radii[0];
-  }
-
-  // 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 (CheckFourFloatsEqual(borderWidths, 1.0)) {
-      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;
-        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:
-        NS_NOTREACHED("Unhandled border style!!");
-        break;
-    }
-
-    // The caller should never give us anything with a mix
-    // of TL/BR if the border style would require a
-    // TL/BR split.
-    if (sides & (SIDE_BIT_BOTTOM | SIDE_BIT_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.
-    PRUint32 maxBorderWidth = 0;
-    for (int i = 0; i < 4; i++)
-      maxBorderWidth = PR_MAX(maxBorderWidth, PRUint32(borderWidths[i]));
-    
-    borderColorStyle = new BorderColorStyle[maxBorderWidth];
-    borderColorStyleCount = maxBorderWidth;
-
-    const nsBorderColors *tmp = compositeColors;
-    do {
-      compositeColorCount++;
-      tmp = tmp->mNext;
-    } while (tmp);
-
-    for (unsigned int i = 0; i < borderColorStyleCount; i++) {
-      borderColorStyle[i] = BorderColorStyleSolid;
-    }
-  }
-
-  SF("borderWidths: %f %f %f %f ", borderWidths[0], borderWidths[1], borderWidths[2], borderWidths[3]), SN(), SF(" borderColorStyleCount: %d\n", borderColorStyleCount);
-  if (radiiPtr) {
-    SF(" radii: %f %f %f %f\n", radiiPtr[0], radiiPtr[1], radiiPtr[2], radiiPtr[3]);
-  }
-
-  // -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,
-                          borderColorStyle, borderColorStyleCount,
-                          nsnull, 0,
-                          borderRenderColor, bgColor, color);
-
-
-      SF("borderColorStyle: %d color: %f %f %f %f\n", borderColorStyle[0], color.r, color.g, color.b, color.a);
-
-      FillFastBorderPath(ctx, oRect, iRect, radiiPtr, borderWidths, sides, color);
-    } else if (borderColorStyleCount == 2) {
-      // with 2 color styles, any extra pixel goes to the outside
-
-      gfxFloat outerBorderWidths[4], innerBorderWidths[4];
-      for (int i = 0; i < 4; i++) {
-        outerBorderWidths[i] = PRInt32(borderWidths[i]) / 2 + PRInt32(borderWidths[i]) % 2;
-        innerBorderWidths[i] = PRInt32(borderWidths[i]) / 2;
-      }
-
-      gfxRGBA color;
-      gfxRect soRect, siRect;
-
-      // draw outer rect
-      if (borderColorStyle[1] != BorderColorStyleNone) {
-        ComputeColorForLine(0,
-                            borderColorStyle, borderColorStyleCount,
-                            nsnull, 0,
-                            borderRenderColor, bgColor, color);
-
-        soRect = oRect;
-        siRect = iRect;
-
-        siRect.Outset(innerBorderWidths);
-
-        FillFastBorderPath(ctx, soRect, siRect, radiiPtr, outerBorderWidths, sides, color);
-      }
-
-      if (radiiPtr)
-        CalculateInnerRadii(radiiPtr, outerBorderWidths, radiiPtr);
-
-      // draw inner rect
-      if (borderColorStyle[0] != BorderColorStyleNone) {
-        ComputeColorForLine(1,
-                            borderColorStyle, borderColorStyleCount,
-                            nsnull, 0,
-                            borderRenderColor, bgColor, color);
-
-        soRect = oRect;
-        siRect = iRect;
-
-        soRect.Inset(outerBorderWidths);
-
-        FillFastBorderPath(ctx, soRect, siRect, radiiPtr, innerBorderWidths, sides, color);
-      }
-
-    } else if (borderColorStyleCount == 3) {
-      // with 3 color styles, any extra pixel (or lack of extra pixel)
-      // goes to the middle
-
-      gfxFloat outerBorderWidths[4], middleBorderWidths[4], innerBorderWidths[4];
-
-      for (int i = 0; i < 4; i++) {
-        if (borderWidths[i] == 1.0) {
-          outerBorderWidths[i] = 1.0;
-          middleBorderWidths[i] = innerBorderWidths[i] = 0.0;
-        } else {
-          PRInt32 rest = PRInt32(borderWidths[i]) % 3;
-          outerBorderWidths[i] = innerBorderWidths[i] = middleBorderWidths[i] = (PRInt32(borderWidths[i]) - rest) / 3;
-
-          if (rest == 1) {
-            middleBorderWidths[i] += 1.0;
-          } else if (rest == 2) {
-            outerBorderWidths[i] += 1.0;
-            innerBorderWidths[i] += 1.0;
-          }
-        }
-      }
-
-      gfxRGBA color;
-      gfxRect soRect, siRect;
-
-      // draw outer rect
-      if (borderColorStyle[2] != BorderColorStyleNone) {
-        ComputeColorForLine(0,
-                            borderColorStyle, borderColorStyleCount,
-                            nsnull, 0,
-                            borderRenderColor, bgColor, color);
-
-        soRect = oRect;
-        siRect = iRect;
-
-        siRect.Outset(innerBorderWidths);
-        siRect.Outset(middleBorderWidths);
-
-        FillFastBorderPath(ctx, soRect, siRect, radiiPtr, outerBorderWidths, sides, color);
-      }
-
-      if (radiiPtr)
-        CalculateInnerRadii(radiiPtr, outerBorderWidths, radiiPtr);
-
-      // draw middle rect
-      if (borderColorStyle[1] != BorderColorStyleNone) {
-        ComputeColorForLine(1,
-                            borderColorStyle, borderColorStyleCount,
-                            nsnull, 0,
-                            borderRenderColor, bgColor, color);
-
-        soRect = oRect;
-        siRect = iRect;
-
-        soRect.Inset(outerBorderWidths);
-        siRect.Outset(innerBorderWidths);
-
-        FillFastBorderPath(ctx, soRect, siRect, radiiPtr, middleBorderWidths, sides, color);
-      }
-
-      if (radiiPtr)
-        CalculateInnerRadii(radiiPtr, middleBorderWidths, radiiPtr);
-
-      // draw inner rect
-      if (borderColorStyle[0] != BorderColorStyleNone) {
-        ComputeColorForLine(2,
-                            borderColorStyle, borderColorStyleCount,
-                            nsnull, 0,
-                            borderRenderColor, bgColor, color);
-
-        soRect = oRect;
-        siRect = iRect;
-
-        soRect.Inset(outerBorderWidths);
-        soRect.Inset(middleBorderWidths);
-
-        FillFastBorderPath(ctx, soRect, siRect, radiiPtr, innerBorderWidths, sides, color);
-      }
-    } 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
-    gfxRect soRect = oRect;
-    gfxRect siRect;
-    gfxFloat maxBorderWidth = 0;
-    for (int i = 0; i < 4; i++)
-      maxBorderWidth = PR_MAX(maxBorderWidth, borderWidths[i]);
-
-    // distribute the border sizes evenly as we draw lines; we end up
-    // drawing borders that are potentially less than 1px in width
-    // if some of the sides are bigger than the others, but we have
-    // consistent colors all the way around.
-    gfxFloat fakeBorderSizes[4];
-    for (int i = 0; i < 4; i++)
-      fakeBorderSizes[i] = borderWidths[i] / maxBorderWidth;
-
-    for (PRUint32 i = 0; i < PRUint32(maxBorderWidth); i++) {
-      gfxRGBA lineColor;
-      siRect = soRect;
-      siRect.Inset(fakeBorderSizes);
-
-      ComputeColorForLine(i,
-                          borderColorStyle, borderColorStyleCount,
-                          compositeColors, compositeColorCount,
-                          borderRenderColor, bgColor, lineColor);
-
-      FillFastBorderPath(ctx, soRect, siRect, radiiPtr, fakeBorderSizes, sides, lineColor);
-
-      soRect.Inset(fakeBorderSizes);
-
-      if (radiiPtr)
-        CalculateInnerRadii(radiiPtr, fakeBorderSizes, radiiPtr);
-    }
-  }
-
-  if (compositeColors) {
-    delete [] borderColorStyle;
-  }
-
-  ctx->SetFillRule(gfxContext::FILL_RULE_WINDING);
-
-#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
-}
-
 /*
  * Compute the float-pixel radii that should be used for drawing
  * this border/outline, given the various input bits.
  *
  * If a side is skipped via skipSides, its corners are forced to 0,
  * otherwise the resulting radius is the smaller of the specified
  * radius and half of each adjacent side's length.
  */
 static void
 ComputePixelRadii(const nscoord *aTwipsRadii,
                   const nsRect& outerRect,
                   const nsMargin& borderMargin,
                   PRIntn skipSides,
                   nscoord twipsPerPixel,
-                  gfxFloat *oBorderRadii)
+                  gfxCornerSizes *oBorderRadii)
 {
   nscoord twipsRadii[4] = { aTwipsRadii[0], aTwipsRadii[1], aTwipsRadii[2], aTwipsRadii[3] };
   nsMargin border(borderMargin);
 
   if (skipSides & SIDE_BIT_TOP) {
     border.top = 0;
     twipsRadii[C_TL] = 0;
     twipsRadii[C_TR] = 0;
@@ -2291,387 +963,26 @@ ComputePixelRadii(const nscoord *aTwipsR
   innerRect.Deflate(border);
 
   // make sure the corner radii don't get too big
   nsMargin maxRadiusSize(innerRect.width/2 + border.left,
                          innerRect.height/2 + border.top,
                          innerRect.width/2 + border.right,
                          innerRect.height/2 + border.bottom);
 
-  oBorderRadii[C_TL] = gfxFloat(PR_MIN(twipsRadii[C_TL], PR_MIN(maxRadiusSize.top, maxRadiusSize.left))) / twipsPerPixel;
-  oBorderRadii[C_TR] = gfxFloat(PR_MIN(twipsRadii[C_TR], PR_MIN(maxRadiusSize.top, maxRadiusSize.right))) / twipsPerPixel;
-  oBorderRadii[C_BL] = gfxFloat(PR_MIN(twipsRadii[C_BL], PR_MIN(maxRadiusSize.bottom, maxRadiusSize.left))) / twipsPerPixel;
-  oBorderRadii[C_BR] = gfxFloat(PR_MIN(twipsRadii[C_BR], PR_MIN(maxRadiusSize.bottom, maxRadiusSize.right))) / twipsPerPixel;
-}
-
-static void
-DrawDashedSide(gfxContext *ctx,
-               PRUint8 side,
-               const gfxRect& iRect,
-               const gfxRect& oRect,
-               PRUint8 style,
-               gfxFloat borderWidth,
-               nscolor borderColor,
-               gfxSize *cornerDimensions)
-{
-  gfxFloat dashWidth;
-  gfxFloat dash[2];
-
-  if (borderWidth == 0.0)
-    return;
-
-  if (style == NS_STYLE_BORDER_STYLE_DASHED) {
-    dashWidth = gfxFloat(borderWidth * DOT_LENGTH * DASH_LENGTH);
-
-    dash[0] = dashWidth;
-    dash[1] = dashWidth;
-
-    ctx->SetLineCap(gfxContext::LINE_CAP_BUTT);
-  } else if (style == NS_STYLE_BORDER_STYLE_DOTTED) {
-    dashWidth = gfxFloat(borderWidth * DOT_LENGTH);
-
-    if (borderWidth > 2.0) {
-      dash[0] = 0.0;
-      dash[1] = dashWidth * 2.0;
-
-      ctx->SetLineCap(gfxContext::LINE_CAP_ROUND);
-    } else {
-      dash[0] = dashWidth;
-      dash[1] = dashWidth;
-    }
-  } else {
-    SF("DrawDashedSide: style: %d!!\n", style);
-    NS_ERROR("DrawDashedSide called with style other than DASHED or DOTTED; someone's not playing nice");
-    return;
-  }
-
-  SF("dash: %f %f\n", dash[0], dash[1]);
-
-  ctx->SetDash(dash, 2, 0.0);
-
-  // Get the line drawn
-  gfxPoint start, end;
-  gfxFloat length;
-  if (side == NS_SIDE_TOP) {
-    start = gfxPoint(oRect.pos.x + cornerDimensions[C_TL].width,
-                     (oRect.pos.y + iRect.pos.y) / 2.0);
-    end = gfxPoint(oRect.pos.x + oRect.size.width - cornerDimensions[C_TR].width,
-                   (oRect.pos.y + iRect.pos.y) / 2.0);
-    length = end.x - start.x;
-  } else if (side == NS_SIDE_RIGHT) {
-    start = gfxPoint(oRect.pos.x + oRect.size.width - borderWidth / 2.0,
-                     oRect.pos.y + cornerDimensions[C_TR].height);
-    end = gfxPoint(oRect.pos.x + oRect.size.width - borderWidth / 2.0,
-                   oRect.pos.y + oRect.size.height - cornerDimensions[C_BR].height);
-    length = end.y - start.y;
-  } else if (side == NS_SIDE_BOTTOM) {
-    start = gfxPoint(oRect.pos.x + oRect.size.width - cornerDimensions[C_BR].width,
-                     oRect.pos.y + oRect.size.height - borderWidth / 2.0);
-    end = gfxPoint(oRect.pos.x + cornerDimensions[C_BL].width,
-                   oRect.pos.y + oRect.size.height - borderWidth / 2.0);
-    length = start.x - end.x;
-  } else if (side == NS_SIDE_LEFT) {
-    start = gfxPoint(oRect.pos.x + borderWidth / 2.0,
-                     oRect.pos.y + oRect.size.height - cornerDimensions[C_BL].height);
-    end = gfxPoint(oRect.pos.x + borderWidth / 2.0,
-                   oRect.pos.y + cornerDimensions[C_TR].height);
-    length = start.y - end.y;
-  }
-
-  ctx->NewPath();
-  ctx->MoveTo(start);
-  ctx->LineTo(end);
-  ctx->SetLineWidth(borderWidth);
-  ctx->SetColor(gfxRGBA(borderColor));
-  //ctx->SetColor(gfxRGBA(1.0, 0.0, 0.0, 1.0));
-  ctx->Stroke();
-}
-
-static void
-DrawBorders(gfxContext *ctx,
-            gfxRect& oRect,
-            gfxRect& iRect,
-            PRUint8 *borderStyles,
-            gfxFloat *borderWidths,
-            gfxFloat *borderRadii,
-            nscolor *borderColors,
-            nsBorderColors **compositeColors,
-            PRIntn skipSides,
-            nscolor backgroundColor,
-            nscoord twipsPerPixel,
-            nsRect *aGap = nsnull)
-{
-  // Examine the border style to figure out if we can draw it in one
-  // go or not.
-  PRUint8 numRenderPasses = NumBorderPasses (borderStyles, borderColors, compositeColors);
-  if (numRenderPasses == 0) {
-    // all the colors are transparent; nothing to do.
-    return;
-  }
-
-  // round oRect and iRect; they're already an integer
-  // number of pixels apart and should stay that way after
-  // rounding.
-  oRect.Round();
-  iRect.Round();
-
-  S(" oRect: "), S(oRect), SN();
-  S(" iRect: "), S(iRect), SN();
-  SF(" borderColors: 0x%08x 0x%08x 0x%08x 0x%08x\n", borderColors[0], borderColors[1], borderColors[2], borderColors[3]);
-
-  // if conditioning the outside rect failed, then bail -- the outside
-  // rect is supposed to enclose the entire border
-  oRect.Condition();
-  if (oRect.IsEmpty())
-    return;
-
-  iRect.Condition();
-
-  // do we have any sides that are dotted/dashed?
-  PRIntn dashedSides = 0;
-  for (int i = 0; i < 4; i++) {
-    PRUint8 style = borderStyles[i];
-    if (style == NS_STYLE_BORDER_STYLE_DASHED ||
-        style == NS_STYLE_BORDER_STYLE_DOTTED)
-    {
-      dashedSides |= (1 << i);
-    }
-
-    // just bail out entirely if RULES_MARKER
-    // got through (see bug 379419).
-    if (style & NS_STYLE_BORDER_STYLE_RULES_MARKER)
-      return;
-  }
-
-  SF(" dashedSides: 0x%02x\n", dashedSides);
-
-  // 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);
-  }
-
-  // if we're going to do separate sides, we need to do it as
-  // a temporary surface group
-  PRBool canAvoidGroup = PR_TRUE;
-  if (numRenderPasses > 1) {
-    // clip to oRect to define the size of the temporary surface
-    ctx->NewPath();
-    ctx->Rectangle(oRect);
-
-    if (aGap) {
-      gfxRect gapRect(RectToGfxRect(*aGap, twipsPerPixel));
-
-      // draw the rectangle backwards, so that we get it
-      // clipped out via the winding rule
-      ctx->MoveTo(gapRect.pos);
-      ctx->LineTo(gapRect.pos + gfxSize(0.0, gapRect.size.height));
-      ctx->LineTo(gapRect.pos + gapRect.size);
-      ctx->LineTo(gapRect.pos + gfxSize(gapRect.size.width, 0.0));
-      ctx->ClosePath();
-    }
-
-    ctx->Clip();
-
-    // OPTIMIZATION
-    // Starting a compositing group is more work than necessary;
-    // can avoid doing it if:
-    // a) all the colors involved have to be solid (NS_GET_A(c) == 0xff)
-    // b) no border radius is involved (the curves have antialiasing)
-    // c) no dashed/dotted borders are involved
-    // d) no DOUBLE style is involved (the middle part of DOUBLE needs
-    //    to have the the background color show through; [we could
-    //    handle this by just clearing out the parts that will be drawn])
-
-    if (dashedSides != 0) {
-      canAvoidGroup = PR_FALSE;
-    } else {
-      for (int i = 0; i < 4; i++) {
-        if (borderRadii[i] != 0.0) {
-          canAvoidGroup = PR_FALSE;
-          break;
-        }
-
-        PRUint8 style = borderStyles[i];
-        if (style == NS_STYLE_BORDER_STYLE_DASHED ||
-            style == NS_STYLE_BORDER_STYLE_DOTTED ||
-            style == NS_STYLE_BORDER_STYLE_DOUBLE)
-        {
-          canAvoidGroup = PR_FALSE;
-          break;
-        }
-
-        if (compositeColors[i]) {
-          nsBorderColors* colors = compositeColors[i];
-          do {
-            if (NS_GET_A(colors->mColor) != 0xff) {
-              canAvoidGroup = PR_FALSE;
-              break;
-            }
-
-            colors = colors->mNext;
-          } while (colors);
-        } else {
-          if (NS_GET_A(borderColors[i]) != 0xff) {
-            canAvoidGroup = PR_FALSE;
-            break;
-          }
-        }
-      }
-    }
-
-    if (canAvoidGroup) {
-      // clear the area underneath where the border's to be
-      // rendered, so we can avoid using a compositing group
-      // but still have the ADD operator work correctly
-
-      // OPTIMIZATION
-      // avoid doing a group or using OPERATOR_ADD for the common
-      // case of a TL/BR border style in 1px size.
-      if (numRenderPasses == 2 &&
-          CheckFourFloatsEqual(borderWidths, 1.0) &&
-          NS_GET_A(borderColors[0]) == 0xff)
-      {
-        // OVER is faster than SOURCE in a lot of cases, and they'll
-        // behave the same since the color has no transparency.
-        // We don't need to clear anything out in this case, either.
-        ctx->SetOperator(gfxContext::OPERATOR_OVER);
-      } else {
-        // clear out the area so that we can use ADD without drawing
-        ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
-        FillFastBorderPath(ctx, oRect, iRect, borderRadii, borderWidths, SIDE_BITS_ALL, gfxRGBA(0.0,0.0,0.0,0.0));
-        ctx->SetOperator(gfxContext::OPERATOR_ADD);
-      }
-    } else {
-      // start a compositing group
-      ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
-      ctx->SetOperator(gfxContext::OPERATOR_ADD);
-    }
-
-    SF("canAvoidGroup: %d\n", canAvoidGroup);
-  } else if (aGap) {
-    gfxRect gapRect(RectToGfxRect(*aGap, twipsPerPixel));
-
-    // draw the rectangle backwards, so that we get it
-    // clipped out via the winding rule
-    ctx->MoveTo(gapRect.pos);
-    ctx->LineTo(gapRect.pos + gfxSize(0.0, gapRect.size.height));
-    ctx->LineTo(gapRect.pos + gapRect.size);
-    ctx->LineTo(gapRect.pos + gfxSize(gapRect.size.width, 0.0));
-    ctx->ClosePath();
-    ctx->Clip();
-  }
-
-  // if we have dashed sides, clip to the corners so that we can draw the
-  // dashed bits later.
-  if (dashedSides) {
-    ctx->Save();
-
-    ctx->NewPath();
-    DoCornerClipSubPath(ctx, oRect, iRect, borderRadii, dashedSides);
-
-#if 0
-    ctx->SetColor(gfxRGBA(1.0, 0.0, 1.0, 1.0));
-    ctx->SetLineWidth(2.);
-    ctx->Stroke();
-#endif
-
-    ctx->Clip();
-  }
-
-  // Render with either 1, 2, or 4 passes, depending on how
-  // many are needed to get the job done.
-  for (int i = 0; i < numRenderPasses; i++) {
-    PRIntn sideBits;
-    PRUint8 side;
-
-    if (numRenderPasses == 4) {
-      side = gBorderSideOrder[i];
-      sideBits = 1 << side;
-
-      // skip this side if it's, well, skipped
-      if (skipSides & (1 << side))
-        continue;
-
-      ctx->Save();
-      ctx->NewPath();
-
-      DoSideClipSubPath(ctx, iRect, oRect, side, borderStyles, borderRadii);
-
-      ctx->Clip();
-    } else if (numRenderPasses == 2) {
-      if (i == 0) {
-        side = NS_SIDE_TOP;
-        sideBits = SIDE_BIT_TOP | SIDE_BIT_LEFT;
-      } else {
-        side = NS_SIDE_BOTTOM;
-        sideBits = SIDE_BIT_BOTTOM | SIDE_BIT_RIGHT;
-      }
-    } else {
-        side = NS_SIDE_TOP;
-        sideBits = SIDE_BITS_ALL;
-    }
-
-    const PRUint8 style = borderStyles[side];
-    if (style != NS_STYLE_BORDER_STYLE_NONE &&
-        style != NS_STYLE_BORDER_STYLE_HIDDEN) {
-      // Draw the whole border.  If we're not drawing multiple passes,
-      // 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.
-
-      DrawBorderSides(ctx,
-                      borderWidths,
-                      sideBits,
-                      style,
-                      oRect, iRect,
-                      borderColors[side],
-                      compositeColors[side],
-                      backgroundColor,
-                      twipsPerPixel,
-                      borderRadii);
-      SN("----------------");
-    }
-
-    if (numRenderPasses > 2)
-      ctx->Restore();
-  }
-
-  // now fill in any dotted/dashed borders
-  if (dashedSides != 0) {
-    // get rid of the corner clip we set earlier
-    ctx->Restore();
-
-    gfxSize dims[4];
-    GetBorderCornerDimensions(oRect, iRect, borderRadii, dims);
-
-    for (int i = 0; i < 4; i++) {
-      PRUint8 side = gBorderSideOrder[i];
-      if (NS_GET_A(borderColors[side]) != 0x00 && dashedSides & (1 << side)) {
-        // side is dotted/dashed.
-        DrawDashedSide (ctx, side,
-                        iRect, oRect,
-                        borderStyles[side],
-                        borderWidths[side],
-                        borderColors[side],
-                        dims);
-      }
-    }
-  }
-
-  if (!canAvoidGroup) {
-    ctx->PopGroupToSource();
-    ctx->Paint();
-  }
+  gfxFloat f[4];
+  f[C_TL] = gfxFloat(PR_MIN(twipsRadii[C_TL], PR_MIN(maxRadiusSize.top, maxRadiusSize.left))) / twipsPerPixel;
+  f[C_TR] = gfxFloat(PR_MIN(twipsRadii[C_TR], PR_MIN(maxRadiusSize.top, maxRadiusSize.right))) / twipsPerPixel;
+  f[C_BL] = gfxFloat(PR_MIN(twipsRadii[C_BL], PR_MIN(maxRadiusSize.bottom, maxRadiusSize.left))) / twipsPerPixel;
+  f[C_BR] = gfxFloat(PR_MIN(twipsRadii[C_BR], PR_MIN(maxRadiusSize.bottom, maxRadiusSize.right))) / twipsPerPixel;
+
+  (*oBorderRadii)[C_TL] = gfxSize(f[C_TL], f[C_TL]);
+  (*oBorderRadii)[C_TR] = gfxSize(f[C_TR], f[C_TR]);
+  (*oBorderRadii)[C_BL] = gfxSize(f[C_BL], f[C_BL]);
+  (*oBorderRadii)[C_BR] = gfxSize(f[C_BR], f[C_BR]);
 }
 
 void
 nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
                             nsIRenderingContext& aRenderingContext,
                             nsIFrame* aForFrame,
                             const nsRect& aDirtyRect,
                             const nsRect& aBorderArea,
@@ -2729,60 +1040,44 @@ nsCSSRendering::PaintBorder(nsPresContex
 
   // Turn off rendering for all of the zero sized sides
   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), innerRect(aBorderArea);
-  innerRect.Deflate(border);
-
-  SF(" innerRect: %d %d %d %d\n", innerRect.x, innerRect.y, innerRect.width, innerRect.height);
+  nsRect outerRect(aBorderArea);
+
   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;
-  }
-
   // we can assume that we're already clipped to aDirtyRect -- I think? (!?)
 
   // Get our conversion values
   nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
 
   // convert outer and inner rects
   gfxRect oRect(RectToGfxRect(outerRect, twipsPerPixel));
-  gfxRect iRect(RectToGfxRect(innerRect, twipsPerPixel));
 
   // convert the border widths
   gfxFloat borderWidths[4] = { border.top / twipsPerPixel,
                                border.right / twipsPerPixel,
                                border.bottom / twipsPerPixel,
                                border.left / twipsPerPixel };
 
   // convert the radii
-  gfxFloat borderRadii[4];
-  ComputePixelRadii(twipsRadii, outerRect, border, aSkipSides, twipsPerPixel, borderRadii);
+  gfxCornerSizes borderRadii;
+  ComputePixelRadii(twipsRadii, outerRect, border, aSkipSides, twipsPerPixel, &borderRadii);
 
   PRUint8 borderStyles[4];
   nscolor borderColors[4];
   nsBorderColors *compositeColors[4];
 
   // pull out styles, colors, composite colors
-  for (int i = 0; i < 4; i++) {
+  NS_FOR_CSS_SIDES (i) {
     PRBool transparent, foreground;
     borderStyles[i] = aBorderStyle.GetBorderStyle(i);
     aBorderStyle.GetBorderColor(i, borderColors[i], transparent, foreground);
     aBorderStyle.GetCompositeColors(i, &compositeColors[i]);
 
     if (transparent)
       borderColors[i] = 0x0;
     else if (foreground)
@@ -2792,42 +1087,42 @@ nsCSSRendering::PaintBorder(nsPresContex
   SF(" borderStyles: %d %d %d %d\n", borderStyles[0], borderStyles[1], borderStyles[2], borderStyles[3]);
 
   // start drawing
   gfxContext *ctx = aRenderingContext.ThebesContext();
 
   ctx->Save();
 
 #if 0
-  // this will draw a transparent red backround underneath the area between iRect and oRect
+  // this will draw a transparent red backround underneath the oRect area
   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
 
-  SF ("borderRadii: %f %f %f %f\n", borderRadii[0], borderRadii[1], borderRadii[2], borderRadii[3]);
-
-  DrawBorders(ctx,
-              oRect,
-              iRect,
-              borderStyles,
-              borderWidths,
-              borderRadii,
-              borderColors,
-              compositeColors,
-              aSkipSides,
-              bgColor->mBackgroundColor,
-              twipsPerPixel,
-              aGap);
+  //SF ("borderRadii: %f %f %f %f\n", borderRadii[0], borderRadii[1], borderRadii[2], borderRadii[3]);
+
+  gfxRect gapRect;
+  if (aGap)
+    gapRect = RectToGfxRect(*aGap, twipsPerPixel);
+
+  nsCSSBorderRenderer br(twipsPerPixel,
+                         ctx,
+                         oRect,
+                         borderStyles,
+                         borderWidths,
+                         borderRadii,
+                         borderColors,
+                         compositeColors,
+                         aSkipSides,
+                         bgColor->mBackgroundColor,
+                         aGap ? &gapRect : nsnull);
+  br.DrawBorders();
 
   ctx->Restore();
 
   SN();
 }
 
 void
 nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
@@ -2918,24 +1213,23 @@ nsCSSRendering::PaintOutline(nsPresConte
   // shorten insideRect by the radius one each side before performing this test.
   if (innerRect.Contains(aDirtyRect)) {
     return;
   }
 
   // Get our conversion values
   nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
 
-  // get the inner and outer rectangles
+  // get the outer rectangles
   gfxRect oRect(RectToGfxRect(outerRect, twipsPerPixel));
-  gfxRect iRect(RectToGfxRect(innerRect, twipsPerPixel));
 
   // convert the radii
   nsMargin outlineMargin(width, width, width, width);
-  gfxFloat outlineRadii[4];
-  ComputePixelRadii(twipsRadii, outerRect, outlineMargin, 0, twipsPerPixel, outlineRadii);
+  gfxCornerSizes outlineRadii;
+  ComputePixelRadii(twipsRadii, outerRect, outlineMargin, 0, twipsPerPixel, &outlineRadii);
 
   PRUint8 outlineStyle = aOutlineStyle.GetOutlineStyle();
   PRUint8 outlineStyles[4] = { outlineStyle,
                                outlineStyle,
                                outlineStyle,
                                outlineStyle };
 
   nscolor outlineColor;
@@ -2956,28 +1250,32 @@ nsCSSRendering::PaintOutline(nsPresConte
                                 width / twipsPerPixel,
                                 width / twipsPerPixel };
 
   // start drawing
   gfxContext *ctx = aRenderingContext.ThebesContext();
 
   ctx->Save();
 
-  DrawBorders(ctx,
-              oRect,
-              iRect,
-              outlineStyles,
-              outlineWidths,
-              outlineRadii,
-              outlineColors,
-              outlineCompositeColors,
-              0,
-              bgColor->mBackgroundColor,
-              twipsPerPixel,
-              aGap);
+  gfxRect gapRect;
+  if (aGap)
+    gapRect = RectToGfxRect(*aGap, twipsPerPixel);
+
+  nsCSSBorderRenderer br(twipsPerPixel,
+                         ctx,
+                         oRect,
+                         outlineStyles,
+                         outlineWidths,
+                         outlineRadii,
+                         outlineColors,
+                         outlineCompositeColors,
+                         0,
+                         bgColor->mBackgroundColor,
+                         aGap ? &gapRect : nsnull);
+  br.DrawBorders();
 
   ctx->Restore();
 
   SN();
 }
 
 // Thebes Border Rendering Code End
 //----------------------------------------------------------------------
@@ -3302,20 +1600,20 @@ nsCSSRendering::DidPaint()
 /* static */ PRBool
 nsCSSRendering::GetBorderRadiusTwips(const nsStyleSides& aBorderRadius,
                                      const nscoord& aFrameWidth,
                                      nscoord aTwipsRadii[4])
 {
   nsStyleCoord bordStyleRadius[4];
   PRBool result = PR_FALSE;
 
-  bordStyleRadius[0] = aBorderRadius.GetTop();    //topleft
-  bordStyleRadius[1] = aBorderRadius.GetRight();  //topright
-  bordStyleRadius[2] = aBorderRadius.GetBottom(); //bottomright
-  bordStyleRadius[3] = aBorderRadius.GetLeft();   //bottomleft
+  bordStyleRadius[gfxCorner::TOP_LEFT] = aBorderRadius.GetTop();
+  bordStyleRadius[gfxCorner::TOP_RIGHT] = aBorderRadius.GetRight();
+  bordStyleRadius[gfxCorner::BOTTOM_RIGHT] = aBorderRadius.GetBottom();
+  bordStyleRadius[gfxCorner::BOTTOM_LEFT] = aBorderRadius.GetLeft();
 
   // Convert percentage values
   for (int i = 0; i < 4; i++) {
     aTwipsRadii[i] = 0;
     float percent;
 
     switch (bordStyleRadius[i].GetUnit()) {
       case eStyleUnit_Percent:
@@ -3339,30 +1637,31 @@ nsCSSRendering::GetBorderRadiusTwips(con
 
 void
 nsCSSRendering::PaintBoxShadow(nsPresContext* aPresContext,
                                nsIRenderingContext& aRenderingContext,
                                nsIFrame* aForFrame,
                                const nsPoint& aForFramePt)
 {
   nsMargin      borderValues;
-  gfxFloat      borderRadii[4];
   PRIntn        sidesToSkip;
   nsRect        frameRect;
 
   const nsStyleBorder* styleBorder = aForFrame->GetStyleBorder();
   borderValues = styleBorder->GetActualBorder();
   sidesToSkip = aForFrame->GetSkipSides();
   frameRect = nsRect(aForFramePt, aForFrame->GetSize());
 
   // Get any border radius, since box-shadow must also have rounded corners if the frame does
   nscoord twipsRadii[4];
   PRBool hasBorderRadius = GetBorderRadiusTwips(styleBorder->mBorderRadius, frameRect.width, twipsRadii);
   nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-  ComputePixelRadii(twipsRadii, frameRect, borderValues, sidesToSkip, twipsPerPixel, borderRadii);
+
+  gfxCornerSizes borderRadii;
+  ComputePixelRadii(twipsRadii, frameRect, borderValues, sidesToSkip, twipsPerPixel, &borderRadii);
 
   gfxRect frameGfxRect = RectToGfxRect(frameRect, twipsPerPixel);
   for (PRUint32 i = styleBorder->mBoxShadow->Length(); i > 0; --i) {
     nsCSSShadowItem* shadowItem = styleBorder->mBoxShadow->ShadowAt(i - 1);
     gfxRect shadowRect(frameRect.x, frameRect.y, frameRect.width, frameRect.height);
     shadowRect.MoveBy(gfxPoint(shadowItem->mXOffset.GetCoordValue(),
                                shadowItem->mYOffset.GetCoordValue()));
     shadowRect.Outset(shadowItem->mSpread.GetCoordValue());
@@ -3398,30 +1697,30 @@ nsCSSRendering::PaintBoxShadow(nsPresCon
     renderContext->Save();
     renderContext->SetColor(gfxRGBA(shadowColor));
 
     // Clip out the area of the actual frame so the shadow is not shown within
     // the frame
     renderContext->NewPath();
     renderContext->Rectangle(shadowRectPlusBlur);
     if (hasBorderRadius)
-      DoRoundedRectCWSubPath(renderContext, frameGfxRect, borderRadii);
+      renderContext->RoundedRectangle(frameGfxRect, borderRadii);
     else
       renderContext->Rectangle(frameGfxRect);
     renderContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
     renderContext->Clip();
 
     // Draw the shape of the frame so it can be blurred. Recall how nsContextBoxBlur
     // doesn't make any temporary surfaces if blur is 0 and it just returns the original
     // surface? If we have no blur, we're painting this fill on the actual content surface
     // (renderContext == shadowContext) which is why we set up the color and clip
     // before doing this.
     shadowContext->NewPath();
     if (hasBorderRadius)
-      DoRoundedRectCWSubPath(shadowContext, shadowRect, borderRadii);
+      shadowContext->RoundedRectangle(shadowRect, borderRadii);
     else
       shadowContext->Rectangle(shadowRect);
     shadowContext->Fill();
 
     blurringArea.DoPaint();
     renderContext->Restore();
   }
 }
@@ -3881,27 +2180,27 @@ nsCSSRendering::PaintBackgroundWithSC(ns
   ctx->NewPath();
   ctx->Rectangle(RectToGfxRect(dirtyRect, appUnitsPerPixel), PR_TRUE);
   ctx->Clip();
 
   nscoord borderRadii[4];
   PRBool haveRadius = GetBorderRadiusTwips(aBorder.mBorderRadius, aForFrame->GetSize().width, borderRadii);
 
   if (haveRadius) {
-    gfxFloat radii[4];
+    gfxCornerSizes radii;
     ComputePixelRadii(borderRadii, bgClipArea, aBorder.GetActualBorder(),
                       aForFrame ? aForFrame->GetSkipSides() : 0,
-                      appUnitsPerPixel, radii);
+                      appUnitsPerPixel, &radii);
 
     gfxRect oRect(RectToGfxRect(bgClipArea, appUnitsPerPixel));
     oRect.Round();
     oRect.Condition();
 
     ctx->NewPath();
-    DoRoundedRectCWSubPath(ctx, oRect, radii);
+    ctx->RoundedRectangle(oRect, radii);
     ctx->Clip();
   }      
 
   // Compute the x and y starting points and limits for tiling
 
   /* An Overview Of The Following Logic
 
           A........ . . . . . . . . . . . . . .
@@ -4544,37 +2843,39 @@ nsCSSRendering::PaintRoundedBackground(n
   // the bgClipArea is the outside
   gfxRect oRect(RectToGfxRect(aBgClipArea, appUnitsPerPixel));
   oRect.Round();
   oRect.Condition();
   if (oRect.IsEmpty())
     return;
 
   // convert the radii
-  gfxFloat radii[4];
+  gfxCornerSizes radii;
   nsMargin border = aBorder.GetActualBorder();
 
   ComputePixelRadii(aTheRadius, aBgClipArea, border,
                     aForFrame ? aForFrame->GetSkipSides() : 0,
-                    appUnitsPerPixel, radii);
+                    appUnitsPerPixel, &radii);
 
   // Add 1.0 to any border radii; if we don't, the border and background
   // curves will combine to have fringing at the rounded corners.  Since
   // alpha is used for coverage, we have problems because the border and
   // background should have identical coverage, and the border should
   // overlay the background exactly.  The way to avoid this is by using
   // a supersampling scheme, but we don't have the mechanism in place to do
   // this.  So, this will do for now.
   for (int i = 0; i < 4; i++) {
-    if (radii[i] > 0.0)
-      radii[i] += 1.0;
+    if (radii[i].width > 0.0)
+      radii[i].width += 1.0;
+    if (radii[i].height > 0.0)
+      radii[i].height += 1.0;
   }
 
   ctx->NewPath();
-  DoRoundedRectCWSubPath(ctx, oRect, radii);
+  ctx->RoundedRectangle(oRect, radii);
   ctx->SetColor(gfxRGBA(color));
   ctx->Fill();
 }
 
 
 void FillOrInvertRect(nsIRenderingContext& aRC, nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aInvert)
 {
 #ifdef GFX_HAS_INVERT
new file mode 100644
--- /dev/null
+++ b/layout/base/nsCSSRenderingBorders.cpp
@@ -0,0 +1,1106 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:cindent:ts=2:et:sw=2:
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * 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 "nsStyleConsts.h"
+#include "nsPresContext.h"
+#include "nsIImage.h"
+#include "nsIFrame.h"
+#include "nsPoint.h"
+#include "nsRect.h"
+#include "nsIViewManager.h"
+#include "nsIPresShell.h"
+#include "nsFrameManager.h"
+#include "nsStyleContext.h"
+#include "nsGkAtoms.h"
+#include "nsCSSAnonBoxes.h"
+#include "nsTransform2D.h"
+#include "nsIDeviceContext.h"
+#include "nsIContent.h"
+#include "nsIDocument.h"
+#include "nsIScrollableFrame.h"
+#include "imgIRequest.h"
+#include "imgIContainer.h"
+#include "gfxIImageFrame.h"
+#include "nsCSSRendering.h"
+#include "nsCSSColorUtils.h"
+#include "nsITheme.h"
+#include "nsThemeConstants.h"
+#include "nsIServiceManager.h"
+#include "nsIHTMLDocument.h"
+#include "nsLayoutUtils.h"
+#include "nsINameSpaceManager.h"
+#include "nsBlockFrame.h"
+
+#include "gfxContext.h"
+
+#include "nsCSSRenderingBorders.h"
+
+/**
+ * nsCSSRendering::PaintBorder
+ * nsCSSRendering::PaintOutline
+ *   -> DrawBorders
+ *
+ * DrawBorders
+ *   |- separate corners?
+ *   |- dashed side mask
+ *   |- gap clip
+ *   |
+ *   -> can border be drawn in 1 pass? (e.g., solid border same color all around)
+ *      |- DrawBorderSides with all 4 sides
+ *   -> more than 1 pass?
+ *      |- for each corner
+ *         |- clip to DoCornerClipSubPath
+ *         |- PushGroup
+ *         |- for each side adjacent to corner
+ *            |- clip to DoSideClipSubPath
+ *            |- DrawBorderSides with one side
+ *         |- PopGroup
+ *      |- for each side
+ *         |- DoSideClipWithoutCornersSubPath
+ *         |- DrawDashedSide || DrawBorderSides with one side
+ */
+
+static void ComputeBorderCornerDimensions(const gfxRect& aOuterRect,
+                                          const gfxRect& aInnerRect,
+                                          const gfxCornerSizes& aRadii,
+                                          gfxCornerSizes *aDimsResult);
+
+static void ComputeInnerRadii(const gfxCornerSizes& radii,
+                              const gfxFloat *borderSizes,
+                              gfxCornerSizes *innerRadii);
+
+// given a side index, get the previous and next side index
+#define NEXT_SIDE(_s) (((_s) + 1) & 3)
+#define PREV_SIDE(_s) (((_s) + 3) & 3)
+
+// from the given base color and the background color, turn
+// color into a color for the given border pattern style
+typedef enum {
+  BorderColorStyleNone,
+  BorderColorStyleSolid,
+  BorderColorStyleLight,
+  BorderColorStyleDark
+} BorderColorStyle;
+
+static gfxRGBA MakeBorderColor(const gfxRGBA& aColor,
+                               const gfxRGBA& aBackgroundColor,
+                               BorderColorStyle aBorderColorStyle);
+
+
+// Given a line index (an index starting from the outside of the
+// border going inwards) and an array of line styles, calculate the
+// color that that stripe of the border should be rendered in.
+static gfxRGBA ComputeColorForLine(PRUint32 aLineIndex,
+                                   const BorderColorStyle* aBorderColorStyle,
+                                   PRUint32 aBorderColorStyleCount,
+                                   nscolor aBorderColor,
+                                   nscolor aBackgroundColor);
+
+static gfxRGBA ComputeCompositeColorForLine(PRUint32 aLineIndex,
+                                            const nsBorderColors* aBorderColors);
+
+// little helper function to check if the array of 4 floats given are
+// equal to the given value
+static PRBool
+CheckFourFloatsEqual(const gfxFloat *vals, gfxFloat k)
+{
+  return (vals[0] == k &&
+          vals[1] == k &&
+          vals[2] == k &&
+          vals[3] == k);
+}
+
+static bool
+IsZeroSize(const gfxSize& sz) {
+  return sz.width == 0.0 || sz.height == 0.0;
+}
+
+static bool
+AllCornersZeroSize(const gfxCornerSizes& corners) {
+  return IsZeroSize(corners[0]) &&
+    IsZeroSize(corners[1]) &&
+    IsZeroSize(corners[2]) &&
+    IsZeroSize(corners[3]);
+}
+
+typedef enum {
+  // Normal solid square corner.  Will be rectangular, the size of the
+  // adjacent sides.  If the corner has a border radius, the corner
+  // will always be solid, since we don't do dotted/dashed etc.
+  CORNER_NORMAL,
+
+  // Paint the corner in whatever style is not dotted/dashed of the
+  // adjacent corners.
+  CORNER_SOLID,
+
+  // Paint the corner as a dot, the size of the bigger of the adjacent
+  // sides.
+  CORNER_DOT
+} CornerStyle;
+
+nsCSSBorderRenderer::nsCSSBorderRenderer(PRInt32 aAppUnitsPerPixel,
+                                         gfxContext* aDestContext,
+                                         gfxRect& aOuterRect,
+                                         const PRUint8* aBorderStyles,
+                                         const gfxFloat* aBorderWidths,
+                                         gfxCornerSizes& aBorderRadii,
+                                         const nscolor* aBorderColors,
+                                         nsBorderColors* const* aCompositeColors,
+                                         PRIntn aSkipSides,
+                                         nscolor aBackgroundColor,
+                                         const gfxRect* aGapRect)
+  : mAUPP(aAppUnitsPerPixel),
+    mContext(aDestContext),
+    mOuterRect(aOuterRect),
+    mBorderStyles(aBorderStyles),
+    mBorderWidths(aBorderWidths),
+    mBorderRadii(aBorderRadii),
+    mBorderColors(aBorderColors),
+    mCompositeColors(aCompositeColors),
+    mSkipSides(aSkipSides),
+    mBackgroundColor(aBackgroundColor),
+    mGapRect(aGapRect)
+{
+  if (!mCompositeColors) {
+    static nsBorderColors * const noColors[4] = { NULL };
+    mCompositeColors = &noColors[0];
+  }
+
+  mInnerRect = mOuterRect;
+  mInnerRect.Inset(mBorderWidths[0], mBorderWidths[1], mBorderWidths[2], mBorderWidths[3]);
+
+  ComputeBorderCornerDimensions(mOuterRect, mInnerRect, mBorderRadii, &mBorderCornerDimensions);
+}
+
+void
+ComputeInnerRadii(const gfxCornerSizes& aRadii,
+                  const gfxFloat *aBorderSizes,
+                  gfxCornerSizes *aInnerRadiiRet)
+{
+  gfxCornerSizes& iRadii = *aInnerRadiiRet;
+
+  iRadii[C_TL].width = PR_MAX(0.0, aRadii[C_TL].width - aBorderSizes[NS_SIDE_LEFT]);
+  iRadii[C_TL].height = PR_MAX(0.0, aRadii[C_TL].height - aBorderSizes[NS_SIDE_TOP]);
+
+  iRadii[C_TR].width = PR_MAX(0.0, aRadii[C_TR].width - aBorderSizes[NS_SIDE_RIGHT]);
+  iRadii[C_TR].height = PR_MAX(0.0, aRadii[C_TR].height - aBorderSizes[NS_SIDE_TOP]);
+
+  iRadii[C_BR].width = PR_MAX(0.0, aRadii[C_BR].width - aBorderSizes[NS_SIDE_RIGHT]);
+  iRadii[C_BR].height = PR_MAX(0.0, aRadii[C_BR].height - aBorderSizes[NS_SIDE_BOTTOM]);
+
+  iRadii[C_BL].width = PR_MAX(0.0, aRadii[C_BL].width - aBorderSizes[NS_SIDE_LEFT]);
+  iRadii[C_BL].height = PR_MAX(0.0, aRadii[C_BL].height - aBorderSizes[NS_SIDE_BOTTOM]);
+}
+
+/*static*/ void
+ComputeBorderCornerDimensions(const gfxRect& aOuterRect,
+                              const gfxRect& aInnerRect,
+                              const gfxCornerSizes& aRadii,
+                              gfxCornerSizes *aDimsRet)
+{
+  gfxFloat topWidth = aInnerRect.pos.y - aOuterRect.pos.y;
+  gfxFloat leftWidth = aInnerRect.pos.x - aOuterRect.pos.x;
+  gfxFloat rightWidth = aOuterRect.size.width - aInnerRect.size.width - leftWidth;
+  gfxFloat bottomWidth = aOuterRect.size.height - aInnerRect.size.height - topWidth;
+
+  if (AllCornersZeroSize(aRadii)) {
+    // These will always be in pixel units from CSS
+    (*aDimsRet)[C_TL] = gfxSize(leftWidth, topWidth);
+    (*aDimsRet)[C_TR] = gfxSize(rightWidth, topWidth);
+    (*aDimsRet)[C_BR] = gfxSize(rightWidth, bottomWidth);
+    (*aDimsRet)[C_BL] = gfxSize(leftWidth, bottomWidth);
+  } else {
+    // Always round up to whole pixels for the corners; it's safe to
+    // make the corners bigger than necessary, and this way we ensure
+    // that we avoid seams.
+    (*aDimsRet)[C_TL] = gfxSize(ceil(PR_MAX(leftWidth, aRadii[C_TL].width)),
+                                ceil(PR_MAX(topWidth, aRadii[C_TL].height)));
+    (*aDimsRet)[C_TR] = gfxSize(ceil(PR_MAX(rightWidth, aRadii[C_TR].width)),
+                                ceil(PR_MAX(topWidth, aRadii[C_TR].height)));
+    (*aDimsRet)[C_BR] = gfxSize(ceil(PR_MAX(rightWidth, aRadii[C_BR].width)),
+                                ceil(PR_MAX(bottomWidth, aRadii[C_BR].height)));
+    (*aDimsRet)[C_BL] = gfxSize(ceil(PR_MAX(leftWidth, aRadii[C_BL].width)),
+                                ceil(PR_MAX(bottomWidth, aRadii[C_BL].height)));
+  }
+}
+
+// And this is what we get due to the aRidiculous aPrefix aConvetion
+// aFor aArguments (sic).
+static PRBool
+AreCompositeColorsEqual(nsBorderColors *aA, nsBorderColors *aB)
+{
+  if (aA == aB)
+    return PR_TRUE;
+
+  if (!aA || !aB)
+    return PR_FALSE;
+
+  while (aA && aB) {
+    if (aA->mTransparent != aB->mTransparent)
+      return PR_FALSE;
+    if (!aA->mTransparent && (aA->mColor != aB->mColor))
+      return PR_FALSE;
+    aA = aA->mNext;
+    aB = aB->mNext;
+  }
+
+  // both should be NULL if these are equal, otherwise one
+  // has more colors than another
+  return (aA == aB);
+}
+
+PRBool
+nsCSSBorderRenderer::AreBorderSideFinalStylesSame(PRUint8 aSides)
+{
+  NS_ASSERTION(aSides != 0 && (aSides & ~SIDE_BITS_ALL) == 0,
+               "AreBorderSidesSame: invalid whichSides!");
+
+  /* First check if the specified styles and colors are the same for all sides */
+  int firstStyle = 0;
+  NS_FOR_CSS_SIDES (i) {
+    if (firstStyle == i) {
+      if (((1 << i) & aSides) == 0)
+        firstStyle++;
+      continue;
+    }
+
+    if (mBorderStyles[firstStyle] != mBorderStyles[i] ||
+        mBorderColors[firstStyle] != mBorderColors[i] ||
+        !AreCompositeColorsEqual(mCompositeColors[firstStyle], mCompositeColors[i]))
+      return PR_FALSE;
+  }
+
+  /* Then if it's one of the two-tone styles and we're not
+   * just comparing the TL or BR sides */
+  switch (mBorderStyles[firstStyle]) {
+    case NS_STYLE_BORDER_STYLE_GROOVE:
+    case NS_STYLE_BORDER_STYLE_RIDGE:
+    case NS_STYLE_BORDER_STYLE_INSET:
+    case NS_STYLE_BORDER_STYLE_OUTSET:
+      return ((aSides & ~(SIDE_BIT_TOP | SIDE_BIT_LEFT)) == 0 ||
+              (aSides & ~(SIDE_BIT_BOTTOM | SIDE_BIT_RIGHT)) == 0);
+  }
+
+  return PR_TRUE;
+}
+
+
+void
+nsCSSBorderRenderer::DoCornerClipSubPath(PRUint8 aCorner)
+{
+  gfxPoint offset(0.0, 0.0);
+
+  if (aCorner == C_TR || aCorner == C_BR)
+    offset.x = mOuterRect.size.width - mBorderCornerDimensions[aCorner].width;
+  if (aCorner == C_BR || aCorner == C_BL)
+    offset.y = mOuterRect.size.height - mBorderCornerDimensions[aCorner].height;
+
+  mContext->Rectangle(gfxRect(mOuterRect.pos + offset,
+                              mBorderCornerDimensions[aCorner]));
+}
+
+void
+nsCSSBorderRenderer::DoSideClipWithoutCornersSubPath(PRUint8 aSide)
+{
+  gfxPoint offset(0.0, 0.0);
+
+  // The offset from the outside rect to the start of this side's
+  // box.  For the top and bottom sides, the height of the box
+  // must be the border height; the x start must take into account
+  // the corner size (which may be bigger than the right or left
+  // side's width).  The same applies to the right and left sides.
+  if (aSide == NS_SIDE_TOP) {
+    offset.x = mBorderCornerDimensions[C_TL].width;
+  } else if (aSide == NS_SIDE_RIGHT) {
+    offset.x = mOuterRect.size.width - mBorderWidths[NS_SIDE_RIGHT];
+    offset.y = mBorderCornerDimensions[C_TR].height;
+  } else if (aSide == NS_SIDE_BOTTOM) {
+    offset.x = mBorderCornerDimensions[C_BL].width;
+    offset.y = mOuterRect.size.height - mBorderWidths[NS_SIDE_BOTTOM];
+  } else if (aSide == NS_SIDE_LEFT) {
+    offset.y = mBorderCornerDimensions[C_TL].height;
+  }
+
+  // The sum of the width & height of the corners adjacent to the
+  // side.  This relies on the relationship between side indexing and
+  // corner indexing; that is, 0 == SIDE_TOP and 0 == CORNER_TOP_LEFT,
+  // with both proceeding clockwise.
+  gfxSize sideCornerSum = mBorderCornerDimensions[aSide] + mBorderCornerDimensions[NEXT_SIDE(aSide)];
+  gfxRect rect(mOuterRect.pos + offset,
+               mOuterRect.size - sideCornerSum);
+
+  if (aSide == NS_SIDE_TOP || aSide == NS_SIDE_BOTTOM)
+    rect.size.height = mBorderWidths[aSide];
+  else
+    rect.size.width = mBorderWidths[aSide];
+
+  mContext->Rectangle(rect);
+}
+
+// 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;
+
+// Given three points, p0, p1, and midPoint, if p0 and p1 do not form
+// a horizontal or vertical line move p1 to the point nearest the
+// midpoint, while maintaing the slope of the line.
+static void
+MaybeMoveToMidPoint(gfxPoint& aP0, gfxPoint& aP1, const gfxPoint& aMidPoint)
+{
+  gfxPoint ps = aP1 - aP0;
+
+  if (ps.x != 0.0 && ps.y != 0.0) {
+    gfxFloat k = PR_MIN((aMidPoint.x - aP0.x) / ps.x,
+                        (aMidPoint.y - aP1.y) / ps.y);
+    aP1 = aP0 + ps * k;
+  }
+}
+
+void
+nsCSSBorderRenderer::DoSideClipSubPath(PRUint8 aSide)
+{
+  // 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];
+
+#define IS_DASHED_OR_DOTTED(_s)  ((_s) == NS_STYLE_BORDER_STYLE_DASHED || (_s) == NS_STYLE_BORDER_STYLE_DOTTED)
+  PRBool isDashed      = IS_DASHED_OR_DOTTED(mBorderStyles[aSide]);
+  PRBool startIsDashed = IS_DASHED_OR_DOTTED(mBorderStyles[PREV_SIDE(aSide)]);
+  PRBool endIsDashed   = IS_DASHED_OR_DOTTED(mBorderStyles[NEXT_SIDE(aSide)]);
+#undef IS_DASHED_OR_DOTTED
+
+  SideClipType startType = SIDE_CLIP_TRAPEZOID;
+  SideClipType endType = SIDE_CLIP_TRAPEZOID;
+
+  if (!IsZeroSize(mBorderRadii[aSide]))
+    startType = SIDE_CLIP_TRAPEZOID_FULL;
+  else if (startIsDashed && isDashed)
+    startType = SIDE_CLIP_RECTANGLE;
+
+  if (!IsZeroSize(mBorderRadii[NEXT_SIDE(aSide)]))
+    endType = SIDE_CLIP_TRAPEZOID_FULL;
+  else if (endIsDashed && isDashed)
+    endType = SIDE_CLIP_RECTANGLE;
+
+  gfxPoint midPoint = mInnerRect.pos + mInnerRect.size / 2.0;
+
+  start[0] = mOuterRect.Corner(aSide);
+  start[1] = mInnerRect.Corner(aSide);
+
+  end[0] = mOuterRect.Corner(NEXT_SIDE(aSide));
+  end[1] = mInnerRect.Corner(NEXT_SIDE(aSide));
+
+  if (startType == SIDE_CLIP_TRAPEZOID_FULL) {
+    MaybeMoveToMidPoint(start[0], start[1], midPoint);
+  } else if (startType == SIDE_CLIP_RECTANGLE) {
+    if (aSide == NS_SIDE_TOP || aSide == NS_SIDE_BOTTOM)
+      start[1] = gfxPoint(mOuterRect.Corner(aSide).x, mInnerRect.Corner(aSide).y);
+    else
+      start[1] = gfxPoint(mInnerRect.Corner(aSide).x, mOuterRect.Corner(aSide).y);
+  }
+
+  if (endType == SIDE_CLIP_TRAPEZOID_FULL) {
+    MaybeMoveToMidPoint(end[0], end[1], midPoint);
+  } else if (endType == SIDE_CLIP_RECTANGLE) {
+    if (aSide == NS_SIDE_TOP || aSide == NS_SIDE_BOTTOM)
+      end[0] = gfxPoint(mInnerRect.Corner(NEXT_SIDE(aSide)).x, mOuterRect.Corner(NEXT_SIDE(aSide)).y);
+    else
+      end[0] = gfxPoint(mOuterRect.Corner(NEXT_SIDE(aSide)).x, mInnerRect.Corner(NEXT_SIDE(aSide)).y);
+  }
+
+  mContext->MoveTo(start[0]);
+  mContext->LineTo(end[0]);
+  mContext->LineTo(end[1]);
+  mContext->LineTo(start[1]);
+  mContext->ClosePath();
+}
+
+void
+nsCSSBorderRenderer::FillSolidBorder(const gfxRect& aOuterRect,
+                                     const gfxRect& aInnerRect,
+                                     const gfxCornerSizes& aBorderRadii,
+                                     const gfxFloat *aBorderSizes,
+                                     PRIntn aSides,
+                                     const gfxRGBA& aColor)
+{
+  mContext->SetColor(aColor);
+
+  mContext->NewPath();
+
+  // If there is no border radius, and all the border sizes are the
+  // same, stroke a rectangle instead of calling Fill.
+  if (AllCornersZeroSize(aBorderRadii) &&
+      CheckFourFloatsEqual(aBorderSizes, aBorderSizes[0]))
+  {
+    if (aSides == SIDE_BITS_ALL) {
+      gfxRect r(aOuterRect);
+      r.Inset(aBorderSizes[0] / 2.0);
+
+      mContext->SetLineWidth(aBorderSizes[0]);
+
+      mContext->Rectangle(r);
+      mContext->Stroke();
+
+      return;
+    }
+
+    if (aBorderSizes[0] == 1.0 && aColor.a == 1.0) {
+      if (aSides == (SIDE_BIT_TOP | SIDE_BIT_LEFT)) {
+          mContext->SetLineWidth(1.0);
+
+          gfxRect r(aOuterRect);
+          r.Inset(0.5, 0.0, 0.0, 0.5);
+
+          mContext->MoveTo(r.BottomLeft());
+          mContext->LineTo(r.TopLeft());
+          mContext->LineTo(r.TopRight());
+          mContext->Stroke();
+          return;
+        }
+
+      if (aSides == (SIDE_BIT_BOTTOM | SIDE_BIT_RIGHT)) {
+        mContext->SetLineWidth(1.0);
+
+        gfxRect r(aOuterRect);
+        r.Inset(0.0, 0.5, 0.5, 0.0);
+
+        mContext->MoveTo(r.BottomLeft());
+        mContext->LineTo(r.BottomRight());
+        mContext->LineTo(r.TopRight());
+        mContext->Stroke();
+        return;
+      }
+    }
+  }
+
+  // we weren't able to render using stroke; do paths and fill.
+  gfxCornerSizes innerRadii;
+  ComputeInnerRadii(aBorderRadii, aBorderSizes, &innerRadii);
+
+  // do the outer border
+  mContext->RoundedRectangle(aOuterRect, aBorderRadii, PR_TRUE);
+
+  // then do the inner border CCW
+  mContext->RoundedRectangle(aInnerRect, innerRadii, PR_FALSE);
+
+  mContext->Fill();
+}
+
+gfxRGBA
+MakeBorderColor(const gfxRGBA& aColor, const gfxRGBA& aBackgroundColor, BorderColorStyle aBorderColorStyle)
+{
+  nscolor colors[2];
+  int k = 0;
+
+  switch (aBorderColorStyle) {
+    case BorderColorStyleNone:
+      return gfxRGBA(0.0, 0.0, 0.0, 0.0);
+
+    case BorderColorStyleLight:
+      k = 1;
+      /* fall through */
+    case BorderColorStyleDark:
+      NS_GetSpecial3DColors(colors, aBackgroundColor.Packed(), aColor.Packed());
+      return gfxRGBA(colors[k]);
+
+    case BorderColorStyleSolid:
+    default:
+      return aColor;
+  }
+}
+
+gfxRGBA
+ComputeColorForLine(PRUint32 aLineIndex,
+                    const BorderColorStyle* aBorderColorStyle,
+                    PRUint32 aBorderColorStyleCount,
+                    nscolor aBorderColor,
+                    nscolor aBackgroundColor)
+{
+  NS_ASSERTION(aLineIndex < aBorderColorStyleCount, "Invalid lineIndex given");
+
+  return MakeBorderColor(gfxRGBA(aBorderColor), gfxRGBA(aBackgroundColor), aBorderColorStyle[aLineIndex]);
+}
+
+gfxRGBA
+ComputeCompositeColorForLine(PRUint32 aLineIndex,
+                             const nsBorderColors* aBorderColors)
+{
+  while (aLineIndex-- && aBorderColors->mNext)
+    aBorderColors = aBorderColors->mNext;
+
+  if (aBorderColors->mTransparent)
+    return gfxRGBA(0.0, 0.0, 0.0, 0.0);
+
+  return gfxRGBA(aBorderColors->mColor);
+}
+
+void
+nsCSSBorderRenderer::DrawBorderSidesCompositeColors(PRIntn aSides, const nsBorderColors *aCompositeColors)
+{
+  gfxCornerSizes radii = mBorderRadii;
+
+  // the generic composite colors path; each border is 1px in size
+  gfxRect soRect = mOuterRect;
+  gfxRect siRect;
+  gfxFloat maxBorderWidth = 0;
+  NS_FOR_CSS_SIDES (i) {
+    maxBorderWidth = PR_MAX(maxBorderWidth, mBorderWidths[i]);
+  }
+
+  gfxFloat fakeBorderSizes[4];
+
+  gfxRGBA lineColor;
+  gfxPoint tl, br;
+
+  gfxPoint itl = mInnerRect.TopLeft();
+  gfxPoint ibr = mInnerRect.BottomRight();
+
+  for (PRUint32 i = 0; i < PRUint32(maxBorderWidth); i++) {
+    lineColor = ComputeCompositeColorForLine(i, aCompositeColors);
+
+    siRect = soRect;
+    siRect.Inset(1.0, 1.0, 1.0, 1.0);
+
+    // now cap the rects to the real mInnerRect
+    tl = siRect.TopLeft();
+    br = siRect.BottomRight();
+
+    tl.x = PR_MIN(tl.x, itl.x);
+    tl.y = PR_MIN(tl.y, itl.y);
+
+    br.x = PR_MAX(br.x, ibr.x);
+    br.y = PR_MAX(br.y, ibr.y);
+
+    siRect.pos = tl;
+    siRect.size.width = br.x - tl.x;
+    siRect.size.height = br.y - tl.y;
+
+    fakeBorderSizes[NS_SIDE_TOP] = siRect.TopLeft().y - soRect.TopLeft().y;
+    fakeBorderSizes[NS_SIDE_RIGHT] = soRect.TopRight().x - siRect.TopRight().x;
+    fakeBorderSizes[NS_SIDE_BOTTOM] = soRect.BottomRight().y - siRect.BottomRight().y;
+    fakeBorderSizes[NS_SIDE_LEFT] = siRect.BottomLeft().x - soRect.BottomLeft().x;
+
+    FillSolidBorder(soRect, siRect, radii, fakeBorderSizes, aSides, lineColor);
+
+    soRect = siRect;
+
+    ComputeInnerRadii(radii, fakeBorderSizes, &radii);
+  }
+}
+
+void
+nsCSSBorderRenderer::DrawBorderSides(PRIntn aSides)
+{
+  if (aSides == 0 || (aSides & ~SIDE_BITS_ALL) != 0) {
+    NS_WARNING("DrawBorderSides: invalid sides!");
+    return;
+  }
+
+  PRUint8 borderRenderStyle;
+  nscolor borderRenderColor;
+  const nsBorderColors *compositeColors = nsnull;
+
+  PRUint32 borderColorStyleCount = 0;
+  BorderColorStyle borderColorStyleTopLeft[3], borderColorStyleBottomRight[3];
+  BorderColorStyle *borderColorStyle = nsnull;
+
+  NS_FOR_CSS_SIDES (i) {
+    if ((aSides & (1 << i)) == 0)
+      continue;
+    borderRenderStyle = mBorderStyles[i];
+    borderRenderColor = mBorderColors[i];
+    compositeColors = mCompositeColors[i];
+    break;
+  }
+
+  if (borderRenderStyle == NS_STYLE_BORDER_STYLE_NONE ||
+      borderRenderStyle == NS_STYLE_BORDER_STYLE_HIDDEN)
+    return;
+
+  // -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.  Just
+  // hand off to another function to do all that.
+  if (compositeColors) {
+    DrawBorderSidesCompositeColors(aSides, compositeColors);
+    return;
+  }
+
+  // We're not doing compositeColors, so we can calculate the
+  // borderColorStyle based on the specified style.  The
+  // borderColorStyle array goes from the outer to the inner style.
+  //
+  // 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 (CheckFourFloatsEqual(mBorderWidths, 1.0)) {
+    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;
+      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:
+      NS_NOTREACHED("Unhandled border style!!");
+      break;
+  }
+
+  // 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_ASSERTION(borderColorStyleCount > 0 && borderColorStyleCount < 4,
+               "Non-border-colors case with borderColorStyleCount < 1 or > 3; what happened?");
+
+  // The caller should never give us anything with a mix
+  // of TL/BR if the border style would require a
+  // TL/BR split.
+  if (aSides & (SIDE_BIT_BOTTOM | SIDE_BIT_RIGHT))
+    borderColorStyle = borderColorStyleBottomRight;
+  else
+    borderColorStyle = borderColorStyleTopLeft;
+
+  // Distribute the border across the available space.
+  gfxFloat borderWidths[3][4];
+
+  if (borderColorStyleCount == 1) {
+    NS_FOR_CSS_SIDES (i) {
+      borderWidths[0][i] = mBorderWidths[i];
+    }
+  } else if (borderColorStyleCount == 2) {
+    // with 2 color styles, any extra pixel goes to the outside
+    NS_FOR_CSS_SIDES (i) {
+      borderWidths[0][i] = PRInt32(mBorderWidths[i]) / 2 + PRInt32(mBorderWidths[i]) % 2;
+      borderWidths[1][i] = PRInt32(mBorderWidths[i]) / 2;
+    }
+  } else if (borderColorStyleCount == 3) {
+    // with 3 color styles, any extra pixel (or lack of extra pixel)
+    // goes to the middle
+    NS_FOR_CSS_SIDES (i) {
+      if (mBorderWidths[i] == 1.0) {
+        borderWidths[0][i] = 1.0;
+        borderWidths[1][i] = borderWidths[2][i] = 0.0;
+      } else {
+        PRInt32 rest = PRInt32(mBorderWidths[i]) % 3;
+        borderWidths[0][i] = borderWidths[2][i] = borderWidths[1][i] = (PRInt32(mBorderWidths[i]) - rest) / 3;
+
+        if (rest == 1) {
+          borderWidths[1][i] += 1.0;
+        } else if (rest == 2) {
+          borderWidths[0][i] += 1.0;
+          borderWidths[2][i] += 1.0;
+        }
+      }
+    }
+  }
+
+  // make a copy that we can modify
+  gfxCornerSizes radii = mBorderRadii;
+
+  gfxRect soRect(mOuterRect);
+  gfxRect siRect(mOuterRect);
+
+  for (unsigned int i = 0; i < borderColorStyleCount; i++) {
+    // walk siRect inwards at the start of the loop to get the
+    // correct inner rect.
+    siRect.Inset(borderWidths[i]);
+
+    if (borderColorStyle[i] != BorderColorStyleNone) {
+      gfxRGBA color = ComputeColorForLine(i,
+                                          borderColorStyle, borderColorStyleCount,
+                                          borderRenderColor, mBackgroundColor);
+
+      FillSolidBorder(soRect, siRect, radii, borderWidths[i], aSides, color);
+    }
+
+    ComputeInnerRadii(radii, borderWidths[i], &radii);
+
+    // And now soRect is the same as siRect, for the next line in.
+    soRect = siRect;
+  }
+}
+
+void
+nsCSSBorderRenderer::DrawDashedSide(PRUint8 aSide)
+{
+  gfxFloat dashWidth;
+  gfxFloat dash[2];
+
+  PRUint8 style = mBorderStyles[aSide];
+  gfxFloat borderWidth = mBorderWidths[aSide];
+  nscolor borderColor = mBorderColors[aSide];
+
+  if (borderWidth == 0.0)
+    return;
+
+  if (style == NS_STYLE_BORDER_STYLE_NONE ||
+      style == NS_STYLE_BORDER_STYLE_HIDDEN)
+    return;
+
+  if (style == NS_STYLE_BORDER_STYLE_DASHED) {
+    dashWidth = gfxFloat(borderWidth * DOT_LENGTH * DASH_LENGTH);
+
+    dash[0] = dashWidth;
+    dash[1] = dashWidth;
+
+    mContext->SetLineCap(gfxContext::LINE_CAP_BUTT);
+  } else if (style == NS_STYLE_BORDER_STYLE_DOTTED) {
+    dashWidth = gfxFloat(borderWidth * DOT_LENGTH);
+
+    if (borderWidth > 2.0) {
+      dash[0] = 0.0;
+      dash[1] = dashWidth * 2.0;
+
+      mContext->SetLineCap(gfxContext::LINE_CAP_ROUND);
+    } else {
+      dash[0] = dashWidth;
+      dash[1] = dashWidth;
+    }
+  } else {
+    SF("DrawDashedSide: style: %d!!\n", style);
+    NS_ERROR("DrawDashedSide called with style other than DASHED or DOTTED; someone's not playing nice");
+    return;
+  }
+
+  SF("dash: %f %f\n", dash[0], dash[1]);
+
+  mContext->SetDash(dash, 2, 0.0);
+
+  gfxPoint start = mOuterRect.Corner(aSide);
+  gfxPoint end = mOuterRect.Corner(NEXT_SIDE(aSide));
+
+  if (aSide == NS_SIDE_TOP) {
+    start.x += mBorderCornerDimensions[C_TL].width;
+    end.x -= mBorderCornerDimensions[C_TR].width;
+
+    start.y += borderWidth / 2.0;
+    end.y += borderWidth / 2.0;
+  } else if (aSide == NS_SIDE_RIGHT) {
+    start.x -= borderWidth / 2.0;
+    end.x -= borderWidth / 2.0;
+
+    start.y += mBorderCornerDimensions[C_TR].height;
+    end.y -= mBorderCornerDimensions[C_BR].height;
+  } else if (aSide == NS_SIDE_BOTTOM) {
+    start.x -= mBorderCornerDimensions[C_BR].width;
+    end.x += mBorderCornerDimensions[C_BL].width;
+
+    start.y -= borderWidth / 2.0;
+    end.y -= borderWidth / 2.0;
+  } else if (aSide == NS_SIDE_LEFT) {
+    start.x += borderWidth / 2.0;
+    end.x += borderWidth / 2.0;
+
+    start.y -= mBorderCornerDimensions[C_BL].height;
+    end.y += mBorderCornerDimensions[C_TL].height;
+  }
+
+  mContext->NewPath();
+  mContext->MoveTo(start);
+  mContext->LineTo(end);
+  mContext->SetLineWidth(borderWidth);
+  mContext->SetColor(gfxRGBA(borderColor));
+  //mContext->SetColor(gfxRGBA(1.0, 0.0, 0.0, 1.0));
+  mContext->Stroke();
+}
+
+void
+nsCSSBorderRenderer::DrawBorders()
+{
+  PRBool forceSeparateCorners = PR_FALSE;
+
+  // Examine the border style to figure out if we can draw it in one
+  // go or not.
+  PRBool allBordersSame = AreBorderSideFinalStylesSame(SIDE_BITS_ALL);
+  if (allBordersSame &&
+      mCompositeColors[0] == NULL &&
+      (mBorderStyles[0] == NS_STYLE_BORDER_STYLE_NONE ||
+       mBorderStyles[0] == NS_STYLE_BORDER_STYLE_HIDDEN ||
+       mBorderColors[0] == NS_RGBA(0,0,0,0)))
+  {
+    // All borders are the same style, and the style is either none or hidden, or the color
+    // is transparent.
+    // This doesn't check if the composite colors happen to be all transparent, but that should
+    // happen very rarely in practice.
+    return;
+  }
+
+  // If we have composite colors -and- border radius,
+  // then use separate corners so we get OPERATOR_ADD for the corners.
+  // Otherwise, we'll get artifacts as we draw stacked 1px-wide curves.
+  if (allBordersSame && mCompositeColors[0] != nsnull && !AllCornersZeroSize(mBorderRadii))
+    forceSeparateCorners = PR_TRUE;
+
+  // round mOuterRect and mInnerRect; they're already an integer
+  // number of pixels apart and should stay that way after
+  // rounding.
+  mOuterRect.Round();
+  mInnerRect.Round();
+
+  S(" mOuterRect: "), S(mOuterRect), SN();
+  S(" mInnerRect: "), S(mInnerRect), SN();
+  SF(" mBorderColors: 0x%08x 0x%08x 0x%08x 0x%08x\n", mBorderColors[0], mBorderColors[1], mBorderColors[2], mBorderColors[3]);
+
+  // if conditioning the outside rect failed, then bail -- the outside
+  // rect is supposed to enclose the entire border
+  mOuterRect.Condition();
+  if (mOuterRect.IsEmpty())
+    return;
+
+  mInnerRect.Condition();
+
+  PRIntn dashedSides = 0;
+  NS_FOR_CSS_SIDES(i) {
+    PRUint8 style = mBorderStyles[i];
+    if (style == NS_STYLE_BORDER_STYLE_DASHED ||
+        style == NS_STYLE_BORDER_STYLE_DOTTED)
+    {
+      // pretend that all borders aren't the same; we need to draw
+      // things separately for dashed/dotting
+      allBordersSame = PR_FALSE;
+      dashedSides |= (1 << i);
+    }
+
+    // just bail out entirely if RULES_MARKER
+    // got through (see bug 379419).
+    if (style & NS_STYLE_BORDER_STYLE_RULES_MARKER)
+      return;
+  }
+
+  SF(" allBordersSame: %d dashedSides: 0x%02x\n", allBordersSame, dashedSides);
+
+  // 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 = mContext->CurrentMatrix();
+  if (!mat.HasNonTranslation()) {
+    mat.x0 = floor(mat.x0 + 0.5);
+    mat.y0 = floor(mat.y0 + 0.5);
+    mContext->SetMatrix(mat);
+  }
+
+  // clip to mOuterRect to define the boundaries of our rendering
+  mContext->NewPath();
+  mContext->Rectangle(mOuterRect);
+
+  if (mGapRect) {
+    // draw the rectangle backwards, so that we get it
+    // clipped out via the winding rule
+    mContext->MoveTo(mGapRect->pos);
+    mContext->LineTo(mGapRect->pos + gfxSize(0.0, mGapRect->size.height));
+    mContext->LineTo(mGapRect->pos + mGapRect->size);
+    mContext->LineTo(mGapRect->pos + gfxSize(mGapRect->size.width, 0.0));
+    mContext->ClosePath();
+  }
+
+  mContext->Clip();
+
+  if (allBordersSame && !forceSeparateCorners) {
+    /* Draw everything in one go */
+    DrawBorderSides(SIDE_BITS_ALL);
+    SN("---------------- (1)");
+  } else {
+    /* We have more than one pass to go.  Draw the corners separately from the sides. */
+
+    // First, the corners
+    for (int corner = 0; corner < gfxCorner::NUM_CORNERS; corner++) {
+      const PRIntn sides[2] = { corner, PREV_SIDE(corner) };
+      PRIntn sideBits = (1 << sides[0]) | (1 << sides[1]);
+
+      mContext->Save();
+
+      // clip to the corner
+      mContext->NewPath();
+      DoCornerClipSubPath(corner);
+      mContext->Clip();
+
+      if (dashedSides == 0 &&
+          mCompositeColors[sides[0]] == NULL &&
+          mCompositeColors[sides[1]] == NULL &&
+          AreBorderSideFinalStylesSame(sideBits))
+      {
+        // we don't need a group for this corner, the sides are the same.
+        DrawBorderSides(sideBits);
+      } else {
+        // Sides are different.  We need to draw using OPERATOR_ADD to
+        // get correct color blending behaviour at the seam.  We need
+        // to do it in an offscreen surface to ensure that we're
+        // always compositing on transparent black.  If the colors
+        // don't have transparency and the current destination surface
+        // has an alpha channel, we could just clear the region and
+        // avoid the temporary, but that situation doesn't happen all
+        // that often in practice (we double buffer to no-alpha
+        // surfaces).
+
+        mContext->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
+        mContext->SetOperator(gfxContext::OPERATOR_ADD);
+
+        for (int cornerSide = 0; cornerSide < 2; cornerSide++) {
+          PRUint8 side = sides[cornerSide];
+          PRUint8 style = mBorderStyles[side];
+
+          SF("corner: %d cornerSide: %d side: %d style: %d\n", corner, cornerSide, side, style);
+
+          mContext->Save();
+
+          mContext->NewPath();
+          DoSideClipSubPath(side);
+          mContext->Clip();
+
+          DrawBorderSides(1 << side);
+
+          mContext->Restore();
+        }
+
+        mContext->PopGroupToSource();
+        mContext->SetOperator(gfxContext::OPERATOR_OVER);
+        mContext->Paint();
+      }
+
+      mContext->Restore();
+
+      SN();
+    }
+
+    // We're done with the corners, now draw the sides.
+    NS_FOR_CSS_SIDES (side) {
+      mContext->Save();
+      mContext->NewPath();
+      DoSideClipWithoutCornersSubPath(side);
+      mContext->Clip();
+
+      if (dashedSides & (1 << side)) {
+        DrawDashedSide (side);
+        SN("---------------- (d)");
+      } else {
+        DrawBorderSides(1 << side);
+        SN("---------------- (*)");
+      }
+
+      mContext->Restore();
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/layout/base/nsCSSRenderingBorders.h
@@ -0,0 +1,250 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:cindent:ts=2:et:sw=2:
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * 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 ***** */
+
+#ifndef NS_CSS_RENDERING_BORDERS_H
+#define NS_CSS_RENDERING_BORDERS_H
+
+#include "nsColor.h"
+#include "nsStyleStruct.h"
+
+#include "gfxContext.h"
+
+// define this to enable a bunch of debug dump info
+#undef DEBUG_NEW_BORDERS
+
+//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)
+
+#define C_TL (gfxCorner::TOP_LEFT)
+#define C_TR (gfxCorner::TOP_RIGHT)
+#define C_BR (gfxCorner::BOTTOM_RIGHT)
+#define C_BL (gfxCorner::BOTTOM_LEFT)
+
+/*
+ * Helper class that handles border rendering.
+ *
+ * appUnitsPerPixel -- current value of AUPP
+ * destContext -- the gfxContext to which the border should be rendered
+ * outsideRect -- the rectangle on the outer edge of the border
+ * 
+ * For any parameter where an array of side values is passed in,
+ * they are in top, right, bottom, left order.
+ *
+ * borderStyles -- one border style enum per side
+ * borderWidths -- one border width per side
+ * borderRadii -- a gfxCornerSizes struct describing the w/h for each rounded corner.
+ *    If the corner doesn't have a border radius, 0,0 should be given for it.
+ * borderColors -- one nscolor per side
+ * compositeColors -- a pointer to an array of composite color structs, or NULL if none
+ *
+ * skipSides -- a bit mask specifying which sides, if any, to skip
+ * backgroundColor -- the background color of the element.
+ *    Used in calculating colors for 2-tone borders, such as inset and outset
+ * gapRect - a rectangle that should be clipped out to leave a gap in a border,
+ *    or nsnull if none.
+ */
+
+struct nsCSSBorderRenderer {
+  nsCSSBorderRenderer(PRInt32 aAppUnitsPerPixel,
+                      gfxContext* aDestContext,
+                      gfxRect& aOuterRect,
+                      const PRUint8* aBorderStyles,
+                      const gfxFloat* aBorderWidths,
+                      gfxCornerSizes& aBorderRadii,
+                      const nscolor* aBorderColors,
+                      nsBorderColors* const* aCompositeColors,
+                      PRIntn aSkipSides,
+                      nscolor aBackgroundColor,
+                      const gfxRect* aGapRect = nsnull);
+
+  // core app units per pixel
+  PRInt32 mAUPP;
+
+  // destination context
+  gfxContext* mContext;
+
+  // the rectangle of the outside and the inside of the border
+  gfxRect mOuterRect;
+  gfxRect mInnerRect;
+
+  // the style and size of the border
+  const PRUint8* mBorderStyles;
+  const gfxFloat* mBorderWidths;
+  gfxCornerSizes mBorderRadii;
+
+  // colors
+  const nscolor* mBorderColors;
+  nsBorderColors* const* mCompositeColors;
+
+  // misc -- which sides to skip, the background color, and whether we should
+  // leave a gap in the border (e.g. for a label)
+  PRIntn mSkipSides;
+  nscolor mBackgroundColor;
+  const gfxRect* mGapRect;
+
+  // calculated values
+  gfxCornerSizes mBorderCornerDimensions;
+
+  // For all the sides in the bitmask, would they be rendered
+  // in an identical color and style?
+  PRBool AreBorderSideFinalStylesSame(PRUint8 aSides);
+
+  //
+  // Path generation functions
+  //
+
+  // add the path for drawing the given corners to the context
+  void DoCornerClipSubPath(PRUint8 aCorner);
+  // add the path for drawing the given side without any adjacent corners to the context
+  void DoSideClipWithoutCornersSubPath(PRUint8 aSide);
+
+  // 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.
+  void DoSideClipSubPath(PRUint8 aSide);
+
+  // Given a set of sides to fill and a color, do so in the fastest way.
+  //
+  // Stroke tends to be faster for smaller borders because it doesn't go
+  // through the tessellator, which has initialization overhead.  If
+  // we're rendering all sides, we can use stroke at any thickness; we
+  // also do TL/BR pairs at 1px thickness using stroke.
+  //
+  // If we can't stroke, then if it's a TL/BR pair, we use the specific
+  // TL/BR paths.  Otherwise, we do the full path and fill.
+  //
+  // Calling code is expected to only set up a clip as necessary; no
+  // clip is needed if we can render the entire border in 1 or 2 passes.
+  void FillSolidBorder(const gfxRect& aOuterRect,
+                       const gfxRect& aInnerRect,
+                       const gfxCornerSizes& aBorderRadii,
+                       const gfxFloat *aBorderSizes,
+                       PRIntn aSides,
+                       const gfxRGBA& aColor);
+
+  //
+  // core rendering
+  //
+
+  // draw the border for the given sides, using the style of the first side
+  // present in the bitmask
+  void DrawBorderSides (PRIntn aSides);
+
+  // function used by the above to handle -moz-border-colors
+  void DrawBorderSidesCompositeColors(PRIntn aSides, const nsBorderColors *compositeColors);
+
+  // draw the given dashed side
+  void DrawDashedSide (PRUint8 aSide);
+
+  // draw the entire border
+  void DrawBorders ();
+};
+
+#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);
+}
+
+static inline void SX(gfxContext *ctx) {
+  gfxPoint p = ctx->CurrentPoint();
+  fprintf (stderr, "p: %f %f\n", p.x, p.y);
+  return;
+  ctx->MoveTo(p + gfxPoint(-2, -2)); ctx->LineTo(p + gfxPoint(2, 2));
+  ctx->MoveTo(p + gfxPoint(-2, 2)); ctx->LineTo(p + gfxPoint(2, -2));
+  ctx->MoveTo(p);
+}
+
+
+#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, ...) {}
+static inline void SX(gfxContext *ctx) {}
+#endif
+
+#endif /* NS_CSS_RENDERING_BORDERS_H */