Implement css3 border-image property. (Bug 378217) r=vlad,dbaron,robarnold
☠☠ backed out by 12d07c032ffc ☠ ☠
authorAndrew Smith <asmith15@littlesvr.ca>, Rob Arnold <tellrob@gmail.com>, L. David Baron <dbaron@dbaron.org>
Wed, 16 Jul 2008 22:18:38 -0700
changeset 15990 9b0b2391485c50da98e30be3f793063d41c95f00
parent 15989 ec061b745244bcb8c6bc47de241c053fd2030bf3
child 15991 12d07c032ffce59fae4c035fa600f744920e4baf
push idunknown
push userunknown
push dateunknown
reviewersvlad, dbaron, robarnold
bugs378217
milestone1.9.1a1pre
Implement css3 border-image property. (Bug 378217) r=vlad,dbaron,robarnold
content/html/content/src/nsGenericHTMLElement.cpp
content/html/document/src/nsImageDocument.cpp
dom/public/idl/css/nsIDOMCSS2Properties.idl
gfx/thebes/public/gfxContext.h
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
layout/base/nsDisplayList.cpp
layout/base/nsImageLoader.cpp
layout/base/nsImageLoader.h
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsStyleConsts.h
layout/forms/nsButtonFrameRenderer.cpp
layout/forms/nsFieldSetFrame.cpp
layout/forms/nsHTMLButtonControlFrame.cpp
layout/generic/nsAbsoluteContainingBlock.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsContainerFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsInlineFrame.cpp
layout/generic/nsPageContentFrame.cpp
layout/reftests/border-image/10x5multicolor.png
layout/reftests/border-image/3x3green-1DD813.png
layout/reftests/border-image/3x3multicolor.png
layout/reftests/border-image/3x3transparent.png
layout/reftests/border-image/4x4multicolor.png
layout/reftests/border-image/multicolor-image-1-ref.html
layout/reftests/border-image/multicolor-image-1.html
layout/reftests/border-image/multicolor-image-2-ref.html
layout/reftests/border-image/multicolor-image-2.html
layout/reftests/border-image/multicolor-image-3-ref.html
layout/reftests/border-image/multicolor-image-3.html
layout/reftests/border-image/reftest.list
layout/reftests/border-image/repeat-image-1-ref.html
layout/reftests/border-image/repeat-image-1.html
layout/reftests/border-image/solid-image-1-ref.html
layout/reftests/border-image/solid-image-1.html
layout/reftests/border-image/solid-image-2-ref.html
layout/reftests/border-image/solid-image-2.html
layout/reftests/border-image/transparent-image-1-ref.html
layout/reftests/border-image/transparent-image-1.html
layout/reftests/pixel-rounding/border-image-width-0.html
layout/reftests/pixel-rounding/border-image-width-10.html
layout/reftests/pixel-rounding/border-image-width-4.html
layout/reftests/pixel-rounding/border-image-width-9.html
layout/reftests/pixel-rounding/random-10x10.png
layout/reftests/pixel-rounding/reftest.list
layout/reftests/reftest.list
layout/style/Makefile.in
layout/style/nsCSSDataBlock.cpp
layout/style/nsCSSDeclaration.cpp
layout/style/nsCSSParser.cpp
layout/style/nsCSSPropList.h
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.h
layout/style/nsCSSStruct.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleContext.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/nsStyleStructInlines.h
layout/style/test/property_database.js
layout/style/test/test_value_storage.html
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableFrame.cpp
layout/xul/base/src/nsBox.cpp
layout/xul/base/src/nsBoxObject.cpp
layout/xul/base/src/nsGroupBoxFrame.cpp
layout/xul/base/src/nsListBoxBodyFrame.cpp
layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -578,18 +578,18 @@ nsGenericHTMLElement::GetOffsetRect(nsRe
       }
     }
   }
 
   // Subtract the parent border unless it uses border-box sizing.
   if (parent &&
       parent->GetStylePosition()->mBoxSizing != NS_STYLE_BOX_SIZING_BORDER) {
     const nsStyleBorder* border = parent->GetStyleBorder();
-    origin.x -= border->GetBorderWidth(NS_SIDE_LEFT);
-    origin.y -= border->GetBorderWidth(NS_SIDE_TOP);
+    origin.x -= border->GetActualBorderWidth(NS_SIDE_LEFT);
+    origin.y -= border->GetActualBorderWidth(NS_SIDE_TOP);
   }
 
   // XXX We should really consider subtracting out padding for
   // content-box sizing, but we should see what IE does....
 
   // Convert to pixels.
   aRect.x = nsPresContext::AppUnitsToIntCSSPixels(origin.x);
   aRect.y = nsPresContext::AppUnitsToIntCSSPixels(origin.y);
--- a/content/html/document/src/nsImageDocument.cpp
+++ b/content/html/document/src/nsImageDocument.cpp
@@ -661,17 +661,17 @@ nsImageDocument::CheckOverflowing(PRBool
     }
 
     nsRefPtr<nsStyleContext> styleContext =
       context->StyleSet()->ResolveStyleFor(content, nsnull);
 
     nsMargin m;
     if (styleContext->GetStyleMargin()->GetMargin(m))
       visibleArea.Deflate(m);
-    m = styleContext->GetStyleBorder()->GetBorder();
+    m = styleContext->GetStyleBorder()->GetActualBorder();
     visibleArea.Deflate(m);
     if (styleContext->GetStylePadding()->GetPadding(m))
       visibleArea.Deflate(m);
 
     float zoomLevel = GetZoomLevel();
     mVisibleWidth = PRInt32(zoomLevel *
       nsPresContext::AppUnitsToIntCSSPixels(visibleArea.width));
     mVisibleHeight = PRInt32(zoomLevel *
--- a/dom/public/idl/css/nsIDOMCSS2Properties.idl
+++ b/dom/public/idl/css/nsIDOMCSS2Properties.idl
@@ -401,17 +401,17 @@ interface nsIDOMCSS2Properties : nsISupp
 
            attribute DOMString        wordSpacing;
                                         // raises(DOMException) on setting
 
            attribute DOMString        zIndex;
                                         // raises(DOMException) on setting
 };
 
-[scriptable, uuid(816581b0-3d89-11dd-ae16-0800200c9a66)]
+[scriptable, uuid(f1781ae4-00e6-4751-8698-2925f925fd76)]
 interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties
 {
            /* Non-DOM 2 extensions */
 
            /* Mozilla extension CSS properties */
            attribute DOMString        MozAppearance;
                                         // raises(DOMException) on setting
 
@@ -591,9 +591,13 @@ interface nsIDOMNSCSS2Properties : nsIDO
            attribute DOMString        MozBorderStartWidth;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozStackSizing;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozBoxShadow;
                                         // raises(DOMException) on setting
+
+           attribute DOMString        MozBorderImage;
+                                        // raises(DOMException) on setting
+
 };
--- a/gfx/thebes/public/gfxContext.h
+++ b/gfx/thebes/public/gfxContext.h
@@ -332,17 +332,18 @@ public:
      * and this call is identical to SetDeviceColor().
      */
     void SetColor(const gfxRGBA& c);
 
     /**
      * Uses a surface for drawing. This is a shorthand for creating a
      * pattern and setting it.
      *
-     * @param offset ?
+     * @param offset from the source surface, to use only part of it.
+     *        May need to make it negative.
      */
     void SetSource(gfxASurface *surface, const gfxPoint& offset = gfxPoint(0.0, 0.0));
 
     /**
      * Uses a pattern for drawing.
      */
     void SetPattern(gfxPattern *pattern);
 
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -21,16 +21,17 @@
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Mats Palmgren <mats.palmgren@bredband.net>
  *   Takeshi Ichimaru <ayakawa.m@gmail.com>
  *   Masayuki Nakano <masayuki@d-toybox.com>
  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
  *   Michael Ventnor <m.ventnor@gmail.com>
+ *   Rob Arnold <robarnold@mozilla.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
@@ -67,18 +68,21 @@
 #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 "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
@@ -2690,28 +2694,34 @@ nsCSSRendering::PaintBorder(nsPresContex
   // may be different!  Always use |aStyleContext|!
   const nsStyleDisplay* displayData = aStyleContext->GetStyleDisplay();
   if (displayData->mAppearance) {
     nsITheme *theme = aPresContext->GetTheme();
     if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame, displayData->mAppearance))
       return; // Let the theme handle it.
   }
 
+  if (aBorderStyle.IsBorderImageLoaded()) {
+    DrawBorderImage(aPresContext, aRenderingContext, aForFrame,
+                    aBorderArea, aBorderStyle, aHardBorderSize);
+    return;
+  }
+  
   // Get our style context's color struct.
   const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
 
   // in NavQuirks mode we want to use the parent's context as a starting point
   // for determining the background color
   const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground
     (aStyleContext, compatMode == eCompatibility_NavQuirks ? PR_TRUE : PR_FALSE);
 
   if (aHardBorderSize > 0) {
     border.SizeTo(aHardBorderSize, aHardBorderSize, aHardBorderSize, aHardBorderSize);
   } else {
-    border = aBorderStyle.GetBorder();
+    border = aBorderStyle.GetComputedBorder();
   }
 
   if ((0 == border.left) && (0 == border.right) &&
       (0 == border.top) && (0 == border.bottom)) {
     // Empty border area
     return;
   }
 
@@ -3334,17 +3344,17 @@ nsCSSRendering::PaintBoxShadow(nsPresCon
                                const nsPoint& aForFramePt)
 {
   nsMargin      borderValues;
   gfxFloat      borderRadii[4];
   PRIntn        sidesToSkip;
   nsRect        frameRect;
 
   const nsStyleBorder* styleBorder = aForFrame->GetStyleBorder();
-  borderValues = styleBorder->GetBorder();
+  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);
@@ -3721,30 +3731,23 @@ nsCSSRendering::PaintBackgroundWithSC(ns
   // Based on the repeat setting, compute how many tiles we should
   // lay down for each axis. The value computed is the maximum based
   // on the dirty rect before accounting for the background-position.
   nscoord tileWidth = imageSize.width;
   nscoord tileHeight = imageSize.height;
   PRBool  needBackgroundColor = !(aColor.mBackgroundFlags &
                                   NS_STYLE_BG_COLOR_TRANSPARENT);
   PRIntn  repeat = aColor.mBackgroundRepeat;
-  nscoord xDistance, yDistance;
 
   switch (repeat) {
     case NS_STYLE_BG_REPEAT_X:
-      xDistance = dirtyRect.width;
-      yDistance = tileHeight;
       break;
     case NS_STYLE_BG_REPEAT_Y:
-      xDistance = tileWidth;
-      yDistance = dirtyRect.height;
       break;
     case NS_STYLE_BG_REPEAT_XY:
-      xDistance = dirtyRect.width;
-      yDistance = dirtyRect.height;
       if (needBackgroundColor) {
         // If the image is completely opaque, we do not need to paint the
         // background color
         nsCOMPtr<gfxIImageFrame> gfxImgFrame;
         image->GetCurrentFrame(getter_AddRefs(gfxImgFrame));
         if (gfxImgFrame) {
           gfxImgFrame->GetNeedsBackground(&needBackgroundColor);
 
@@ -3759,18 +3762,16 @@ nsCSSRendering::PaintBackgroundWithSC(ns
             needBackgroundColor = PR_TRUE;
           }
         }
       }
       break;
     case NS_STYLE_BG_REPEAT_OFF:
     default:
       NS_ASSERTION(repeat == NS_STYLE_BG_REPEAT_OFF, "unknown background-repeat value");
-      xDistance = tileWidth;
-      yDistance = tileHeight;
       break;
   }
 
   // The background color is rendered over the 'background-clip' area
   if (needBackgroundColor) {
     PaintBackgroundColor(aPresContext, aRenderingContext, aForFrame, bgClipArea,
                          aColor, aBorder, aPadding, canDrawBackgroundColor);
   }
@@ -3841,17 +3842,17 @@ nsCSSRendering::PaintBackgroundWithSC(ns
         "|:viewport| pseudo-element in |html.css|.");
 
       // temporary null check -- see bug 97226
       if (firstRootElementFrame) {
         firstRootElementFrameArea = firstRootElementFrame->GetRect();
 
         // Take the border out of the frame's rect
         const nsStyleBorder* borderStyle = firstRootElementFrame->GetStyleBorder();
-        firstRootElementFrameArea.Deflate(borderStyle->GetBorder());
+        firstRootElementFrameArea.Deflate(borderStyle->GetActualBorder());
 
         // Get the anchor point
         ComputeBackgroundAnchorPoint(aColor, firstRootElementFrameArea +
             aBorderArea.TopLeft(), bgClipArea, tileWidth, tileHeight, anchor);
       } else {
         ComputeBackgroundAnchorPoint(aColor, bgOriginArea, bgClipArea, tileWidth, tileHeight, anchor);
       }
     } else {
@@ -3881,17 +3882,17 @@ nsCSSRendering::PaintBackgroundWithSC(ns
   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];
-    ComputePixelRadii(borderRadii, bgClipArea, aBorder.GetBorder(),
+    ComputePixelRadii(borderRadii, bgClipArea, aBorder.GetActualBorder(),
                       aForFrame ? aForFrame->GetSkipSides() : 0,
                       appUnitsPerPixel, radii);
 
     gfxRect oRect(RectToGfxRect(bgClipArea, appUnitsPerPixel));
     oRect.Round();
     oRect.Condition();
 
     ctx->NewPath();
@@ -4057,16 +4058,411 @@ nsCSSRendering::PaintBackgroundWithSC(ns
     }
   }
 
   ctx->Restore();
 
 }
 
 void
+nsCSSRendering::DrawBorderImage(nsPresContext* aPresContext,
+                                nsIRenderingContext& aRenderingContext,
+                                nsIFrame* aForFrame,
+                                const nsRect& aBorderArea,
+                                const nsStyleBorder& aBorderStyle,
+                                nscoord aHardBorderSize)
+{
+    float percent;
+    nsStyleCoord borderImageSplit[4];
+    PRInt32 borderImageSplitInt[4];
+    nsMargin border;
+    gfxFloat borderTop, borderRight, borderBottom, borderLeft;
+    gfxFloat borderImageSplitGfx[4];
+
+    if (aHardBorderSize > 0) {
+      border.SizeTo(aHardBorderSize, aHardBorderSize, aHardBorderSize, aHardBorderSize);
+    } else {
+      border = aBorderStyle.GetActualBorder();
+    }
+
+    if ((0 == border.left) && (0 == border.right) &&
+        (0 == border.top) && (0 == border.bottom)) {
+      // Empty border area
+      return;
+    }
+
+    borderImageSplit[NS_SIDE_TOP] = aBorderStyle.mBorderImageSplit.GetTop();
+    borderImageSplit[NS_SIDE_RIGHT] = aBorderStyle.mBorderImageSplit.GetRight();
+    borderImageSplit[NS_SIDE_BOTTOM] = aBorderStyle.mBorderImageSplit.GetBottom();
+    borderImageSplit[NS_SIDE_LEFT] = aBorderStyle.mBorderImageSplit.GetLeft();
+
+    imgIRequest *req = aPresContext->LoadBorderImage(aBorderStyle.GetBorderImage(), aForFrame);
+
+    nsCOMPtr<imgIContainer> image;
+    req->GetImage(getter_AddRefs(image));
+
+    nsSize imageSize;
+    image->GetWidth(&imageSize.width);
+    image->GetHeight(&imageSize.height);
+    imageSize.width = nsPresContext::CSSPixelsToAppUnits(imageSize.width);
+    imageSize.height = nsPresContext::CSSPixelsToAppUnits(imageSize.height);
+
+    // convert percentage values
+    NS_FOR_CSS_SIDES(side) {
+      borderImageSplitInt[side] = 0;
+      switch (borderImageSplit[side].GetUnit()) {
+        case eStyleUnit_Percent:
+          percent = borderImageSplit[side].GetPercentValue();
+          if (side == NS_SIDE_TOP || side == NS_SIDE_BOTTOM)
+            borderImageSplitInt[side] = (nscoord)(percent * imageSize.height);
+          else
+            borderImageSplitInt[side] = (nscoord)(percent * imageSize.width);
+          break;
+        case eStyleUnit_Integer:
+          borderImageSplitInt[side] = nsPresContext::CSSPixelsToAppUnits(borderImageSplit[side].
+                                          GetIntValue());
+          break;
+        case eStyleUnit_Factor:
+          borderImageSplitInt[side] = nsPresContext::CSSPixelsToAppUnits(borderImageSplit[side].GetFactorValue());
+          break;
+        default:
+          break;
+      }
+    }
+
+    gfxContext *thebesCtx = aRenderingContext.ThebesContext();
+    nsCOMPtr<nsIDeviceContext> dc;
+    aRenderingContext.GetDeviceContext(*getter_AddRefs(dc));
+
+    NS_FOR_CSS_SIDES(side) {
+      borderImageSplitGfx[side] = nsPresContext::AppUnitsToFloatCSSPixels(borderImageSplitInt[side]);
+    }
+
+    borderTop = dc->AppUnitsToGfxUnits(border.top);
+    borderRight = dc->AppUnitsToGfxUnits(border.right);
+    borderBottom = dc->AppUnitsToGfxUnits(border.bottom);
+    borderLeft = dc->AppUnitsToGfxUnits(border.left);
+
+    gfxSize gfxImageSize;
+    gfxImageSize.width = nsPresContext::AppUnitsToFloatCSSPixels(imageSize.width);
+    gfxImageSize.height = nsPresContext::AppUnitsToFloatCSSPixels(imageSize.height);
+
+    nsRect outerRect(aBorderArea);
+    gfxRect rectToDraw,
+            rectToDrawSource;
+
+    gfxRect clipRect;
+    clipRect.pos.x = dc->AppUnitsToGfxUnits(outerRect.x);
+    clipRect.pos.y = dc->AppUnitsToGfxUnits(outerRect.y);
+    clipRect.size.width = dc->AppUnitsToGfxUnits(outerRect.width);
+    clipRect.size.height = dc->AppUnitsToGfxUnits(outerRect.height);
+    thebesCtx->UserToDevicePixelSnapped(clipRect);
+
+    thebesCtx->Save();
+    thebesCtx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
+
+    gfxSize middleSize(clipRect.size.width - (borderLeft + borderRight),
+                       clipRect.size.height - (borderTop + borderBottom));
+
+    // middle size in source space
+    gfxIntSize middleSizeSource(gfxImageSize.width - (borderImageSplitGfx[NS_SIDE_RIGHT] + borderImageSplitGfx[NS_SIDE_LEFT]), 
+                                gfxImageSize.height - (borderImageSplitGfx[NS_SIDE_TOP] + borderImageSplitGfx[NS_SIDE_BOTTOM]));
+
+    gfxSize interSizeTop, interSizeBottom, interSizeLeft, interSizeRight,
+            interSizeMiddle;
+    gfxFloat topScale = borderTop/borderImageSplitGfx[NS_SIDE_TOP];
+    gfxFloat bottomScale = borderBottom/borderImageSplitGfx[NS_SIDE_BOTTOM];
+    gfxFloat leftScale = borderLeft/borderImageSplitGfx[NS_SIDE_LEFT];
+    gfxFloat rightScale = borderRight/borderImageSplitGfx[NS_SIDE_RIGHT];
+    gfxFloat middleScaleH,
+             middleScaleV;
+    // TODO: check for nan and properly check for inf
+    if (topScale != 0.0 && borderImageSplitGfx[NS_SIDE_TOP] != 0.0) {
+      middleScaleH = topScale;
+    } else if (bottomScale != 0.0 && borderImageSplitGfx[NS_SIDE_BOTTOM] != 0.0) {
+      middleScaleH = bottomScale;
+    } else {
+      middleScaleH = 1.0;
+    }
+
+    if (leftScale != 0.0 && borderImageSplitGfx[NS_SIDE_LEFT] != 0.0) {
+      middleScaleV = leftScale;
+    } else if (rightScale != 0.0 && borderImageSplitGfx[NS_SIDE_RIGHT] != 0.0) {
+      middleScaleV = rightScale;
+    } else {
+      middleScaleV = 1.0;
+    }
+
+    interSizeTop.height = borderTop;
+    interSizeTop.width = middleSizeSource.width*topScale;
+
+    interSizeBottom.height = borderBottom;
+    interSizeBottom.width = middleSizeSource.width*bottomScale;
+
+    interSizeLeft.width = borderLeft;
+    interSizeLeft.height = middleSizeSource.height*leftScale;
+
+    interSizeRight.width = borderRight;
+    interSizeRight.height = middleSizeSource.height*rightScale;
+
+    interSizeMiddle.width = middleSizeSource.width*middleScaleH;
+    interSizeMiddle.height = middleSizeSource.height*middleScaleV;
+
+    // draw top left corner
+    rectToDraw = clipRect;
+    rectToDraw.size.width = borderLeft;
+    rectToDraw.size.height = borderTop;
+    rectToDrawSource.pos.x = 0;
+    rectToDrawSource.pos.y = 0;
+    rectToDrawSource.size.width = borderImageSplitGfx[NS_SIDE_LEFT];
+    rectToDrawSource.size.height = borderImageSplitGfx[NS_SIDE_TOP];
+    DrawBorderImageSide(thebesCtx, dc, image,
+                        rectToDraw, rectToDraw.size, rectToDrawSource,
+                        NS_STYLE_BORDER_IMAGE_STRETCH, NS_STYLE_BORDER_IMAGE_STRETCH);
+
+    // draw top
+    rectToDraw = clipRect;
+    rectToDraw.pos.x += borderLeft;
+    rectToDraw.size.width = middleSize.width;
+    rectToDraw.size.height = borderTop;
+    rectToDrawSource.pos.x = borderImageSplitGfx[NS_SIDE_LEFT];
+    rectToDrawSource.pos.y = 0;
+    rectToDrawSource.size.width = middleSizeSource.width;
+    rectToDrawSource.size.height = borderImageSplitGfx[NS_SIDE_TOP];
+    DrawBorderImageSide(thebesCtx, dc, image,
+                        rectToDraw, interSizeTop, rectToDrawSource, 
+                        aBorderStyle.mBorderImageHFill, NS_STYLE_BORDER_IMAGE_STRETCH);
+    
+    // draw top right corner
+    rectToDraw = clipRect;
+    rectToDraw.pos.x += clipRect.size.width - borderRight;
+    rectToDraw.size.width = borderRight;
+    rectToDraw.size.height = borderTop;
+    rectToDrawSource.pos.x = gfxImageSize.width - borderImageSplitGfx[NS_SIDE_RIGHT];
+    rectToDrawSource.pos.y = 0;
+    rectToDrawSource.size.width = borderImageSplitGfx[NS_SIDE_RIGHT];
+    rectToDrawSource.size.height = borderImageSplitGfx[NS_SIDE_TOP];
+    DrawBorderImageSide(thebesCtx, dc, image,
+                        rectToDraw, rectToDraw.size, rectToDrawSource,
+                        NS_STYLE_BORDER_IMAGE_STRETCH, NS_STYLE_BORDER_IMAGE_STRETCH);
+    
+    // draw right
+    rectToDraw = clipRect;
+    rectToDraw.pos.x += clipRect.size.width - borderRight;
+    rectToDraw.pos.y += borderTop;
+    rectToDraw.size.width = borderRight;
+    rectToDraw.size.height = middleSize.height;
+    rectToDrawSource.pos.x = gfxImageSize.width - borderImageSplitGfx[NS_SIDE_RIGHT];
+    rectToDrawSource.pos.y = borderImageSplitGfx[NS_SIDE_TOP];
+    rectToDrawSource.size.width = borderImageSplitGfx[NS_SIDE_RIGHT];
+    rectToDrawSource.size.height = middleSizeSource.height;
+    DrawBorderImageSide(thebesCtx, dc, image,
+                        rectToDraw, interSizeRight, rectToDrawSource, 
+                        NS_STYLE_BORDER_IMAGE_STRETCH, aBorderStyle.mBorderImageVFill);
+    
+    // draw bottom right corner
+    rectToDraw = clipRect;
+    rectToDraw.pos.x += clipRect.size.width - borderRight;
+    rectToDraw.pos.y += clipRect.size.height - borderBottom;
+    rectToDraw.size.width = borderRight;
+    rectToDraw.size.height = borderBottom;
+    rectToDrawSource.pos.x = gfxImageSize.width - borderImageSplitGfx[NS_SIDE_RIGHT];
+    rectToDrawSource.pos.y = gfxImageSize.height - borderImageSplitGfx[NS_SIDE_BOTTOM];
+    rectToDrawSource.size.width = borderImageSplitGfx[NS_SIDE_RIGHT];
+    rectToDrawSource.size.height = borderImageSplitGfx[NS_SIDE_BOTTOM];
+    DrawBorderImageSide(thebesCtx, dc, image,
+                        rectToDraw, rectToDraw.size, rectToDrawSource,
+                        NS_STYLE_BORDER_IMAGE_STRETCH, NS_STYLE_BORDER_IMAGE_STRETCH);
+    
+    // draw bottom
+    rectToDraw = clipRect;
+    rectToDraw.pos.x += borderLeft;
+    rectToDraw.pos.y += clipRect.size.height - borderBottom;
+    rectToDraw.size.width = middleSize.width;
+    rectToDraw.size.height = borderBottom;
+    rectToDrawSource.pos.x = borderImageSplitGfx[NS_SIDE_LEFT];
+    rectToDrawSource.pos.y = gfxImageSize.height - borderImageSplitGfx[NS_SIDE_BOTTOM];
+    rectToDrawSource.size.width = middleSizeSource.width;
+    rectToDrawSource.size.height = borderImageSplitGfx[NS_SIDE_BOTTOM];
+    DrawBorderImageSide(thebesCtx, dc, image,
+                        rectToDraw, interSizeBottom, rectToDrawSource, 
+                        aBorderStyle.mBorderImageHFill, NS_STYLE_BORDER_IMAGE_STRETCH);
+    
+    // draw bottom left corner
+    rectToDraw = clipRect;
+    rectToDraw.pos.y += clipRect.size.height - borderBottom;
+    rectToDraw.size.width = borderLeft;
+    rectToDraw.size.height = borderBottom;
+    rectToDrawSource.pos.x = 0;
+    rectToDrawSource.pos.y = gfxImageSize.height - borderImageSplitGfx[NS_SIDE_BOTTOM];
+    rectToDrawSource.size.width = borderImageSplitGfx[NS_SIDE_LEFT];
+    rectToDrawSource.size.height = borderImageSplitGfx[NS_SIDE_BOTTOM];
+    DrawBorderImageSide(thebesCtx, dc, image,
+                        rectToDraw, rectToDraw.size, rectToDrawSource,
+                        NS_STYLE_BORDER_IMAGE_STRETCH, NS_STYLE_BORDER_IMAGE_STRETCH);
+    
+    // draw left
+    rectToDraw = clipRect;
+    rectToDraw.pos.y += borderTop;
+    rectToDraw.size.width = borderLeft;
+    rectToDraw.size.height = middleSize.height;
+    rectToDrawSource.pos.x = 0;
+    rectToDrawSource.pos.y = borderImageSplitGfx[NS_SIDE_TOP];
+    rectToDrawSource.size.width = borderImageSplitGfx[NS_SIDE_LEFT];
+    rectToDrawSource.size.height = middleSizeSource.height;
+    DrawBorderImageSide(thebesCtx, dc, image,
+                        rectToDraw, interSizeLeft, rectToDrawSource, 
+                        NS_STYLE_BORDER_IMAGE_STRETCH, aBorderStyle.mBorderImageVFill);
+
+    // Draw middle
+    rectToDraw = clipRect;
+    rectToDraw.pos.x += borderLeft;
+    rectToDraw.pos.y += borderTop;
+    rectToDraw.size.width = middleSize.width;
+    rectToDraw.size.height = middleSize.height;
+    rectToDrawSource.pos.x = borderImageSplitGfx[NS_SIDE_LEFT];
+    rectToDrawSource.pos.y = borderImageSplitGfx[NS_SIDE_TOP];
+    rectToDrawSource.size = middleSizeSource;
+    DrawBorderImageSide(thebesCtx, dc, image,
+                        rectToDraw, interSizeMiddle, rectToDrawSource,
+                        aBorderStyle.mBorderImageHFill, aBorderStyle.mBorderImageVFill);
+
+    thebesCtx->PopGroupToSource();
+    thebesCtx->SetOperator(gfxContext::OPERATOR_OVER);
+    thebesCtx->Paint();
+    thebesCtx->Restore();
+}
+
+void
+nsCSSRendering::DrawBorderImageSide(gfxContext *aThebesContext,
+                                    nsIDeviceContext* aDeviceContext,
+                                    imgIContainer* aImage,
+                                    gfxRect& aDestRect,
+                                    gfxSize& aInterSize,
+                                    gfxRect& aSourceRect,
+                                    PRUint8 aHFillType,
+                                    PRUint8 aVFillType)
+{
+  if (aDestRect.size.width < 1.0 || aDestRect.size.height < 1.0 ||
+      aSourceRect.size.width < 1.0 || aSourceRect.size.height < 1.0) {
+    return;
+  }
+
+  gfxIntSize gfxSourceSize((PRInt32)aSourceRect.size.width,
+                           (PRInt32)aSourceRect.size.height);
+
+  // where the actual border ends up being rendered
+  aThebesContext->UserToDevicePixelSnapped(aDestRect);
+  aThebesContext->UserToDevicePixelSnapped(aSourceRect);
+
+  if (aDestRect.size.height < 1.0 ||
+     aDestRect.size.width < 1.0)
+    return;
+
+  if (aInterSize.width < 1.0 ||
+     aInterSize.height < 1.0)
+    return;
+
+  // Surface will hold just the part of the source image specified by the aSourceRect
+  // but at a different size
+  nsRefPtr<gfxASurface> interSurface =
+    gfxPlatform::GetPlatform()->CreateOffscreenSurface(
+        gfxSourceSize, gfxASurface::ImageFormatARGB32);
+
+  gfxMatrix srcMatrix;
+  // Adjust the matrix scale for Step 1 of the spec
+  srcMatrix.Scale(aSourceRect.size.width/aInterSize.width,
+                  aSourceRect.size.height/aInterSize.height);
+  {
+    nsCOMPtr<gfxIImageFrame> frame;
+    nsresult rv = aImage->GetCurrentFrame(getter_AddRefs(frame));
+    if(NS_FAILED(rv))
+      return;
+    nsCOMPtr<nsIImage> image;
+    image = do_GetInterface(frame);
+    if(!image)
+      return;
+
+    // surface for the whole image
+    nsRefPtr<gfxPattern> imagePattern;
+    rv = image->GetPattern(getter_AddRefs(imagePattern));
+    if(NS_FAILED(rv) || !imagePattern)
+      return;
+
+    gfxMatrix mat;
+    mat.Translate(aSourceRect.pos);
+    imagePattern->SetMatrix(mat);
+
+    // Straightforward blit - no resizing
+    nsRefPtr<gfxContext> srcCtx = new gfxContext(interSurface);
+    srcCtx->SetPattern(imagePattern);
+    srcCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
+    srcCtx->Paint();
+    srcCtx = nsnull;
+
+  }
+
+  // offset to make the middle tile centered in the middle of the border
+  gfxPoint renderOffset(0, 0);
+  gfxSize rectSize(aDestRect.size);
+
+  aThebesContext->Save();
+  aThebesContext->Clip(aDestRect);
+
+  gfxFloat hScale(1.0), vScale(1.0);
+
+  nsRefPtr<gfxPattern> pattern = new gfxPattern(interSurface);
+  pattern->SetExtend(gfxPattern::EXTEND_PAD);
+  switch (aHFillType) {
+    case NS_STYLE_BORDER_IMAGE_REPEAT:
+      renderOffset.x = (rectSize.width - aInterSize.width*NS_ceil(rectSize.width/aInterSize.width))*-0.5;
+      aDestRect.pos.x -= renderOffset.x;
+      pattern->SetExtend(gfxPattern::EXTEND_REPEAT);
+      break;
+    case NS_STYLE_BORDER_IMAGE_ROUND:
+      hScale = aInterSize.width*(NS_ceil(aDestRect.size.width/aInterSize.width)/aDestRect.size.width);
+      pattern->SetExtend(gfxPattern::EXTEND_REPEAT);
+      break;
+    case NS_STYLE_BORDER_IMAGE_STRETCH:
+    default:
+      hScale = aInterSize.width/aDestRect.size.width;
+      break;
+  }
+
+  switch (aVFillType) {
+    case NS_STYLE_BORDER_IMAGE_REPEAT:
+      renderOffset.y = (rectSize.height - aInterSize.height*NS_ceil(rectSize.height/aInterSize.height))*-0.5;
+      aDestRect.pos.y -= renderOffset.y;
+      pattern->SetExtend(gfxPattern::EXTEND_REPEAT);
+      break;
+    case NS_STYLE_BORDER_IMAGE_ROUND:
+      vScale = aInterSize.height*(NS_ceil(aDestRect.size.height/aInterSize.height)/aDestRect.size.height);
+      pattern->SetExtend(gfxPattern::EXTEND_REPEAT);
+      break;
+    case NS_STYLE_BORDER_IMAGE_STRETCH:
+    default:
+      vScale = aInterSize.height/aDestRect.size.height;
+      break;
+  }
+
+  // Adjust the matrix scale for Step 2 of the spec
+  srcMatrix.Scale(hScale,vScale);
+  pattern->SetMatrix(srcMatrix);
+
+  // render
+  aThebesContext->Translate(aDestRect.pos);
+  aThebesContext->SetPattern(pattern);
+  aThebesContext->NewPath();
+  aThebesContext->Rectangle(gfxRect(renderOffset, rectSize));
+  aThebesContext->SetOperator(gfxContext::OPERATOR_ADD);
+  aThebesContext->Fill();
+  aThebesContext->Restore();
+}
+
+void
 nsCSSRendering::PaintBackgroundColor(nsPresContext* aPresContext,
                                      nsIRenderingContext& aRenderingContext,
                                      nsIFrame* aForFrame,
                                      const nsRect& aBgClipArea,
                                      const nsStyleBackground& aColor,
                                      const nsStyleBorder& aBorder,
                                      const nsStylePadding& aPadding,
                                      PRBool aCanPaintNonWhite)
@@ -4135,31 +4531,31 @@ nsCSSRendering::PaintRoundedBackground(n
 
   // Adjust for background-clip, if necessary
   if (aColor.mBackgroundClip != NS_STYLE_BG_CLIP_BORDER) {
     NS_ASSERTION(aColor.mBackgroundClip == NS_STYLE_BG_CLIP_PADDING, "unknown background-clip value");
 
     // Get the radius to the outer edge of the padding.
     // -moz-border-radius is the radius to the outer edge of the border.
     NS_FOR_CSS_SIDES(side) {
-      aTheRadius[side] -= aBorder.GetBorderWidth(side);
+      aTheRadius[side] -= aBorder.GetActualBorderWidth(side);
       aTheRadius[side] = PR_MAX(aTheRadius[side], 0);
     }
   }
 
   // the bgClipArea is the outside
   gfxRect oRect(RectToGfxRect(aBgClipArea, appUnitsPerPixel));
   oRect.Round();
   oRect.Condition();
   if (oRect.IsEmpty())
     return;
 
   // convert the radii
   gfxFloat radii[4];
-  nsMargin border = aBorder.GetBorder();
+  nsMargin border = aBorder.GetActualBorder();
 
   ComputePixelRadii(aTheRadius, aBgClipArea, border,
                     aForFrame ? aForFrame->GetSkipSides() : 0,
                     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
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -268,16 +268,32 @@ public:
                                       const gfxSize& aLineSize,
                                       const gfxFloat aAscent,
                                       const gfxFloat aOffset,
                                       const PRUint8 aDecoration,
                                       const PRUint8 aStyle);
 
 protected:
 
+  static void DrawBorderImage(nsPresContext* aPresContext,
+                              nsIRenderingContext& aRenderingContext,
+                              nsIFrame* aForFrame,
+                              const nsRect& aBorderArea,
+                              const nsStyleBorder& aBorderStyle,
+                              nscoord aHardBorderSize);
+
+  static void DrawBorderImageSide(gfxContext *aThebesContext,
+                                  nsIDeviceContext* aDeviceContext,
+                                  imgIContainer* aImage,
+                                  gfxRect& aDestRect,
+                                  gfxSize& aInterSize,
+                                  gfxRect& aSourceRect,
+                                  PRUint8 aHFillType,
+                                  PRUint8 aVFillType);
+
   static void PaintBackgroundColor(nsPresContext* aPresContext,
                                    nsIRenderingContext& aRenderingContext,
                                    nsIFrame* aForFrame,
                                    const nsRect& aBgClipArea,
                                    const nsStyleBackground& aColor,
                                    const nsStyleBorder& aBorder,
                                    const nsStylePadding& aPadding,
                                    PRBool aCanPaintNonWhite);
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -45,16 +45,17 @@
 #include "nsDisplayList.h"
 
 #include "nsCSSRendering.h"
 #include "nsISelectionController.h"
 #include "nsIPresShell.h"
 #include "nsRegion.h"
 #include "nsFrameManager.h"
 #include "gfxContext.h"
+#include "nsStyleStructInlines.h"
 
 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
     PRBool aIsForEvents, PRBool aBuildCaret)
     : mReferenceFrame(aReferenceFrame),
       mMovingFrame(nsnull),
       mIgnoreScrollFrame(nsnull),
       mCurrentTableItem(nsnull),
       mBuildCaret(aBuildCaret),
@@ -603,21 +604,26 @@ nsDisplayCaret::Paint(nsDisplayListBuild
 PRBool
 nsDisplayBorder::OptimizeVisibility(nsDisplayListBuilder* aBuilder,
                                     nsRegion* aVisibleRegion) {
   if (!nsDisplayItem::OptimizeVisibility(aBuilder, aVisibleRegion))
     return PR_FALSE;
 
   nsRect paddingRect = mFrame->GetPaddingRect() - mFrame->GetPosition() +
     aBuilder->ToReferenceFrame(mFrame);
+  const nsStyleBorder *styleBorder;
   if (paddingRect.Contains(aVisibleRegion->GetBounds()) &&
-      !nsLayoutUtils::HasNonZeroSide(mFrame->GetStyleBorder()->mBorderRadius)) {
+      !(styleBorder = mFrame->GetStyleBorder())->IsBorderImageLoaded() &&
+      !nsLayoutUtils::HasNonZeroSide(styleBorder->mBorderRadius)) {
     // the visible region is entirely inside the content rect, and no part
     // of the border is rendered inside the content rect, so we are not
     // visible
+    // Skip this if there's a border-image (which draws a background
+    // too) or if there is a border-radius (which makes the border draw
+    // further in).
     return PR_FALSE;
   }
 
   return PR_TRUE;
 }
 
 void
 nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
--- a/layout/base/nsImageLoader.cpp
+++ b/layout/base/nsImageLoader.cpp
@@ -75,20 +75,22 @@ nsImageLoader::~nsImageLoader()
 
   if (mRequest) {
     mRequest->Cancel(NS_ERROR_FAILURE);
   }
 }
 
 
 void
-nsImageLoader::Init(nsIFrame *aFrame, nsPresContext *aPresContext)
+nsImageLoader::Init(nsIFrame *aFrame, nsPresContext *aPresContext,
+                    PRBool aReflowOnLoad)
 {
   mFrame = aFrame;
   mPresContext = aPresContext;
+  mReflowOnLoad = aReflowOnLoad;
 }
 
 void
 nsImageLoader::Destroy()
 {
   mFrame = nsnull;
   mPresContext = nsnull;
 
@@ -203,16 +205,26 @@ NS_IMETHODIMP nsImageLoader::FrameChange
 
   return NS_OK;
 }
 
 
 void
 nsImageLoader::RedrawDirtyFrame(const nsRect* aDamageRect)
 {
+  if (mReflowOnLoad) {
+    nsIPresShell *shell = mPresContext->GetPresShell();
+    nsresult rv = shell->FrameNeedsReflow(mFrame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
+    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not reflow after loading border-image");
+    // Note that we're assuming that the resulting reflow will
+    // invalidate the entire frame.  Given that we only set
+    // mReflowOnLoad if the actual border width will change when we do
+    // this reflow, this invalidate should happen.
+    return;
+  }
   // NOTE: It is not sufficient to invalidate only the size of the image:
   //       the image may be tiled! 
   //       The best option is to call into the frame, however lacking this
   //       we have to at least invalidate the frame's bounds, hence
   //       as long as we have a frame we'll use its size.
   //
 
   // Invalidate the entire frame
--- a/layout/base/nsImageLoader.h
+++ b/layout/base/nsImageLoader.h
@@ -64,24 +64,26 @@ public:
   // has been loaded.
   // Note: Images referenced by the <img> element are displayed
   // incrementally in nsImageFrame.cpp.
 
   // imgIContainerObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe,
                           nsRect * dirtyRect);
 
-  void Init(nsIFrame *aFrame, nsPresContext *aPresContext);
+  void Init(nsIFrame *aFrame, nsPresContext *aPresContext,
+            PRBool aReflowOnLoad);
   nsresult Load(imgIRequest *aImage);
 
   void Destroy();
 
   nsIFrame *GetFrame() { return mFrame; }
   imgIRequest *GetRequest() { return mRequest; }
 
 private:
   void RedrawDirtyFrame(const nsRect* aDamageRect);
 
 private:
   nsIFrame *mFrame;
   nsPresContext *mPresContext;
   nsCOMPtr<imgIRequest> mRequest;
+  PRBool mReflowOnLoad;
 };
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -796,16 +796,19 @@ nsPresContext::Init(nsIDeviceContext* aD
 
   if (mDeviceContext->SetPixelScale(mFullZoom))
     mDeviceContext->FlushFontCache();
   mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
 
   if (!mImageLoaders.Init())
     return NS_ERROR_OUT_OF_MEMORY;
   
+  if (!mBorderImageLoaders.Init())
+    return NS_ERROR_OUT_OF_MEMORY;
+  
   // Get the look and feel service here; default colors will be initialized
   // from calling GetUserPreferences() when we get a presshell.
   nsresult rv = CallGetService(kLookAndFeelCID, &mLookAndFeel);
   if (NS_FAILED(rv)) {
     NS_ERROR("LookAndFeel service must be implemented for this toolkit");
     return rv;
   }
 
@@ -1163,50 +1166,73 @@ nsPresContext::SetFullZoom(float aZoom)
   RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
 
   mSupressResizeReflow = PR_FALSE;
 
   mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
 }
 
 imgIRequest*
-nsPresContext::LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame)
+nsPresContext::DoLoadImage(nsPresContext::ImageLoaderTable& aTable,
+                           imgIRequest* aImage,
+                           nsIFrame* aTargetFrame,
+                           PRBool aReflowOnLoad)
 {
   // look and see if we have a loader for the target frame.
   nsCOMPtr<nsImageLoader> loader;
-  mImageLoaders.Get(aTargetFrame, getter_AddRefs(loader));
+  aTable.Get(aTargetFrame, getter_AddRefs(loader));
 
   if (!loader) {
     loader = new nsImageLoader();
     if (!loader)
       return nsnull;
 
-    loader->Init(aTargetFrame, this);
+    loader->Init(aTargetFrame, this, aReflowOnLoad);
     mImageLoaders.Put(aTargetFrame, loader);
   }
 
   loader->Load(aImage);
 
   imgIRequest *request = loader->GetRequest();
 
   return request;
 }
 
+imgIRequest*
+nsPresContext::LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame)
+{
+  return DoLoadImage(mImageLoaders, aImage, aTargetFrame, PR_FALSE);
+}
+
+imgIRequest*
+nsPresContext::LoadBorderImage(imgIRequest* aImage, nsIFrame* aTargetFrame)
+{
+  return DoLoadImage(mBorderImageLoaders, aImage, aTargetFrame,
+                     aTargetFrame->GetStyleBorder()->ImageBorderDiffers());
+}
 
 void
 nsPresContext::StopImagesFor(nsIFrame* aTargetFrame)
 {
   nsCOMPtr<nsImageLoader> loader;
   mImageLoaders.Get(aTargetFrame, getter_AddRefs(loader));
 
   if (loader) {
     loader->Destroy();
 
     mImageLoaders.Remove(aTargetFrame);
   }
+  
+  mBorderImageLoaders.Get(aTargetFrame, getter_AddRefs(loader));
+  
+  if (loader) {
+    loader->Destroy();
+
+    mBorderImageLoaders.Remove(aTargetFrame);
+  }
 }
 
 
 void
 nsPresContext::SetContainer(nsISupports* aHandler)
 {
   mContainer = do_GetWeakReference(aHandler);
   if (mContainer) {
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -359,24 +359,38 @@ public:
   const nscolor FocusTextColor() const { return mFocusTextColor; }
 
   PRBool GetUseFocusColors() const { return mUseFocusColors; }
   PRUint8 FocusRingWidth() const { return mFocusRingWidth; }
   PRBool GetFocusRingOnAnything() const { return mFocusRingOnAnything; }
  
 
   /**
-   * Load an image for the target frame. This call can be made
-   * repeated with only a single image ever being loaded. When the
-   * image's data is ready for rendering the target frame's Paint()
-   * method will be invoked (via the ViewManager) so that the
-   * appropriate damage repair is done.
+   * Set up observers so that aTargetFrame will be invalidated when
+   * aImage loads, where aImage is its background image.  Only a single
+   * image will be tracked per frame.
    */
   NS_HIDDEN_(imgIRequest*) LoadImage(imgIRequest* aImage,
                                      nsIFrame* aTargetFrame);
+  /**
+   * Set up observers so that aTargetFrame will be invalidated or
+   * reflowed (as appropriate) when aImage loads, where aImage is its
+   * *border* image.  Only a single image will be tracked per frame.
+   */
+  NS_HIDDEN_(imgIRequest*) LoadBorderImage(imgIRequest* aImage,
+                                           nsIFrame* aTargetFrame);
+
+private:
+  typedef nsInterfaceHashtable<nsVoidPtrHashKey, nsImageLoader> ImageLoaderTable;
+
+  NS_HIDDEN_(imgIRequest*) DoLoadImage(ImageLoaderTable& aTable,
+                                       imgIRequest* aImage,
+                                       nsIFrame* aTargetFrame,
+                                       PRBool aReflowOnLoad);
+public:
 
   /**
    * This method is called when a frame is being destroyed to
    * ensure that the image load gets disassociated from the prescontext
    */
   NS_HIDDEN_(void) StopImagesFor(nsIFrame* aTargetFrame);
 
   NS_HIDDEN_(void) SetContainer(nsISupports* aContainer);
@@ -795,17 +809,18 @@ protected:
   nsIEventStateManager* mEventManager;  // [STRONG]
   nsILookAndFeel*       mLookAndFeel;   // [STRONG]
   nsIAtom*              mMedium;        // initialized by subclass ctors;
                                         // weak pointer to static atom
 
   nsILinkHandler*       mLinkHandler;   // [WEAK]
   nsIAtom*              mLangGroup;     // [STRONG]
 
-  nsInterfaceHashtable<nsVoidPtrHashKey, nsImageLoader> mImageLoaders;
+  ImageLoaderTable      mImageLoaders;
+  ImageLoaderTable      mBorderImageLoaders;
   nsWeakPtr             mContainer;
 
   float                 mTextZoom;      // Text zoom, defaults to 1.0
   float                 mFullZoom;      // Page zoom, defaults to 1.0
 
   PRInt32               mCurAppUnitsPerDevPixel;
   PRInt32               mAutoQualityMinFontSizePixelsPref;
 
--- a/layout/base/nsStyleConsts.h
+++ b/layout/base/nsStyleConsts.h
@@ -266,16 +266,21 @@
 #define NS_STYLE_BORDER_STYLE_INSET             7
 #define NS_STYLE_BORDER_STYLE_OUTSET            8
 #define NS_STYLE_BORDER_STYLE_HIDDEN            9
 #define NS_STYLE_BORDER_STYLE_AUTO              10 // for outline-style only
 // a bit ORed onto the style for table border collapsing indicating that the style was 
 // derived from a table with its rules attribute set
 #define NS_STYLE_BORDER_STYLE_RULES_MARKER      0x10  
 
+// See nsStyleBorder mBorderImage
+#define NS_STYLE_BORDER_IMAGE_STRETCH           0
+#define NS_STYLE_BORDER_IMAGE_REPEAT            1
+#define NS_STYLE_BORDER_IMAGE_ROUND             2
+
 // See nsStyleDisplay
 #define NS_STYLE_CLEAR_NONE                     0
 #define NS_STYLE_CLEAR_LEFT                     1
 #define NS_STYLE_CLEAR_RIGHT                    2
 #define NS_STYLE_CLEAR_LEFT_AND_RIGHT           3
 #define NS_STYLE_CLEAR_LINE                     4
 #define NS_STYLE_CLEAR_BLOCK                    5
 #define NS_STYLE_CLEAR_COLUMN                   6
--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ b/layout/forms/nsButtonFrameRenderer.cpp
@@ -258,17 +258,17 @@ nsMargin
 nsButtonFrameRenderer::GetButtonOuterFocusBorderAndPadding()
 {
   nsMargin result(0,0,0,0);
 
   if (mOuterFocusStyle) {
     if (!mOuterFocusStyle->GetStylePadding()->GetPadding(result)) {
       NS_NOTYETIMPLEMENTED("percentage padding");
     }
-    result += mOuterFocusStyle->GetStyleBorder()->GetBorder();
+    result += mOuterFocusStyle->GetStyleBorder()->GetActualBorder();
   }
 
   return result;
 }
 
 nsMargin
 nsButtonFrameRenderer::GetButtonBorderAndPadding()
 {
@@ -297,17 +297,17 @@ nsMargin
 nsButtonFrameRenderer::GetButtonInnerFocusBorderAndPadding()
 {
   nsMargin result(0,0,0,0);
 
   if (mInnerFocusStyle) {
     if (!mInnerFocusStyle->GetStylePadding()->GetPadding(result)) {
       NS_NOTYETIMPLEMENTED("percentage padding");
     }
-    result += mInnerFocusStyle->GetStyleBorder()->GetBorder();
+    result += mInnerFocusStyle->GetStyleBorder()->GetActualBorder();
   }
 
   return result;
 }
 
 nsMargin
 nsButtonFrameRenderer::GetButtonOutlineBorderAndPadding()
 {
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -257,17 +257,17 @@ nsFieldSetFrame::BuildDisplayList(nsDisp
 void
 nsFieldSetFrame::PaintBorderBackground(nsIRenderingContext& aRenderingContext,
     nsPoint aPt, const nsRect& aDirtyRect)
 {
   PRIntn skipSides = GetSkipSides();
   const nsStyleBorder* borderStyle = GetStyleBorder();
   const nsStylePadding* paddingStyle = GetStylePadding();
        
-  nscoord topBorder = borderStyle->GetBorderWidth(NS_SIDE_TOP);
+  nscoord topBorder = borderStyle->GetActualBorderWidth(NS_SIDE_TOP);
   nscoord yoff = 0;
   nsPresContext* presContext = PresContext();
      
   // if the border is smaller than the legend. Move the border down
   // to be centered on the legend. 
   if (topBorder < mLegendRect.height)
     yoff = (mLegendRect.height - topBorder)/2;
       
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -221,17 +221,17 @@ nsHTMLButtonControlFrame::BuildDisplayLi
   // Put the foreground outline and focus rects on top of the children
   set.Content()->AppendToTop(&onTop);
 
     // XXX This is temporary
   // clips to its size minus the border 
   // but the real problem is the FirstChild (the AreaFrame)
   // isn't being constrained properly
   // Bug #17474
-  nsMargin border = GetStyleBorder()->GetBorder();
+  nsMargin border = GetStyleBorder()->GetActualBorder();
   nsRect rect(aBuilder->ToReferenceFrame(this), GetSize());
   rect.Deflate(border);
   
   nsresult rv = OverflowClip(aBuilder, set, aLists, rect);
   NS_ENSURE_SUCCESS(rv, rv);
   
   rv = DisplayOutline(aBuilder, aLists);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -390,17 +390,17 @@ nsAbsoluteContainingBlock::ReflowAbsolut
   // Store position and overflow rect so taht we can invalidate the correct
   // area if the position changes
   nsRect oldOverflowRect(aKidFrame->GetOverflowRect() +
                          aKidFrame->GetPosition());
   nsRect oldRect = aKidFrame->GetRect();
 
   nsresult  rv;
   // Get the border values
-  const nsMargin& border = aReflowState.mStyleBorder->GetBorder();
+  const nsMargin& border = aReflowState.mStyleBorder->GetActualBorder();
 
   nscoord availWidth = aContainingBlockWidth;
   if (availWidth == -1) {
     NS_ASSERTION(aReflowState.ComputedWidth() != NS_UNCONSTRAINEDSIZE,
                  "Must have a useful width _somewhere_");
     availWidth =
       aReflowState.ComputedWidth() + aReflowState.mComputedPadding.LeftRight();
   }
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -791,17 +791,17 @@ CalculateContainingBlockSizeForAbsolutes
   // The issue here is that for a 'height' of 'auto' the reflow state
   // code won't know how to calculate the containing block height
   // because it's calculated bottom up. So we use our own computed
   // size as the dimensions.
   nsIFrame* frame = aReflowState.frame;
 
   nsSize cbSize(aFrameSize);
     // Containing block is relative to the padding edge
-  const nsMargin& border = aReflowState.mStyleBorder->GetBorder();
+  const nsMargin& border = aReflowState.mStyleBorder->GetActualBorder();
   cbSize.width -= border.left + border.right;
   cbSize.height -= border.top + border.bottom;
 
   if (frame->GetParent()->GetContent() == frame->GetContent()) {
     // We are a wrapped frame for the content. Use the container's
     // dimensions, if they have been precomputed.
     // XXX This is a hack! We really should be waiting until the outermost
     // frame is fully reflowed and using the resulting dimensions, even
@@ -2645,18 +2645,18 @@ nsBlockFrame::IsSelfEmpty()
         return PR_FALSE;
       break;
     default:
       return PR_FALSE;
   }
 
   const nsStyleBorder* border = GetStyleBorder();
   const nsStylePadding* padding = GetStylePadding();
-  if (border->GetBorderWidth(NS_SIDE_TOP) != 0 ||
-      border->GetBorderWidth(NS_SIDE_BOTTOM) != 0 ||
+  if (border->GetActualBorderWidth(NS_SIDE_TOP) != 0 ||
+      border->GetActualBorderWidth(NS_SIDE_BOTTOM) != 0 ||
       !IsPaddingZero(padding->mPadding.GetTopUnit(),
                      padding->mPadding.GetTop()) ||
       !IsPaddingZero(padding->mPadding.GetBottomUnit(),
                      padding->mPadding.GetBottom())) {
     return PR_FALSE;
   }
 
   return PR_TRUE;
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -661,17 +661,17 @@ nsContainerFrame::DoInlineIntrinsicWidth
   // (implemented in bug 328168), the startSide border is always on the
   // first line.
   // This frame is a first-in-flow, but it might have a previous bidi
   // continuation, in which case that continuation should handle the startSide 
   // border.
   if (!GetPrevContinuation()) {
     aData->currentLine +=
       GetCoord(stylePadding->mPadding.Get(startSide), 0) +
-      styleBorder->GetBorderWidth(startSide) +
+      styleBorder->GetActualBorderWidth(startSide) +
       GetCoord(styleMargin->mMargin.Get(startSide), 0);
   }
 
   const nsLineList_iterator* savedLine = aData->line;
 
   nsContainerFrame *lastInFlow;
   for (nsContainerFrame *nif = this; nif;
        nif = (nsContainerFrame*) nif->GetNextInFlow()) {
@@ -698,17 +698,17 @@ nsContainerFrame::DoInlineIntrinsicWidth
   // (implemented in bug 328168), the endSide border is always on the
   // last line.
   // We reached the last-in-flow, but it might have a next bidi
   // continuation, in which case that continuation should handle 
   // the endSide border.
   if (!lastInFlow->GetNextContinuation()) {
     aData->currentLine +=
       GetCoord(stylePadding->mPadding.Get(endSide), 0) +
-      styleBorder->GetBorderWidth(endSide) +
+      styleBorder->GetActualBorderWidth(endSide) +
       GetCoord(styleMargin->mMargin.Get(endSide), 0);
   }
 }
 
 /* virtual */ nsSize
 nsContainerFrame::ComputeAutoSize(nsIRenderingContext *aRenderingContext,
                                   nsSize aCBSize, nscoord aAvailableWidth,
                                   nsSize aMargin, nsSize aBorder,
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -581,17 +581,17 @@ nsIFrame::GetUsedBorder() const
                                              &result);
     result.top = presContext->DevPixelsToAppUnits(result.top);
     result.right = presContext->DevPixelsToAppUnits(result.right);
     result.bottom = presContext->DevPixelsToAppUnits(result.bottom);
     result.left = presContext->DevPixelsToAppUnits(result.left);
     return result;
   }
 
-  return GetStyleBorder()->GetBorder();
+  return GetStyleBorder()->GetActualBorder();
 }
 
 /* virtual */ nsMargin
 nsIFrame::GetUsedPadding() const
 {
   NS_ASSERTION(nsLayoutUtils::sDisableGetUsedXAssertions ||
                !NS_SUBTREE_DIRTY(this) ||
                (GetStateBits() & NS_FRAME_IN_REFLOW),
@@ -2984,18 +2984,18 @@ nsFrame::IntrinsicWidthOffsets(nsIRender
 
   const nsStylePadding *stylePadding = GetStylePadding();
   AddCoord(stylePadding->mPadding.GetLeft(), aRenderingContext, this,
            &result.hPadding, &result.hPctPadding);
   AddCoord(stylePadding->mPadding.GetRight(), aRenderingContext, this,
            &result.hPadding, &result.hPctPadding);
 
   const nsStyleBorder *styleBorder = GetStyleBorder();
-  result.hBorder += styleBorder->GetBorderWidth(NS_SIDE_LEFT);
-  result.hBorder += styleBorder->GetBorderWidth(NS_SIDE_RIGHT);
+  result.hBorder += styleBorder->GetActualBorderWidth(NS_SIDE_LEFT);
+  result.hBorder += styleBorder->GetActualBorderWidth(NS_SIDE_RIGHT);
 
   const nsStyleDisplay *disp = GetStyleDisplay();
   if (IsThemed(disp)) {
     nsPresContext *presContext = PresContext();
 
     nsMargin border;
     presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
                                              this, disp->mAppearance,
@@ -3776,17 +3776,17 @@ nsFrame::CheckInvalidateSizeChange(nsPre
     Invalidate(r);
     return;
   }
 
   // Invalidate the old frame borders if the frame has borders. Those borders
   // may be moving.
   const nsStyleBorder* border = GetStyleBorder();
   NS_FOR_CSS_SIDES(side) {
-    if (border->GetBorderWidth(side) != 0) {
+    if (border->GetActualBorderWidth(side) != 0) {
       Invalidate(nsRect(0, 0, mRect.width, mRect.height));
       return;
     }
   }
 
   // Invalidate the old frame background if the frame has a background
   // whose position depends on the size of the frame
   const nsStyleBackground* background = GetStyleBackground();
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -303,16 +303,27 @@ nsHTMLReflowState::Init(nsPresContext* a
 
   InitFrameType();
   InitCBReflowState();
 
   InitConstraints(aPresContext, aContainingBlockWidth, aContainingBlockHeight, aBorder, aPadding);
 
   InitResizeFlags(aPresContext);
 
+  // We have to start loading the border image now, because the
+  // border-image's width overrides only apply once the image is loaded.
+  // Starting the load of the image means we'll get a reflow when the
+  // image loads.  (If we didn't do it now, and the image loaded between
+  // reflow and paint, we'd never get the notification, and our size
+  // would be wrong.)
+  imgIRequest *borderImage = mStyleBorder->GetBorderImage();
+  if (borderImage) {
+    aPresContext->LoadBorderImage(borderImage, frame);
+  }
+
   NS_ASSERTION((mFrameType == NS_CSS_FRAME_TYPE_INLINE &&
                 !frame->IsFrameOfType(nsIFrame::eReplaced)) ||
                frame->GetType() == nsGkAtoms::textFrame ||
                mComputedWidth != NS_UNCONSTRAINEDSIZE,
                "shouldn't use unconstrained widths anymore");
 }
 
 void nsHTMLReflowState::InitCBReflowState()
@@ -794,17 +805,17 @@ GetIntrinsicSizeFor(nsIFrame* aFrame, ns
  * aOutsideBoxSizing returns the rest.
  */
 void
 nsHTMLReflowState::CalculateHorizBorderPaddingMargin(
                        nscoord aContainingBlockWidth,
                        nscoord* aInsideBoxSizing,
                        nscoord* aOutsideBoxSizing)
 {
-  const nsMargin& border = mStyleBorder->GetBorder();
+  const nsMargin& border = mStyleBorder->GetActualBorder();
   nsMargin padding, margin;
 
   // See if the style system can provide us the padding directly
   if (!mStylePadding->GetPadding(padding)) {
     // We have to compute the left and right values
     ComputeWidthDependentValue(aContainingBlockWidth,
                                mStylePadding->mPadding.GetLeft(),
                                padding.left);
@@ -1886,17 +1897,17 @@ nsCSSOffsetState::InitOffsets(nscoord aC
       presContext->DevPixelsToAppUnits(mComputedBorderPadding.bottom);
     mComputedBorderPadding.left =
       presContext->DevPixelsToAppUnits(mComputedBorderPadding.left);
   }
   else if (aBorder) {  // border is an input arg
     mComputedBorderPadding = *aBorder;
   }
   else {
-    mComputedBorderPadding = frame->GetStyleBorder()->GetBorder();
+    mComputedBorderPadding = frame->GetStyleBorder()->GetActualBorder();
   }
   mComputedBorderPadding += mComputedPadding;
 
   if (frame->GetType() == nsGkAtoms::tableFrame) {
     nsTableFrame *tableFrame = static_cast<nsTableFrame*>(frame);
 
     if (tableFrame->IsBorderCollapse()) {
       // border-collapsed tables don't use any of their padding, and
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -128,18 +128,18 @@ nsInlineFrame::IsSelfEmpty()
   }
 #endif
   const nsStyleMargin* margin = GetStyleMargin();
   const nsStyleBorder* border = GetStyleBorder();
   const nsStylePadding* padding = GetStylePadding();
   // XXX Top and bottom removed, since they shouldn't affect things, but this
   // doesn't really match with nsLineLayout.cpp's setting of
   // ZeroEffectiveSpanBox, anymore, so what should this really be?
-  if (border->GetBorderWidth(NS_SIDE_RIGHT) != 0 ||
-      border->GetBorderWidth(NS_SIDE_LEFT) != 0 ||
+  if (border->GetActualBorderWidth(NS_SIDE_RIGHT) != 0 ||
+      border->GetActualBorderWidth(NS_SIDE_LEFT) != 0 ||
       !IsPaddingZero(padding->mPadding.GetRightUnit(),
                      padding->mPadding.GetRight()) ||
       !IsPaddingZero(padding->mPadding.GetLeftUnit(),
                      padding->mPadding.GetLeft()) ||
       !IsMarginZero(margin->mMargin.GetRightUnit(),
                     margin->mMargin.GetRight()) ||
       !IsMarginZero(margin->mMargin.GetLeftUnit(),
                     margin->mMargin.GetLeft())) {
--- a/layout/generic/nsPageContentFrame.cpp
+++ b/layout/generic/nsPageContentFrame.cpp
@@ -201,17 +201,17 @@ nsPageContentFrame::Reflow(nsPresContext
 
     // First check the combined area
     if (NS_FRAME_OUTSIDE_CHILDREN & frame->GetStateBits()) {
       // The background covers the content area and padding area, so check
       // for children sticking outside the child frame's padding edge
       if (aDesiredSize.mOverflowArea.XMost() > aDesiredSize.width) {
         mPD->mPageContentXMost =
           aDesiredSize.mOverflowArea.XMost() +
-          kidReflowState.mStyleBorder->GetBorderWidth(NS_SIDE_RIGHT) +
+          kidReflowState.mStyleBorder->GetActualBorderWidth(NS_SIDE_RIGHT) +
           padding.right;
       }
     }
 
     // Place and size the child
     FinishReflowChild(frame, aPresContext, &kidReflowState, aDesiredSize, 0, 0, 0);
 
     NS_ASSERTION(aPresContext->IsDynamic() || !NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a7d888a32188f39fa19befdbd660fc366097f9a2
GIT binary patch
literal 213
zc%17D@N?(olHy`uVBq!ia0vp^AT}!p6OjDO_R1beF%}28J29*~C-V}>;VkfoEM{Qf
z76xHPhFNnYfP(BLp1!W^H&}(mjQNjrJ!t?6NtU=qlsM<-=BDPAFgO>bCYGe8D3oWG
zWGJ|M`UZqI@`(c#IeEG`hHzX@p0me%S|bQJW;!x43+?!*)(YfwGU_M1tgewebjc>U
xLuccbj!urdq0@gVtTB+SOzE^0RF{yDU?^<kjrk(As1IlwgQu&X%Q~loCIIvzJ=y>O
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bb7a3cf21f5a2298a16cb7ce0e132bb4fa4ebf4e
GIT binary patch
literal 89
zc%17D@N?(olHy`uVBq!ia0vp^%plCc1|-8Yw(bW~3Z5>GAsp9}r|ebyGoO)bh6E7E
iW$#H%NdN+uX^af5@oYR+=B!>owG5uFelF{r5}E)hoD_)w
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9be62f07a0f10aae43601e5d239a753fec9f5316
GIT binary patch
literal 109
zc%17D@N?(olHy`uVBq!ia0vp^%plCc1SD^IDZKzvjKx9jP7LeL$-D$|)ID7sLpZJ{
z=ltLBbi>oNzf^pWadx-pT5js=zMu5)?yhwgZ2p}JlxH|2$1C<{t$8U>3xlVtpUXO@
GgeCx4RwOY1
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6528a9f036834a59300848246ca8442de86e1a21
GIT binary patch
literal 69
zc%17D@N?(olHy`uVBq!ia0vp^%plCc1|-8Yw(bW~Jf1F&Asp9}6BIzo)EOA1Q~16D
OSqz@8elF{r5}E*Z`3!mh
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c2518c3e10c601aa5d0063014ad6aef6e0c230a3
GIT binary patch
literal 118
zc%17D@N?(olHy`uVBq!ia0vp^EFjFm1SHiab7}%9&H|6fVg?4j!ywFfJby(BP>``W
z$lZxy-8q?;K#sJhi(`mHc=C_)2M#bCQ(!v56cixl!lTu{hKFI%eEyFe`ip)8l`(j_
L`njxgN@xNAnPDC!
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/multicolor-image-1-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+
+  table { margin: 0; padding: 0; border-spacing: 0; empty-cells: show; }
+  td { padding: 0; }
+
+  </style>
+</head>
+<body>
+<table>
+  <col style="width: 7px">
+  <col style="width: 100px">
+  <col style="width: 7px">
+
+  <tr style="height: 7px">
+    <td style="background: #87f0b4"></td>
+    <td style="background: #4a298e"></td>
+    <td style="background: #c98bb7"></td>
+  </tr>
+  <tr style="height: 5px">
+    <td style="background: #90a213"></td>
+    <td style="background: #c9aa7d"></td>
+    <td style="background: #90c157"></td>
+  </tr>
+  <tr style="height: 7px">
+    <td style="background: #9d57c1"></td>
+    <td style="background: #3a8e20"></td>
+    <td style="background: #0e6f6c"></td>
+  </tr>
+</table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/multicolor-image-1.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+
+  div {
+    background: red; /* fail if this shows through */
+    background-image: url('3x3multicolor.png'); /* fail if this shows through */
+    -moz-border-image: url('3x3multicolor.png') 1 1 1 1 / 7px;
+    -khtml-border-image: url('3x3multicolor.png') 1 1 1 1 / 7px;
+    border-image: url('3x3multicolor.png') 1 1 1 1 / 7px;
+  }
+
+  </style>
+</head>
+<body>
+<div style="width: 100px; height: 5px"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/multicolor-image-2-ref.html
@@ -0,0 +1,165 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+
+  table { margin: 0; padding: 0; border-spacing: 0; empty-cells: show; }
+  td { padding: 0; }
+  table { margin-bottom: 2px; }
+
+  </style>
+</head>
+<body>
+
+<table>
+  <col style="width: 11px">
+  <col style="width: 9px">
+  <col style="width: 6px">
+  <tr style="height: 4px">
+    <td style="background: #93bd5d"></td>
+    <td style="background: #b55dbd"></td>
+    <td style="background: #8d4921"></td>
+  </tr>
+  <tr style="height: 1px">
+    <td style="background: #21a02c"></td>
+    <td style="background: #4a298e"></td>
+    <td style="background: #ef9b23"></td>
+  </tr>
+  <tr style="height: 8px">
+    <td style="background: #9b733a"></td>
+    <td style="background: #f155ad"></td>
+    <td style="background: #adf3eb"></td>
+  </tr>
+</table>
+
+<table>
+  <col style="width: 4px">
+  <col style="width: 2px">
+  <col style="width: 1px">
+  <tr style="height: 3px">
+    <td style="background: #93bd5d"></td>
+    <td style="background: #b55dbd"></td>
+    <td style="background: #8d4921"></td>
+  </tr>
+  <tr style="height: 17px">
+    <td style="background: #21a02c"></td>
+    <td style="background: #4a298e"></td>
+    <td style="background: #ef9b23"></td>
+  </tr>
+  <tr style="height: 0px">
+    <td style="background: #9b733a"></td>
+    <td style="background: #f155ad"></td>
+    <td style="background: #adf3eb"></td>
+  </tr>
+</table>
+
+<table>
+  <col style="width: 3px">
+  <col style="width: 17px">
+  <col style="width: 2px">
+  <tr style="height: 10px">
+    <td style="background: #93bd5d"></td>
+    <td style="background: #b55dbd"></td>
+    <td style="background: #8d4921"></td>
+  </tr>
+  <tr style="height: 8px">
+    <td style="background: #21a02c"></td>
+    <td style="background: #4a298e"></td>
+    <td style="background: #ef9b23"></td>
+  </tr>
+  <tr style="height: 5px">
+    <td style="background: #9b733a"></td>
+    <td style="background: #f155ad"></td>
+    <td style="background: #adf3eb"></td>
+  </tr>
+</table>
+
+<table>
+  <col style="width: 0px">
+  <col style="width: 8px">
+  <col style="width: 7px">
+  <tr style="height: 5px">
+    <td style="background: #93bd5d"></td>
+    <td style="background: #b55dbd"></td>
+    <td style="background: #8d4921"></td>
+  </tr>
+  <tr style="height: 5px">
+    <td style="background: #21a02c"></td>
+    <td style="background: #4a298e"></td>
+    <td style="background: #ef9b23"></td>
+  </tr>
+  <tr style="height: 1px">
+    <td style="background: #9b733a"></td>
+    <td style="background: #f155ad"></td>
+    <td style="background: #adf3eb"></td>
+  </tr>
+</table>
+
+<table>
+  <col style="width: 2px">
+  <col style="width: 0px">
+  <col style="width: 8px">
+  <tr style="height: 4px">
+    <td style="background: #93bd5d"></td>
+    <td style="background: #b55dbd"></td>
+    <td style="background: #8d4921"></td>
+  </tr>
+  <tr style="height: 8px">
+    <td style="background: #21a02c"></td>
+    <td style="background: #4a298e"></td>
+    <td style="background: #ef9b23"></td>
+  </tr>
+  <tr style="height: 10px">
+    <td style="background: #9b733a"></td>
+    <td style="background: #f155ad"></td>
+    <td style="background: #adf3eb"></td>
+  </tr>
+</table>
+
+<table>
+  <col style="width: 2px">
+  <col style="width: 17px">
+  <col style="width: 0px">
+  <tr style="height: 4px">
+    <td style="background: #93bd5d"></td>
+    <td style="background: #b55dbd"></td>
+    <td style="background: #8d4921"></td>
+  </tr>
+  <tr style="height: 0px">
+    <td style="background: #21a02c"></td>
+    <td style="background: #4a298e"></td>
+    <td style="background: #ef9b23"></td>
+  </tr>
+  <tr style="height: 10px">
+    <td style="background: #9b733a"></td>
+    <td style="background: #f155ad"></td>
+    <td style="background: #adf3eb"></td>
+  </tr>
+</table>
+
+<table>
+  <col style="width: 0px">
+  <col style="width: 17px">
+  <col style="width: 3px">
+  <tr style="height: 1px">
+    <td style="background: #93bd5d"></td>
+    <td style="background: #b55dbd"></td>
+    <td style="background: #8d4921"></td>
+  </tr>
+  <tr style="height: 0px">
+    <td style="background: #21a02c"></td>
+    <td style="background: #4a298e"></td>
+    <td style="background: #ef9b23"></td>
+  </tr>
+  <tr style="height: 0px">
+    <td style="background: #9b733a"></td>
+    <td style="background: #f155ad"></td>
+    <td style="background: #adf3eb"></td>
+  </tr>
+</table>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/multicolor-image-2.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+
+  div {
+    background: red; /* fail if this shows through */
+    background-image: url('3x3multicolor.png'); /* fail if this shows through */
+    margin-bottom: 2px;
+  }
+
+  div.one {
+    -moz-border-image: url(10x5multicolor.png) 2 2 1 3;
+    -khtml-border-image: url(10x5multicolor.png) 2 2 1 3;
+    border-image: url(10x5multicolor.png) 2 2 1 3;
+    border-width: 4px 6px 8px 11px;
+    width: 9px;
+    height: 1px;
+  }
+
+  div.two {
+    -moz-border-image: url(10x5multicolor.png) 40% 20% 20% 30%;
+    -khtml-border-image: url(10x5multicolor.png) 40% 20% 20% 30%;
+    border-image: url(10x5multicolor.png) 40% 20% 20% 30%;
+    border-width: 3px 1px 0px 4px;
+    width: 2px;
+    height: 17px;
+  }
+
+  div.three {
+    -moz-border-image: url(10x5multicolor.png) 40% 2 1 30%;
+    -khtml-border-image: url(10x5multicolor.png) 40% 2 1 30%;
+    border-image: url(10x5multicolor.png) 40% 2 1 30%;
+    border-width: 10px 2px 5px 3px;
+    width: 17px;
+    height: 8px;
+  }
+
+  div.four {
+    -moz-border-image: url(10x5multicolor.png) 2 2 20% 30%;
+    -khtml-border-image: url(10x5multicolor.png) 2 2 20% 30%;
+    border-image: url(10x5multicolor.png) 2 2 20% 30%;
+    border-width: 5px 7px 1px 0;
+    width: 8px;
+    height: 5px;
+  }
+
+  div.five {
+    border-width: 5px 6px 7px 8px; /* ignored */
+    border-width: 5px 6px 7px 8px ! important; /* ignored */
+    -moz-border-image: url(10x5multicolor.png) 40% 2 1 30% / 4px 8px 10px 2px;
+    -khtml-border-image: url(10x5multicolor.png) 40% 2 1 30% / 4px 8px 10px 2px;
+    border-image: url(10x5multicolor.png) 40% 2 1 30% / 4px 8px 10px 2px;
+    border-width: 5px 6px 7px 8px; /* ignored */
+    border-width: 5px 6px 7px 8px ! important; /* ignored */
+    width: 0;
+    height: 8px;
+  }
+  div.five {
+    border-width: 5px 6px 7px 8px; /* ignored */
+    border-width: 5px 6px 7px 8px ! important; /* ignored */
+  }
+
+  div.six {
+    border-width: 5px 6px 7px 8px; /* ignored */
+    -moz-border-image: url(10x5multicolor.png) 40% 2 1 30% / 4px 0 10px 2px;
+    -khtml-border-image: url(10x5multicolor.png) 40% 2 1 30% / 4px 0 10px 2px;
+    border-image: url(10x5multicolor.png) 40% 2 1 30% / 4px 0 10px 2px;
+    width: 17px;
+    height: 0;
+  }
+
+  div.seven {
+    -moz-border-image: url(10x5multicolor.png) 40% 2 1 30%;
+    -khtml-border-image: url(10x5multicolor.png) 40% 2 1 30%;
+    border-image: url(10x5multicolor.png) 40% 2 1 30%;
+    border-width: 1px 3px 0 0;
+    width: 17px;
+    height: 0;
+  }
+
+  </style>
+</head>
+<body>
+<div class="one"></div>
+<div class="two"></div>
+<div class="three"></div>
+<div class="four"></div>
+<div class="five"></div>
+<div class="six"></div>
+<div class="seven"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/multicolor-image-3-ref.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image: number repetition</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+
+  div {
+    background: red; /* fail if this shows through */
+    background-image: url('3x3multicolor.png'); /* fail if this shows through */
+    margin-bottom: 2px;
+  }
+
+  div.one {
+    -moz-border-image: url(10x5multicolor.png) 2 2 2 2 / 4px 6px 8px 6px;
+    -khtml-border-image: url(10x5multicolor.png) 2 2 2 2 / 4px 6px 8px 6px;
+    border-image: url(10x5multicolor.png) 2 2 2 2 / 4px 6px 8px 6px;
+    width: 5px;
+    height: 2px;
+  }
+
+  div.two {
+    -moz-border-image: url(10x5multicolor.png) 2 1 2 1/ 4px 4px 4px 4px;
+    -khtml-border-image: url(10x5multicolor.png) 2 1 2 1/ 4px 4px 4px 4px;
+    border-image: url(10x5multicolor.png) 2 1 2 1/ 4px 4px 4px 4px;
+    width: 5px;
+    height: 2px;
+  }
+
+  div.three {
+    -moz-border-image: url(10x5multicolor.png) 2 3 1 3 / 4px 2px 4px 2px;
+    -khtml-border-image: url(10x5multicolor.png) 2 3 1 3 / 4px 2px 4px 2px;
+    border-image: url(10x5multicolor.png) 2 3 1 3 / 4px 2px 4px 2px;
+    width: 5px;
+    height: 2px;
+  }
+
+  div.four {
+    -moz-border-image: url(10x5multicolor.png) 2 3 1 1 / 4px 3px 4px 3px;
+    -khtml-border-image: url(10x5multicolor.png) 2 3 1 1 / 4px 3px 4px 3px;
+    border-image: url(10x5multicolor.png) 2 3 1 1 / 4px 3px 4px 3px;
+    width: 5px;
+    height: 2px;
+  }
+
+  </style>
+</head>
+<body>
+<div class="one"></div>
+<div class="two"></div>
+<div class="three"></div>
+<div class="four"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/multicolor-image-3.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image: number repetition</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+
+  div {
+    background: red; /* fail if this shows through */
+    background-image: url('3x3multicolor.png'); /* fail if this shows through */
+    margin-bottom: 2px;
+  }
+
+  div.one {
+    -moz-border-image: url(10x5multicolor.png) 2 / 4px 6px 8px;
+    -khtml-border-image: url(10x5multicolor.png) 2 / 4px 6px 8px;
+    border-image: url(10x5multicolor.png) 2 / 4px 6px 8px;
+    width: 5px;
+    height: 2px;
+  }
+
+  div.two {
+    -moz-border-image: url(10x5multicolor.png) 2 1 / 4px;
+    -khtml-border-image: url(10x5multicolor.png) 2 1 / 4px;
+    border-image: url(10x5multicolor.png) 2 1 / 4px;
+    width: 5px;
+    height: 2px;
+  }
+
+  div.three {
+    -moz-border-image: url(10x5multicolor.png) 2 3 1;
+    -khtml-border-image: url(10x5multicolor.png) 2 3 1;
+    border-image: url(10x5multicolor.png) 2 3 1;
+    border-width: 4px 2px;
+    width: 5px;
+    height: 2px;
+  }
+
+  div.four {
+    -moz-border-image: url(10x5multicolor.png) 2 3 1 1 / 4px 3px;
+    -khtml-border-image: url(10x5multicolor.png) 2 3 1 1 / 4px 3px;
+    border-image: url(10x5multicolor.png) 2 3 1 1 / 4px 3px;
+    width: 5px;
+    height: 2px;
+  }
+
+  </style>
+</head>
+<body>
+<div class="one"></div>
+<div class="two"></div>
+<div class="three"></div>
+<div class="four"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/reftest.list
@@ -0,0 +1,7 @@
+== solid-image-1.html solid-image-1-ref.html
+== transparent-image-1.html transparent-image-1-ref.html
+== solid-image-2.html solid-image-2-ref.html
+== multicolor-image-1.html multicolor-image-1-ref.html
+== multicolor-image-2.html multicolor-image-2-ref.html
+== multicolor-image-3.html multicolor-image-3-ref.html
+!= repeat-image-1.html repeat-image-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/repeat-image-1-ref.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+
+  table { margin: 0; padding: 0; border-spacing: 0; empty-cells: show; }
+  td { padding: 0; }
+
+  </style>
+</head>
+<body>
+<table>
+  <col style="width: 3px">
+  <col style="width: 1px">
+  <col style="width: 1px">
+  <col style="width: 1px">
+  <col style="width: 1px">
+  <col style="width: 3px">
+
+  <tr style="height: 1px">
+    <td style="background: #ff0000"></td>
+    <td style="background: #00ff00"></td>
+    <td style="background: #0000ff"></td>
+    <td style="background: #00ff00"></td>
+    <td style="background: #0000ff"></td>
+    <td style="background: #ff0000"></td>
+  </tr>
+  <tr style="height: 1px">
+    <td style="background: #00ff00"></td>
+    <td style="background: #ff0000"></td>
+    <td style="background: #ff0000"></td>
+    <td style="background: #ff0000"></td>
+    <td style="background: #ff0000"></td>
+    <td style="background: #0000ff"></td>
+  </tr>
+  <tr style="height: 1px">
+    <td style="background: #0000ff"></td>
+    <td style="background: #ff0000"></td>
+    <td style="background: #ff0000"></td>
+    <td style="background: #ff0000"></td>
+    <td style="background: #ff0000"></td>
+    <td style="background: #00ff00"></td>
+  </tr>
+  <tr style="height: 1px">
+    <td style="background: #ff0000"></td>
+    <td style="background: #00ff00"></td>
+    <td style="background: #0000ff"></td>
+    <td style="background: #00ff00"></td>
+    <td style="background: #0000ff"></td>
+    <td style="background: #ff0000"></td>
+  </tr>
+</table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/repeat-image-1.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+
+  div.p1 {
+    background: red; /* fail if this shows through */
+    background-image: url('3x3multicolor.png'); /* fail if this shows through */
+    -moz-border-image: url('4x4multicolor.png') 1 1 1 1 / 1px 3px repeat;
+    -khtml-border-image: url('4x4multicolor.png') 1 1 1 1 / 1px 3px repeat;
+    border-image: url('4x4multicolor.png') 1 1 1 1 / 1px 3px repeat;
+  }
+
+  div.p2 {
+    background: red; /* fail if this shows through */
+    background-image: url('3x3multicolor.png'); /* fail if this shows through */
+    -moz-border-image: url('4x4multicolor.png') 1 1 1 1 / 1px 3px;
+    -khtml-border-image: url('4x4multicolor.png') 1 1 1 1 / 1px 3px;
+    border-image: url('4x4multicolor.png') 1 1 1 1 / 1px 3px;
+  }
+
+  </style>
+</head>
+<body>
+<div class="p1" style="width: 4px; height: 2px"></div>
+<!--<div class="p2" style="width: 4px; height: 2px"></div> -->
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/solid-image-1-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+</head>
+<body>
+<div style="border: solid #1DD813 1em;">border.png<br />second longer longer longer longer longer longer line<br />third longer longer longer longer longer longer line</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/solid-image-1.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+  div {
+    -moz-border-image: url('3x3green-1DD813.png') 1 1 1 1 / 1em;
+    -khtml-border-image: url('3x3green-1DD813.png') 1 1 1 1 / 1em;
+    border-image: url('3x3green-1DD813.png') 1 1 1 1 / 1em;
+  }
+  </style>
+</head>
+<body>
+<div>border.png<br />second longer longer longer longer longer longer line<br />third longer longer longer longer longer longer line</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/solid-image-2-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+
+  div {
+    border: 10px solid #1DD813;
+    margin: 1px;
+  }
+
+  </style>
+</head>
+<body>
+<div style="width: 50px; height: 5px"></div>
+<div style="width: 51px; height: 5px"></div>
+<div style="width: 52px; height: 5px"></div>
+<div style="width: 53px; height: 5px"></div>
+<div style="width: 54px; height: 5px"></div>
+<div style="width: 55px; height: 5px"></div>
+<div style="width: 56px; height: 5px"></div>
+<div style="width: 57px; height: 5px"></div>
+<div style="width: 58px; height: 5px"></div>
+<div style="width: 59px; height: 5px"></div>
+<div style="width: 550px; height: 5px"></div>
+<div style="width: 551px; height: 5px"></div>
+<div style="width: 552px; height: 5px"></div>
+<div style="width: 553px; height: 5px"></div>
+<div style="width: 554px; height: 5px"></div>
+<div style="width: 555px; height: 5px"></div>
+<div style="width: 556px; height: 5px"></div>
+<div style="width: 557px; height: 5px"></div>
+<div style="width: 558px; height: 5px"></div>
+<div style="width: 559px; height: 5px"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/solid-image-2.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+
+  div {
+    -moz-border-image: url('3x3green-1DD813.png') 1 1 1 1 / 10px;
+    -khtml-border-image: url('3x3green-1DD813.png') 1 1 1 1 / 10px;
+    border-image: url('3x3green-1DD813.png') 1 1 1 1 / 10px;
+    margin: 1px;
+  }
+
+  </style>
+</head>
+<body>
+<div style="width: 50px; height: 5px"></div>
+<div style="width: 51px; height: 5px"></div>
+<div style="width: 52px; height: 5px"></div>
+<div style="width: 53px; height: 5px"></div>
+<div style="width: 54px; height: 5px"></div>
+<div style="width: 55px; height: 5px"></div>
+<div style="width: 56px; height: 5px"></div>
+<div style="width: 57px; height: 5px"></div>
+<div style="width: 58px; height: 5px"></div>
+<div style="width: 59px; height: 5px"></div>
+<div style="width: 550px; height: 5px"></div>
+<div style="width: 551px; height: 5px"></div>
+<div style="width: 552px; height: 5px"></div>
+<div style="width: 553px; height: 5px"></div>
+<div style="width: 554px; height: 5px"></div>
+<div style="width: 555px; height: 5px"></div>
+<div style="width: 556px; height: 5px"></div>
+<div style="width: 557px; height: 5px"></div>
+<div style="width: 558px; height: 5px"></div>
+<div style="width: 559px; height: 5px"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/transparent-image-1-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+</head>
+<body>
+<div style="padding: 1em;">border.png<br />second longer longer longer longer longer longer line<br />third longer longer longer longer longer longer line</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-image/transparent-image-1.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+  <title>test of -moz-border-image</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <style type="text/css">
+  div {
+    -moz-border-image: url('3x3transparent.png') 1 1 1 1; border: double orange 1em;
+    -khtml-border-image: url('3x3transparent.png') 1 1 1 1; border: double orange 1em;
+    border-image: url('3x3transparent.png') 1 1 1 1; border: double orange 1em;
+  }
+  </style>
+</head>
+<body>
+<div>border.png<br />second longer longer longer longer longer longer line<br />third longer longer longer longer longer longer line</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pixel-rounding/border-image-width-0.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Pixel rounding testcase</title>
+<style type="text/css">
+
+html, body { margin: 0; border: none; padding: 0; }
+div { position: absolute; height: 10px; width: 10px; }
+
+</style>
+</head>
+<body>
+
+<div style="top: 10px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch stretch; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 2px 2px 2px 2px;"></div>
+
+<div style="top: 30px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px round;"></div>
+<div style="top: 30px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px round round;"></div>
+<div style="top: 30px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px round round;"></div>
+<div style="top: 30px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px round;"></div>
+<div style="top: 30px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px round;"></div>
+<div style="top: 30px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round round; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 30px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 30px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 30px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 30px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round round; border-width: 2px 2px 2px 2px;"></div>
+
+<div style="top: 50px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px repeat;"></div>
+<div style="top: 50px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px repeat repeat;"></div>
+<div style="top: 50px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px repeat repeat;"></div>
+<div style="top: 50px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px repeat;"></div>
+<div style="top: 50px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px repeat;"></div>
+<div style="top: 50px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat repeat; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 50px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 50px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 50px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 50px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat repeat; border-width: 2px 2px 2px 2px;"></div>
+
+<div style="top: 70px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px repeat round;"></div>
+<div style="top: 70px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px stretch repeat;"></div>
+<div style="top: 70px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px round repeat;"></div>
+<div style="top: 70px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px repeat stretch;"></div>
+<div style="top: 70px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2px round stretch;"></div>
+<div style="top: 70px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch round; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 70px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round repeat; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 70px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch repeat; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 70px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat round; border-width: 2px 2px 2px 2px;"></div>
+<div style="top: 70px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat round; border-width: 2px 2px 2px 2px;"></div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pixel-rounding/border-image-width-10.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Pixel rounding testcase</title>
+<style type="text/css">
+
+html, body { margin: 0; border: none; padding: 0; }
+div { position: absolute; height: 10px; width: 10px; }
+
+</style>
+</head>
+<body>
+
+<div style="top: 10px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 3px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 3px 2px 2px;"></div>
+<div style="top: 10px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 3px 2px;"></div>
+<div style="top: 10px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 3px;"></div>
+<div style="top: 10px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 3px 3px 3px 3px;"></div>
+<div style="top: 10px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 3px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch; border-width: 2px 3px 2px 2px;"></div>
+<div style="top: 10px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch stretch; border-width: 2px 2px 3px 2px;"></div>
+<div style="top: 10px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 2px 2px 2px 3px;"></div>
+<div style="top: 10px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 3px 3px 3px 3px;"></div>
+
+<div style="top: 30px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 3px 2px 2px 2px round;"></div>
+<div style="top: 30px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 3px 2px 2px round round;"></div>
+<div style="top: 30px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 3px 2px round round;"></div>
+<div style="top: 30px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 3px round;"></div>
+<div style="top: 30px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 3px 3px 3px 3px round;"></div>
+<div style="top: 30px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round round; border-width: 3px 2px 2px 2px;"></div>
+<div style="top: 30px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 3px 2px 2px;"></div>
+<div style="top: 30px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 2px 3px 2px;"></div>
+<div style="top: 30px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 2px 2px 3px;"></div>
+<div style="top: 30px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round round; border-width: 3px 3px 3px 3px;"></div>
+
+<div style="top: 50px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 3px 2px 2px 2px repeat;"></div>
+<div style="top: 50px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 3px 2px 2px repeat repeat;"></div>
+<div style="top: 50px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 3px 2px repeat repeat;"></div>
+<div style="top: 50px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 3px repeat;"></div>
+<div style="top: 50px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 3px 3px 3px 3px repeat;"></div>
+<div style="top: 50px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat repeat; border-width: 3px 2px 2px 2px;"></div>
+<div style="top: 50px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 3px 2px 2px;"></div>
+<div style="top: 50px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 2px 3px 2px;"></div>
+<div style="top: 50px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 2px 2px 3px;"></div>
+<div style="top: 50px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat repeat; border-width: 3px 3px 3px 3px;"></div>
+
+<div style="top: 70px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 3px 2px 2px 2px repeat round;"></div>
+<div style="top: 70px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 3px 2px 2px stretch repeat;"></div>
+<div style="top: 70px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 3px 2px round repeat;"></div>
+<div style="top: 70px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 3px repeat stretch;"></div>
+<div style="top: 70px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 3px 3px 3px 3px round stretch;"></div>
+<div style="top: 70px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch round; border-width: 3px 2px 2px 2px;"></div>
+<div style="top: 70px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round repeat; border-width: 2px 3px 2px 2px;"></div>
+<div style="top: 70px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch repeat; border-width: 2px 2px 3px 2px;"></div>
+<div style="top: 70px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat round; border-width: 2px 2px 2px 3px;"></div>
+<div style="top: 70px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat round; border-width: 3px 3px 3px 3px;"></div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pixel-rounding/border-image-width-4.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Pixel rounding testcase</title>
+<style type="text/css">
+
+html, body { margin: 0; border: none; padding: 0; }
+div { position: absolute; height: 10px; width: 10px; }
+
+</style>
+</head>
+<body>
+
+<div style="top: 10px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.4px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2.4px 2px 2px;"></div>
+<div style="top: 10px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2.4px 2px;"></div>
+<div style="top: 10px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2.4px;"></div>
+<div style="top: 10px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.4px 2.4px 2.4px 2.4px;"></div>
+<div style="top: 10px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 2.4px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch; border-width: 2px 2.4px 2px 2px;"></div>
+<div style="top: 10px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch stretch; border-width: 2px 2px 2.4px 2px;"></div>
+<div style="top: 10px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 2px 2px 2px 2.4px;"></div>
+<div style="top: 10px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 2.4px 2.4px 2.4px 2.4px;"></div>
+
+<div style="top: 30px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.4px 2px 2px 2px round;"></div>
+<div style="top: 30px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2.4px 2px 2px round round;"></div>
+<div style="top: 30px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2.4px 2px round round;"></div>
+<div style="top: 30px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2.4px round;"></div>
+<div style="top: 30px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.4px 2.4px 2.4px 2.4px round;"></div>
+<div style="top: 30px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round round; border-width: 2.4px 2px 2px 2px;"></div>
+<div style="top: 30px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 2.4px 2px 2px;"></div>
+<div style="top: 30px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 2px 2.4px 2px;"></div>
+<div style="top: 30px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 2px 2px 2.4px;"></div>
+<div style="top: 30px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round round; border-width: 2.4px 2.4px 2.4px 2.4px;"></div>
+
+<div style="top: 50px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.4px 2px 2px 2px repeat;"></div>
+<div style="top: 50px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2.4px 2px 2px repeat repeat;"></div>
+<div style="top: 50px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2.4px 2px repeat repeat;"></div>
+<div style="top: 50px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2.4px repeat;"></div>
+<div style="top: 50px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.4px 2.4px 2.4px 2.4px repeat;"></div>
+<div style="top: 50px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat repeat; border-width: 2.4px 2px 2px 2px;"></div>
+<div style="top: 50px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 2.4px 2px 2px;"></div>
+<div style="top: 50px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 2px 2.4px 2px;"></div>
+<div style="top: 50px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 2px 2px 2.4px;"></div>
+<div style="top: 50px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat repeat; border-width: 2.4px 2.4px 2.4px 2.4px;"></div>
+
+<div style="top: 70px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.4px 2px 2px 2px repeat round;"></div>
+<div style="top: 70px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2.4px 2px 2px stretch repeat;"></div>
+<div style="top: 70px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2.4px 2px round repeat;"></div>
+<div style="top: 70px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2.4px repeat stretch;"></div>
+<div style="top: 70px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.4px 2.4px 2.4px 2.4px round stretch;"></div>
+<div style="top: 70px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch round; border-width: 2.4px 2px 2px 2px;"></div>
+<div style="top: 70px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round repeat; border-width: 2px 2.4px 2px 2px;"></div>
+<div style="top: 70px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch repeat; border-width: 2px 2px 2.4px 2px;"></div>
+<div style="top: 70px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat round; border-width: 2px 2px 2px 2.4px;"></div>
+<div style="top: 70px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat round; border-width: 2.4px 2.4px 2.4px 2.4px;"></div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pixel-rounding/border-image-width-9.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Pixel rounding testcase</title>
+<style type="text/css">
+
+html, body { margin: 0; border: none; padding: 0; }
+div { position: absolute; height: 10px; width: 10px; }
+
+</style>
+</head>
+<body>
+
+<div style="top: 10px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.9px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2.9px 2px 2px;"></div>
+<div style="top: 10px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2.9px 2px;"></div>
+<div style="top: 10px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2.9px;"></div>
+<div style="top: 10px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.9px 2.9px 2.9px 2.9px;"></div>
+<div style="top: 10px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 2.9px 2px 2px 2px;"></div>
+<div style="top: 10px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch; border-width: 2px 2.9px 2px 2px;"></div>
+<div style="top: 10px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch stretch; border-width: 2px 2px 2.9px 2px;"></div>
+<div style="top: 10px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 2px 2px 2px 2.9px;"></div>
+<div style="top: 10px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3; border-width: 2.9px 2.9px 2.9px 2.9px;"></div>
+
+<div style="top: 30px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.9px 2px 2px 2px round;"></div>
+<div style="top: 30px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2.9px 2px 2px round round;"></div>
+<div style="top: 30px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2.9px 2px round round;"></div>
+<div style="top: 30px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2.9px round;"></div>
+<div style="top: 30px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.9px 2.9px 2.9px 2.9px round;"></div>
+<div style="top: 30px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round round; border-width: 2.9px 2px 2px 2px;"></div>
+<div style="top: 30px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 2.9px 2px 2px;"></div>
+<div style="top: 30px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 2px 2.9px 2px;"></div>
+<div style="top: 30px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round; border-width: 2px 2px 2px 2.9px;"></div>
+<div style="top: 30px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round round; border-width: 2.9px 2.9px 2.9px 2.9px;"></div>
+
+<div style="top: 50px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.9px 2px 2px 2px repeat;"></div>
+<div style="top: 50px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2.9px 2px 2px repeat repeat;"></div>
+<div style="top: 50px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2.9px 2px repeat repeat;"></div>
+<div style="top: 50px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2.9px repeat;"></div>
+<div style="top: 50px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.9px 2.9px 2.9px 2.9px repeat;"></div>
+<div style="top: 50px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat repeat; border-width: 2.9px 2px 2px 2px;"></div>
+<div style="top: 50px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 2.9px 2px 2px;"></div>
+<div style="top: 50px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 2px 2.9px 2px;"></div>
+<div style="top: 50px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat; border-width: 2px 2px 2px 2.9px;"></div>
+<div style="top: 50px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat repeat; border-width: 2.9px 2.9px 2.9px 2.9px;"></div>
+
+<div style="top: 70px; left: 10px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.9px 2px 2px 2px repeat round;"></div>
+<div style="top: 70px; left: 30px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2.9px 2px 2px stretch repeat;"></div>
+<div style="top: 70px; left: 50px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2.9px 2px round repeat;"></div>
+<div style="top: 70px; left: 70px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2px 2px 2px 2.9px repeat stretch;"></div>
+<div style="top: 70px; left: 90px; -moz-border-image: url(random-10x10.png) 3 2 2 3 / 2.9px 2.9px 2.9px 2.9px round stretch;"></div>
+<div style="top: 70px; left: 110px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch round; border-width: 2.9px 2px 2px 2px;"></div>
+<div style="top: 70px; left: 130px; -moz-border-image: url(random-10x10.png) 3 2 2 3 round repeat; border-width: 2px 2.9px 2px 2px;"></div>
+<div style="top: 70px; left: 150px; -moz-border-image: url(random-10x10.png) 3 2 2 3 stretch repeat; border-width: 2px 2px 2.9px 2px;"></div>
+<div style="top: 70px; left: 170px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat round; border-width: 2px 2px 2px 2.9px;"></div>
+<div style="top: 70px; left: 190px; -moz-border-image: url(random-10x10.png) 3 2 2 3 repeat round; border-width: 2.9px 2.9px 2.9px 2.9px;"></div>
+
+</body>
+</html>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a91d31a838e20b490f68a7444147a9494304300f
GIT binary patch
literal 391
zc$@);0eJq2P)<h;3K|Lk000e1NJLTq000UA000UI0ssI20#I1$00001b5ch_0Itp)
z=>Px$K}keGR2b6%HUY{01Kd(f=O6j}lw^5gLkJ+i*A^HkRN3FD<2iM@-sh788bN<k
zt4x|Lb}OU-rTGEiea*=BK#M5m>Pmn9<Lv+rDP|GRC(K)sDk<T}a^>d_u~e#%EjObu
zCX>F>I|GMD=fhrV1?5EvQ`Rh<SKfvX;w&!d-RnZ%4a*P@1JU81{5ELJ^Yfu3m+A!7
zl@H6|iEZI3#fa!CG&BzY`{n$UE-wA|#ICw{2nGs&jsS%&)LWplXl!KC0qO(ct)Dcj
zyB9S<E+9_C7|^*5&4k6m9`@TFZ;Jc6zyPhOb1ny3v(*t_ZEzV%l7Kni{xdRm984fg
zc*E4~0q~GM#^T>W1XKW56qYABm>+Edw+Oi~gQLS3ZM!Q2m>0Oi`oaf=+$d8b3jkhh
lzy6yeq`B$#)GQuOPK6^Dl)F%It5yI2002ovPDHLkV1kNtr=$P?
--- a/layout/reftests/pixel-rounding/reftest.list
+++ b/layout/reftests/pixel-rounding/reftest.list
@@ -168,8 +168,12 @@ random-if(MOZ_WIDGET_TOOLKIT=="cocoa") =
 == rounded-background-color-height-top-4.html rounded-background-color-height-4.html
 == rounded-background-color-height-top-5.html rounded-background-color-height-5.html
 == rounded-background-color-height-top-6.html rounded-background-color-height-6.html
 == rounded-background-color-width-left-4.html rounded-background-color-width-4.html
 == rounded-background-color-width-left-5.html rounded-background-color-width-5.html
 == rounded-background-color-width-left-6.html rounded-background-color-width-6.html
 
 fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == background-image-tiling.html background-image-tiling-ref.html # probably bug 379317
+
+!= border-image-width-0.html border-image-width-10.html
+== border-image-width-4.html border-image-width-0.html
+== border-image-width-9.html border-image-width-0.html
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -9,16 +9,19 @@
 include reftest-sanity/reftest.list
 
 # images (if libpr0n is busted, could result in weird failures in other tests)
 include ../../modules/libpr0n/test/reftest/reftest.list
 
 # bidi/
 include bidi/reftest.list
 
+# border-image
+include border-image/reftest.list
+
 # box-properties/
 include box-properties/reftest.list
 
 # box-shadow/
 include box-shadow/reftest.list
 
 # bugs/
 include bugs/reftest.list
--- a/layout/style/Makefile.in
+++ b/layout/style/Makefile.in
@@ -112,16 +112,17 @@ EXPORTS		= \
 		nsRuleData.h \
 		nsRuleNode.h \
 		nsRuleWalker.h \
 		nsStyleContext.h \
 		nsStyleCoord.h \
 		nsStyleSet.h \
 		nsStyleStruct.h \
 		nsStyleStructFwd.h \
+		nsStyleStructInlines.h \
 		nsStyleStructList.h \
 		nsStyleUtil.h \
 		$(NULL)
 
 CPPSRCS		= \
 		nsCSSAnonBoxes.cpp \
 		nsCSSDataBlock.cpp \
 		nsCSSDeclaration.cpp \
--- a/layout/style/nsCSSDataBlock.cpp
+++ b/layout/style/nsCSSDataBlock.cpp
@@ -201,20 +201,30 @@ nsCSSCompressedDataBlock::MapRuleInfoInt
             void *prop =
                 nsCSSExpandedDataBlock::RuleDataPropertyAt(aRuleData, iProp);
             switch (nsCSSProps::kTypeTable[iProp]) {
                 case eCSSType_Value: {
                     nsCSSValue* target = static_cast<nsCSSValue*>(prop);
                     if (target->GetUnit() == eCSSUnit_Null) {
                         const nsCSSValue *val = ValueAtCursor(cursor);
                         NS_ASSERTION(val->GetUnit() != eCSSUnit_Null, "oops");
-                        if ((iProp == eCSSProperty_background_image ||
-                             iProp == eCSSProperty_list_style_image) &&
-                            val->GetUnit() == eCSSUnit_URL) {
-                            val->StartImageLoad(aRuleData->mPresContext->Document());
+                        if (iProp == eCSSProperty_background_image ||
+                            iProp == eCSSProperty_list_style_image) {
+                            if (val->GetUnit() == eCSSUnit_URL) {
+                                val->StartImageLoad(
+                                    aRuleData->mPresContext->Document());
+                            }
+                        } else if (iProp == eCSSProperty_border_image) {
+                            if (val->GetUnit() == eCSSUnit_Array) {
+                                nsCSSValue::Array *array = val->GetArrayValue();
+                                if (array->Item(0).GetUnit() == eCSSUnit_URL) {
+                                    array->Item(0).StartImageLoad(
+                                        aRuleData->mPresContext->Document());
+                                }
+                            }
                         }
                         *target = *val;
                         if (iProp == eCSSProperty_font_family) {
                             // XXX Are there other things like this?
                             aRuleData->mFontData->mFamilyFromHTML = PR_FALSE;
                         }
                         else if (iProp == eCSSProperty_color ||
                                  iProp == eCSSProperty_background_color ||
--- a/layout/style/nsCSSDeclaration.cpp
+++ b/layout/style/nsCSSDeclaration.cpp
@@ -324,16 +324,24 @@ nsCSSDeclaration::AppendCSSValueToString
       case eCSSUnit_Counter:  aResult.AppendLiteral("counter(");  break;
       case eCSSUnit_Counters: aResult.AppendLiteral("counters("); break;
       default: break;
     }
 
     nsCSSValue::Array *array = aValue.GetArrayValue();
     PRBool mark = PR_FALSE;
     for (PRUint16 i = 0, i_end = array->Count(); i < i_end; ++i) {
+      if (aProperty == eCSSProperty_border_image && i >= 5) {
+        if (array->Item(i).GetUnit() == eCSSUnit_Null) {
+          continue;
+        }
+        if (i == 5) {
+          aResult.AppendLiteral(" /");
+        }
+      }
       if (mark && array->Item(i).GetUnit() != eCSSUnit_Null) {
         if (unit == eCSSUnit_Array)
           aResult.AppendLiteral(" ");
         else
           aResult.AppendLiteral(", ");
       }
       nsCSSProperty prop =
         ((eCSSUnit_Counter <= unit && unit <= eCSSUnit_Counters) &&
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -319,16 +319,17 @@ protected:
   PRBool ParseAzimuth(nsresult& aErrorCode, nsCSSValue& aValue);
   PRBool ParseBackground(nsresult& aErrorCode);
   PRBool ParseBackgroundPosition(nsresult& aErrorCode);
   PRBool ParseBackgroundPositionValues(nsresult& aErrorCode);
   PRBool ParseBorderColor(nsresult& aErrorCode);
   PRBool ParseBorderColors(nsresult& aErrorCode,
                            nsCSSValueList** aResult,
                            nsCSSProperty aProperty);
+  PRBool ParseBorderImage(nsresult& aErrorCode);
   PRBool ParseBorderSpacing(nsresult& aErrorCode);
   PRBool ParseBorderSide(nsresult& aErrorCode,
                          const nsCSSProperty aPropIDs[],
                          PRBool aSetAllSides);
   PRBool ParseDirectionalBorderSide(nsresult& aErrorCode,
                                     const nsCSSProperty aPropIDs[],
                                     PRInt32 aSourceType);
   PRBool ParseBorderStyle(nsresult& aErrorCode);
@@ -4434,16 +4435,18 @@ PRBool CSSParserImpl::ParseProperty(nsre
   case eCSSProperty_border_right_colors:
     return ParseBorderColors(aErrorCode,
                              &mTempData.mMargin.mBorderColors.mRight,
                              aPropID);
   case eCSSProperty_border_top_colors:
     return ParseBorderColors(aErrorCode,
                              &mTempData.mMargin.mBorderColors.mTop,
                              aPropID);
+  case eCSSProperty_border_image:
+    return ParseBorderImage(aErrorCode);
   case eCSSProperty_border_width:
     return ParseBorderWidth(aErrorCode);
   case eCSSProperty_border_end_color:
     return ParseDirectionalBoxProperty(aErrorCode, 
                                        eCSSProperty_border_end_color,
                                        NS_BOXPROP_SOURCE_LOGICAL);
   case eCSSProperty_border_left_color:
     return ParseDirectionalBoxProperty(aErrorCode, 
@@ -4647,16 +4650,17 @@ PRBool CSSParserImpl::ParseSingleValuePr
 {
   switch (aPropID) {
   case eCSSProperty_UNKNOWN:
   case eCSSProperty_background:
   case eCSSProperty_background_position:
   case eCSSProperty_border:
   case eCSSProperty_border_color:
   case eCSSProperty_border_bottom_colors:
+  case eCSSProperty_border_image:
   case eCSSProperty_border_left_colors:
   case eCSSProperty_border_right_colors:
   case eCSSProperty_border_end_color:
   case eCSSProperty_border_left_color:
   case eCSSProperty_border_right_color:
   case eCSSProperty_border_start_color:
   case eCSSProperty_border_end_style:
   case eCSSProperty_border_left_style:
@@ -5484,16 +5488,103 @@ PRBool CSSParserImpl::ParseBorderColor(n
   };
 
   // do this now, in case 4 values weren't specified
   InitBoxPropsAsPhysical(kBorderColorSources);
   return ParseBoxProperties(aErrorCode, mTempData.mMargin.mBorderColor,
                             kBorderColorIDs);
 }
 
+PRBool CSSParserImpl::ParseBorderImage(nsresult& aErrorCode)
+{
+  if (ParseVariant(aErrorCode, mTempData.mMargin.mBorderImage, 
+                   VARIANT_INHERIT | VARIANT_NONE, nsnull)) {
+    mTempData.SetPropertyBit(eCSSProperty_border_image);
+    return PR_TRUE;
+  }
+  
+  // <uri> [<number> | <percentage>]{1,4} [ / <border-width>{1,4} ]? [stretch | repeat | round]{0,2}
+  nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(11);
+  if (!arr) {
+    aErrorCode = NS_ERROR_OUT_OF_MEMORY;
+    return PR_FALSE;
+  }
+  
+  nsCSSValue& url = arr->Item(0);
+  nsCSSValue& splitTop = arr->Item(1);
+  nsCSSValue& splitRight = arr->Item(2);
+  nsCSSValue& splitBottom = arr->Item(3);
+  nsCSSValue& splitLeft = arr->Item(4);
+  nsCSSValue& borderWidthTop = arr->Item(5);
+  nsCSSValue& borderWidthRight = arr->Item(6);
+  nsCSSValue& borderWidthBottom = arr->Item(7);
+  nsCSSValue& borderWidthLeft = arr->Item(8);
+  nsCSSValue& horizontalKeyword = arr->Item(9);
+  nsCSSValue& verticalKeyword = arr->Item(10);
+  
+  // <uri>
+  if (!ParseVariant(aErrorCode, url, VARIANT_URL, nsnull)) {
+    return PR_FALSE;
+  }
+  
+  // [<number> | <percentage>]{1,4}
+  if (!ParsePositiveVariant(aErrorCode, splitTop,
+                            VARIANT_NUMBER | VARIANT_PERCENT, nsnull)) {
+    return PR_FALSE;
+  }
+  if (!ParsePositiveVariant(aErrorCode, splitRight,
+                            VARIANT_NUMBER | VARIANT_PERCENT, nsnull)) {
+    splitRight = splitTop;
+  }
+  if (!ParsePositiveVariant(aErrorCode, splitBottom,
+                            VARIANT_NUMBER | VARIANT_PERCENT, nsnull)) {
+    splitBottom = splitTop;
+  }
+  if (!ParsePositiveVariant(aErrorCode, splitLeft,
+                            VARIANT_NUMBER | VARIANT_PERCENT, nsnull)) {
+    splitLeft = splitRight;
+  }
+  
+  // [ / <border-width>{1,4} ]?
+  if (ExpectSymbol(aErrorCode, '/', PR_TRUE)) {
+    // if have '/', at least one value is required
+    if (!ParsePositiveVariant(aErrorCode, borderWidthTop,
+                              VARIANT_LENGTH, nsnull)) {
+      return PR_FALSE;
+    }
+    if (!ParsePositiveVariant(aErrorCode, borderWidthRight,
+                              VARIANT_LENGTH, nsnull)) {
+      borderWidthRight = borderWidthTop;
+    }
+    if (!ParsePositiveVariant(aErrorCode, borderWidthBottom,
+                              VARIANT_LENGTH, nsnull)) {
+      borderWidthBottom = borderWidthTop;
+    }
+    if (!ParsePositiveVariant(aErrorCode, borderWidthLeft,
+                              VARIANT_LENGTH, nsnull)) {
+      borderWidthLeft = borderWidthRight;
+    }
+  }
+  
+  // [stretch | repeat | round]{0,2}
+  // missing keywords are handled in nsRuleNode::ComputeBorderData()
+  if (ParseEnum(aErrorCode, horizontalKeyword, nsCSSProps::kBorderImageKTable)) {
+    ParseEnum(aErrorCode, verticalKeyword, nsCSSProps::kBorderImageKTable);
+  }
+  
+  if (!ExpectEndProperty(aErrorCode)) {
+    return PR_FALSE;
+  }
+  
+  mTempData.mMargin.mBorderImage.SetArrayValue(arr, eCSSUnit_Array);
+  mTempData.SetPropertyBit(eCSSProperty_border_image);
+  
+  return PR_TRUE;
+}
+
 PRBool CSSParserImpl::ParseBorderSpacing(nsresult& aErrorCode)
 {
   nsCSSValue  xValue;
   if (ParsePositiveVariant(aErrorCode, xValue, VARIANT_HL, nsnull)) {
     if (xValue.IsLengthUnit()) {
       // We have one length. Get the optional second length.
       nsCSSValue yValue;
       if (ParsePositiveVariant(aErrorCode, yValue, VARIANT_LENGTH, nsnull)) {
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -299,16 +299,17 @@ CSS_PROP_BORDER(border-end-color-value, 
 CSS_PROP_SHORTHAND(-moz-border-end-style, border_end_style, MozBorderEndStyle)
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_BORDER(border-end-style-value, border_end_style_value, X, Margin, mBorderEndStyle, eCSSType_Value, kBorderStyleKTable)
 #endif
 CSS_PROP_SHORTHAND(-moz-border-end-width, border_end_width, MozBorderEndWidth)
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_BORDER(border-end-width-value, border_end_width_value, X, Margin, mBorderEndWidth, eCSSType_Value, kBorderWidthKTable)
 #endif
+CSS_PROP_BORDER(-moz-border-image, border_image, MozBorderImage, Margin, mBorderImage, eCSSType_Value, kBorderImageKTable)
 CSS_PROP_SHORTHAND(border-left, border_left, BorderLeft)
 CSS_PROP_SHORTHAND(border-left-color, border_left_color, BorderLeftColor)
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_BORDER(border-left-color-value, border_left_color_value, X, Margin, mBorderColor.mLeft, eCSSType_Value, kBorderColorKTable)
 CSS_PROP_BORDER(border-left-color-ltr-source, border_left_color_ltr_source, X, Margin, mBorderLeftColorLTRSource, eCSSType_Value, kBoxPropSourceKTable)
 CSS_PROP_BORDER(border-left-color-rtl-source, border_left_color_rtl_source, X, Margin, mBorderLeftColorRTLSource, eCSSType_Value, kBoxPropSourceKTable)
 #endif
 CSS_PROP_BORDER(-moz-border-left-colors, border_left_colors, MozBorderLeftColors, Margin, mBorderColors.mLeft, eCSSType_ValueList, nsnull)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -347,16 +347,23 @@ const PRInt32 nsCSSProps::kBorderCollaps
 };
 
 const PRInt32 nsCSSProps::kBorderColorKTable[] = {
   eCSSKeyword_transparent, NS_STYLE_COLOR_TRANSPARENT,
   eCSSKeyword__moz_use_text_color, NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,
   eCSSKeyword_UNKNOWN,-1
 };
 
+const PRInt32 nsCSSProps::kBorderImageKTable[] = {
+  eCSSKeyword_stretch, NS_STYLE_BORDER_IMAGE_STRETCH,
+  eCSSKeyword_repeat, NS_STYLE_BORDER_IMAGE_REPEAT,
+  eCSSKeyword_round, NS_STYLE_BORDER_IMAGE_ROUND,
+  eCSSKeyword_UNKNOWN,-1
+};
+
 const PRInt32 nsCSSProps::kBorderStyleKTable[] = {
   eCSSKeyword_hidden, NS_STYLE_BORDER_STYLE_HIDDEN,
   eCSSKeyword_dotted, NS_STYLE_BORDER_STYLE_DOTTED,
   eCSSKeyword_dashed, NS_STYLE_BORDER_STYLE_DASHED,
   eCSSKeyword_solid,  NS_STYLE_BORDER_STYLE_SOLID,
   eCSSKeyword_double, NS_STYLE_BORDER_STYLE_DOUBLE,
   eCSSKeyword_groove, NS_STYLE_BORDER_STYLE_GROOVE,
   eCSSKeyword_ridge,  NS_STYLE_BORDER_STYLE_RIDGE,
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -117,16 +117,17 @@ public:
   static const PRInt32 kBackgroundClipKTable[];
   static const PRInt32 kBackgroundColorKTable[];
   static const PRInt32 kBackgroundInlinePolicyKTable[];
   static const PRInt32 kBackgroundOriginKTable[];
   static const PRInt32 kBackgroundPositionKTable[];
   static const PRInt32 kBackgroundRepeatKTable[];
   static const PRInt32 kBorderCollapseKTable[];
   static const PRInt32 kBorderColorKTable[];
+  static const PRInt32 kBorderImageKTable[];
   static const PRInt32 kBorderStyleKTable[];
   static const PRInt32 kBorderWidthKTable[];
   static const PRInt32 kBoxAlignKTable[];
   static const PRInt32 kBoxDirectionKTable[];
   static const PRInt32 kBoxOrientKTable[];
   static const PRInt32 kBoxPackKTable[];
 #ifdef MOZ_SVG
   static const PRInt32 kDominantBaselineKTable[];
--- a/layout/style/nsCSSStruct.h
+++ b/layout/style/nsCSSStruct.h
@@ -349,16 +349,17 @@ struct nsCSSMargin : public nsCSSStruct 
   nsCSSValue  mBorderRightStyleRTLSource;
   nsCSSRect   mBorderRadius;  // (extension)
   nsCSSValue  mOutlineWidth;
   nsCSSValue  mOutlineColor;
   nsCSSValue  mOutlineStyle;
   nsCSSValue  mOutlineOffset;
   nsCSSRect   mOutlineRadius; // (extension)
   nsCSSValue  mFloatEdge; // NEW
+  nsCSSValue  mBorderImage;
   nsCSSValueList* mBoxShadow;
 private:
   nsCSSMargin(const nsCSSMargin& aOther); // NOT IMPLEMENTED
 };
 
 struct nsRuleDataMargin : public nsCSSMargin {
   nsRuleDataMargin() {}
 private:
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -56,16 +56,17 @@
 
 #include "nsCSSProps.h"
 #include "nsCSSKeywords.h"
 #include "nsDOMCSSRect.h"
 #include "nsGkAtoms.h"
 #include "nsHTMLReflowState.h"
 #include "nsThemeConstants.h"
 #include "nsStyleUtil.h"
+#include "nsStyleStructInlines.h"
 
 #include "nsPresContext.h"
 #include "nsIDocument.h"
 
 #include "nsCSSPseudoElements.h"
 #include "nsStyleSet.h"
 #include "imgIRequest.h"
 #include "nsInspectorCSSUtils.h"
@@ -2169,16 +2170,103 @@ nsComputedDOMStyle::GetBoxSizing(nsIDOMC
     nsCSSProps::ValueToKeyword(GetStylePosition()->mBoxSizing,
                                nsCSSProps::kBoxSizingKTable);
   val->SetIdent(boxSizingIdent);
 
   return CallQueryInterface(val, aValue);
 }
 
 nsresult
+nsComputedDOMStyle::GetBorderImage(nsIDOMCSSValue** aValue)
+{
+  const nsStyleBorder* border = GetStyleBorder();
+  
+  // none
+  if (!border->GetBorderImage()) {
+    nsROCSSPrimitiveValue *valNone = GetROCSSPrimitiveValue();
+    NS_ENSURE_TRUE(valNone, NS_ERROR_OUT_OF_MEMORY);
+    valNone->SetIdent(nsGkAtoms::none);
+    return CallQueryInterface(valNone, aValue);
+  }
+  
+  nsDOMCSSValueList *valueList = GetROCSSValueList(PR_FALSE);
+  NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY);
+  
+  // uri
+  nsROCSSPrimitiveValue *valURI = GetROCSSPrimitiveValue();
+  if (!valURI || !valueList->AppendCSSValue(valURI)) {
+    delete valURI;
+    delete valueList;
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  nsCOMPtr<nsIURI> uri;
+  border->GetBorderImage()->GetURI(getter_AddRefs(uri));
+  valURI->SetURI(uri);
+  
+  // four split numbers
+  NS_FOR_CSS_SIDES(side) {
+    nsROCSSPrimitiveValue *valSplit = GetROCSSPrimitiveValue();
+    if (!valSplit || !valueList->AppendCSSValue(valSplit)) {
+      delete valSplit;
+      delete valueList;
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    SetValueToCoord(valSplit, border->mBorderImageSplit.Get(side), nsnull,
+                    nsnull);
+  }
+  
+  // copy of border-width
+  if (border->mHaveBorderImageWidth) {
+    nsROCSSPrimitiveValue *slash = GetROCSSPrimitiveValue();
+    if (!slash || !valueList->AppendCSSValue(slash)) {
+      delete slash;
+      delete valueList;
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    slash->SetString(NS_LITERAL_STRING("/"));
+    NS_FOR_CSS_SIDES(side) {
+      nsROCSSPrimitiveValue *borderWidth = GetROCSSPrimitiveValue();
+      if (!borderWidth || !valueList->AppendCSSValue(borderWidth)) {
+        delete borderWidth;
+        delete valueList;
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+      nscoord width = GetStyleBorder()->mBorderImageWidth.side(side);
+      borderWidth->SetAppUnits(width);
+    }
+  }
+  
+  // first keyword
+  nsROCSSPrimitiveValue *keyword = GetROCSSPrimitiveValue();
+  if (!keyword || !valueList->AppendCSSValue(keyword)) {
+    delete keyword;
+    delete valueList;
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  const nsAFlatCString& borderImageIdent =
+            nsCSSProps::ValueToKeyword(GetStyleBorder()->mBorderImageHFill,
+                                       nsCSSProps::kBorderImageKTable);
+  keyword->SetIdent(borderImageIdent);
+  
+  // second keyword
+  nsROCSSPrimitiveValue *keyword2 = GetROCSSPrimitiveValue();
+  if (!keyword2 || !valueList->AppendCSSValue(keyword2)) {
+    delete keyword2;
+    delete valueList;
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  const nsAFlatCString& borderImageIdent2 =
+            nsCSSProps::ValueToKeyword(GetStyleBorder()->mBorderImageVFill,
+                                       nsCSSProps::kBorderImageKTable);
+  keyword2->SetIdent(borderImageIdent2);
+  
+  return CallQueryInterface(valueList, aValue);
+}
+
+nsresult
 nsComputedDOMStyle::GetFloatEdge(nsIDOMCSSValue** aValue)
 {
   nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
   NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
 
   const nsAFlatCString& floatEdgeIdent =
     nsCSSProps::ValueToKeyword(GetStyleBorder()->mFloatEdge,
                                nsCSSProps::kFloatEdgeKTable);
@@ -2961,17 +3049,17 @@ nsComputedDOMStyle::GetBorderWidthFor(PR
   nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
   NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
 
   nscoord width;
   if (mInnerFrame) {
     FlushPendingReflows();
     width = mInnerFrame->GetUsedBorder().side(aSide);
   } else {
-    width = GetStyleBorder()->GetBorderWidth(aSide);
+    width = GetStyleBorder()->GetActualBorderWidth(aSide);
   }
   val->SetAppUnits(width);
 
   return CallQueryInterface(val, aValue);
 }
 
 nsresult
 nsComputedDOMStyle::GetBorderColorFor(PRUint8 aSide, nsIDOMCSSValue** aValue)
@@ -3849,16 +3937,17 @@ nsComputedDOMStyle::GetQueryableProperty
     \* ******************************* */
 
     COMPUTED_STYLE_MAP_ENTRY(appearance,                    Appearance),
     COMPUTED_STYLE_MAP_ENTRY(_moz_background_clip,          BackgroundClip),
     COMPUTED_STYLE_MAP_ENTRY(_moz_background_inline_policy, BackgroundInlinePolicy),
     COMPUTED_STYLE_MAP_ENTRY(_moz_background_origin,        BackgroundOrigin),
     COMPUTED_STYLE_MAP_ENTRY(binding,                       Binding),
     COMPUTED_STYLE_MAP_ENTRY(border_bottom_colors,          BorderBottomColors),
+    COMPUTED_STYLE_MAP_ENTRY(border_image,                  BorderImage),
     COMPUTED_STYLE_MAP_ENTRY(border_left_colors,            BorderLeftColors),
     COMPUTED_STYLE_MAP_ENTRY(border_right_colors,           BorderRightColors),
     COMPUTED_STYLE_MAP_ENTRY(border_top_colors,             BorderTopColors),
     COMPUTED_STYLE_MAP_ENTRY(_moz_border_radius_bottomLeft, BorderRadiusBottomLeft),
     COMPUTED_STYLE_MAP_ENTRY(_moz_border_radius_bottomRight,BorderRadiusBottomRight),
     COMPUTED_STYLE_MAP_ENTRY(_moz_border_radius_topLeft,    BorderRadiusTopLeft),
     COMPUTED_STYLE_MAP_ENTRY(_moz_border_radius_topRight,   BorderRadiusTopRight),
     COMPUTED_STYLE_MAP_ENTRY(box_align,                     BoxAlign),
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -193,16 +193,17 @@ private:
   nsresult GetBorderLeftColors(nsIDOMCSSValue** aValue);
   nsresult GetBorderRightColors(nsIDOMCSSValue** aValue);
   nsresult GetBorderTopColors(nsIDOMCSSValue** aValue);
   nsresult GetBorderRadiusBottomLeft(nsIDOMCSSValue** aValue);
   nsresult GetBorderRadiusBottomRight(nsIDOMCSSValue** aValue);
   nsresult GetBorderRadiusTopLeft(nsIDOMCSSValue** aValue);
   nsresult GetBorderRadiusTopRight(nsIDOMCSSValue** aValue);
   nsresult GetFloatEdge(nsIDOMCSSValue** aValue);
+  nsresult GetBorderImage(nsIDOMCSSValue** aValue);
 
   /* Box Shadow */
   nsresult GetBoxShadow(nsIDOMCSSValue** aValue);
 
   /* Margin Properties */
   nsresult GetMarginWidth(nsIDOMCSSValue** aValue);
   nsresult GetMarginTopWidth(nsIDOMCSSValue** aValue);
   nsresult GetMarginBottomWidth(nsIDOMCSSValue** aValue);
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -63,16 +63,17 @@
 #include "nsStyleContext.h"
 #include "nsStyleSet.h"
 #include "nsSize.h"
 #include "imgIRequest.h"
 #include "nsRuleData.h"
 #include "nsILanguageAtomService.h"
 #include "nsIStyleRule.h"
 #include "nsBidiUtils.h"
+#include "nsStyleStructInlines.h"
 
 /*
  * For storage of an |nsRuleNode|'s children in a PLDHashTable.
  */
 
 struct ChildrenHashEntry : public PLDHashEntryHdr {
   // key is |mRuleNode->GetKey()|
   nsRuleNode *mRuleNode;
@@ -3766,22 +3767,27 @@ nsRuleNode::ComputeBorderData(void* aSta
       // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
       else if (SetCoord(value, coord, nsStyleCoord(), SETCOORD_LENGTH,
                         aContext, mPresContext, inherited)) {
         NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
         border->SetBorderWidth(side, coord.GetCoordValue());
       }
       else if (eCSSUnit_Inherit == value.GetUnit()) {
         inherited = PR_TRUE;
-        border->SetBorderWidth(side, parentBorder->GetBorderWidth(side));
+        border->SetBorderWidth(side,
+                               parentBorder->GetComputedBorder().side(side));
       }
       else if (eCSSUnit_Initial == value.GetUnit()) {
         border->SetBorderWidth(side,
           (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
       }
+      else {
+        NS_ASSERTION(eCSSUnit_Null == value.GetUnit(),
+                     "missing case handling border width");
+      }
     }
   }
 
   // border-style, border-*-style: enum, none, inherit
   nsCSSRect ourStyle(marginData.mBorderStyle);
   AdjustLogicalBoxProp(aContext,
                        marginData.mBorderLeftStyleLTRSource,
                        marginData.mBorderLeftStyleRTLSource,
@@ -3908,16 +3914,88 @@ nsRuleNode::ComputeBorderData(void* aSta
     border->mFloatEdge = marginData.mFloatEdge.GetIntValue();
   else if (eCSSUnit_Inherit == marginData.mFloatEdge.GetUnit()) {
     inherited = PR_TRUE;
     border->mFloatEdge = parentBorder->mFloatEdge;
   }
   else if (eCSSUnit_Initial == marginData.mFloatEdge.GetUnit()) {
     border->mFloatEdge = NS_STYLE_FLOAT_EDGE_CONTENT;
   }
+  
+  // border-image
+  if (eCSSUnit_Array == marginData.mBorderImage.GetUnit()) {
+    nsCSSValue::Array *arr = marginData.mBorderImage.GetArrayValue();
+    
+    // the image
+    if (eCSSUnit_Image == arr->Item(0).GetUnit()) {
+      border->SetBorderImage(arr->Item(0).GetImageValue());
+    }
+    
+    // the numbers saying where to split the image
+    NS_FOR_CSS_SIDES(side) {
+      // an uninitialized parentCoord is ok because I'm not passing SETCOORD_INHERIT
+      if (SetCoord(arr->Item(1 + side), coord, nsStyleCoord(),
+                   SETCOORD_FACTOR | SETCOORD_PERCENT, aContext,
+                   mPresContext, inherited)) {
+        border->mBorderImageSplit.Set(side, coord);
+      }
+    }
+    
+    // possible replacement for border-width
+    // if have one - have all four (see CSSParserImpl::ParseBorderImage())
+    if (eCSSUnit_Null != arr->Item(5).GetUnit()) {
+      NS_FOR_CSS_SIDES(side) {
+        // an uninitialized parentCoord is ok because I'm not passing SETCOORD_INHERIT
+        if (!SetCoord(arr->Item(5 + side), coord, nsStyleCoord(),
+                      SETCOORD_LENGTH, aContext, mPresContext, inherited)) {
+          NS_NOTREACHED("SetCoord for border-width replacement from border-image failed");
+        }
+        if (coord.GetUnit() == eStyleUnit_Coord) {
+          border->SetBorderImageWidthOverride(side, coord.GetCoordValue());
+        } else {
+          NS_WARNING("a border-width replacement from border-image "
+                     "has a unit that's not eStyleUnit_Coord");
+          border->SetBorderImageWidthOverride(side, 0);
+        }
+      }
+      border->mHaveBorderImageWidth = PR_TRUE;
+    } else {
+      border->mHaveBorderImageWidth = PR_FALSE;
+    }
+    
+    // stretch/round/repeat keywords
+    if (eCSSUnit_Null == arr->Item(9).GetUnit()) {
+      // default, both horizontal and vertical are stretch
+      border->mBorderImageHFill = NS_STYLE_BORDER_IMAGE_STRETCH;
+      border->mBorderImageVFill = NS_STYLE_BORDER_IMAGE_STRETCH;
+    } else {
+      // have horizontal value
+      border->mBorderImageHFill = arr->Item(9).GetIntValue();
+      if (eCSSUnit_Null == arr->Item(10).GetUnit()) {
+        // vertical same as horizontal
+        border->mBorderImageVFill = border->mBorderImageHFill;
+      } else {
+        // have vertical value
+        border->mBorderImageVFill = arr->Item(10).GetIntValue();
+      }
+    }
+  } else if (eCSSUnit_None == marginData.mBorderImage.GetUnit() ||
+             eCSSUnit_Initial == marginData.mBorderImage.GetUnit()) {
+    border->mHaveBorderImageWidth = PR_FALSE;
+    border->SetBorderImage(nsnull);
+  } else if (eCSSUnit_Inherit == marginData.mBorderImage.GetUnit()) {
+    NS_FOR_CSS_SIDES(side) {
+      border->SetBorderImageWidthOverride(side, parentBorder->mBorderImageWidth.side(side));
+    }
+    border->mBorderImageSplit = parentBorder->mBorderImageSplit;
+    border->mBorderImageHFill = parentBorder->mBorderImageHFill;
+    border->mBorderImageVFill = parentBorder->mBorderImageVFill;
+    border->mHaveBorderImageWidth = parentBorder->mHaveBorderImageWidth;
+    border->SetBorderImage(parentBorder->GetBorderImage());
+  }
 
   COMPUTE_END_RESET(Border, border)
 }
   
 const void*
 nsRuleNode::ComputePaddingData(void* aStartStruct,
                                const nsRuleDataStruct& aData, 
                                nsStyleContext* aContext, 
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -639,20 +639,20 @@ void nsStyleContext::DumpRegressionData(
   
   const nsStyleBorder* border = GetStyleBorder();
 #ifdef NS_COORD_IS_FLOAT
   const char format [] = "top: %ftw right: %ftw bottom: %ftw left: %ftw";
 #else
   const char format [] = "top: %dtw right: %dtw bottom: %dtw left: %dtw";
 #endif
   nsPrintfCString output(format,
-                         border->GetBorderWidth(NS_SIDE_TOP),
-                         border->GetBorderWidth(NS_SIDE_RIGHT),
-                         border->GetBorderWidth(NS_SIDE_BOTTOM),
-                         border->GetBorderWidth(NS_SIDE_LEFT));
+                         border->GetActualBorderWidth(NS_SIDE_TOP),
+                         border->GetActualBorderWidth(NS_SIDE_RIGHT),
+                         border->GetActualBorderWidth(NS_SIDE_BOTTOM),
+                         border->GetActualBorderWidth(NS_SIDE_LEFT));
   fprintf(out, "%s ", output.get());
   border->mBorderRadius.ToString(str);
   fprintf(out, "%s ", NS_ConvertUTF16toUTF8(str).get());
   
   const nsStyleOutline* outline = GetStyleOutline();
   outline->mOutlineRadius.ToString(str);
   fprintf(out, "%s ", NS_ConvertUTF16toUTF8(str).get());
   outline->mOutlineWidth.ToString(str);
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -39,16 +39,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * structs that contain the data provided by nsStyleContext, the
  * internal API for computed style data for an element
  */
 
 #include "nsStyleStruct.h"
+#include "nsStyleStructInlines.h"
 #include "nsStyleConsts.h"
 #include "nsThemeConstants.h"
 #include "nsString.h"
 #include "nsPresContext.h"
 #include "nsIDeviceContext.h"
 #include "nsIStyleRule.h"
 #include "nsCRT.h"
 
@@ -348,17 +349,19 @@ nsChangeHint nsStylePadding::CalcDiffere
 /* static */
 nsChangeHint nsStylePadding::MaxDifference()
 {
   return NS_STYLE_HINT_REFLOW;
 }
 #endif
 
 nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext)
-  : mActualBorder(0, 0, 0, 0)
+  : mHaveBorderImageWidth(PR_FALSE),
+    mComputedBorder(0, 0, 0, 0),
+    mBorderImage(nsnull)
 {
   nscoord medium =
     (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
   NS_FOR_CSS_SIDES(side) {
     mBorder.side(side) = medium;
     mBorderStyle[side] = NS_STYLE_BORDER_STYLE_NONE | BORDER_COLOR_FOREGROUND;
     mBorderColor[side] = NS_RGB(0, 0, 0);
     mBorderRadius.Set(side, nsStyleCoord(0));
@@ -368,22 +371,28 @@ nsStyleBorder::nsStyleBorder(nsPresConte
   mBoxShadow = nsnull;
 
   mFloatEdge = NS_STYLE_FLOAT_EDGE_CONTENT;
 
   mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
 }
 
 nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
-  : mActualBorder(aSrc.mActualBorder),
-    mTwipsPerPixel(aSrc.mTwipsPerPixel),
+  : mBorderRadius(aSrc.mBorderRadius),
+    mBorderImageSplit(aSrc.mBorderImageSplit),
+    mFloatEdge(aSrc.mFloatEdge),
+    mBorderImageHFill(aSrc.mBorderImageHFill),
+    mBorderImageVFill(aSrc.mBorderImageVFill),
+    mBoxShadow(aSrc.mBoxShadow),
+    mHaveBorderImageWidth(aSrc.mHaveBorderImageWidth),
+    mBorderImageWidth(aSrc.mBorderImageWidth),
+    mComputedBorder(aSrc.mComputedBorder),
     mBorder(aSrc.mBorder),
-    mBorderRadius(aSrc.mBorderRadius),
-    mFloatEdge(aSrc.mFloatEdge),
-    mBoxShadow(aSrc.mBoxShadow)
+    mBorderImage(aSrc.mBorderImage),
+    mTwipsPerPixel(aSrc.mTwipsPerPixel)
 {
   mBorderColors = nsnull;
   if (aSrc.mBorderColors) {
     EnsureBorderColors();
     for (PRInt32 i = 0; i < 4; i++)
       if (aSrc.mBorderColors[i])
         mBorderColors[i] = aSrc.mBorderColors[i]->CopyColors();
       else
@@ -391,16 +400,25 @@ nsStyleBorder::nsStyleBorder(const nsSty
   }
 
   NS_FOR_CSS_SIDES(side) {
     mBorderStyle[side] = aSrc.mBorderStyle[side];
     mBorderColor[side] = aSrc.mBorderColor[side];
   }
 }
 
+nsStyleBorder::~nsStyleBorder()
+{
+  if (mBorderColors) {
+    for (PRInt32 i = 0; i < 4; i++)
+      delete mBorderColors[i];
+    delete [] mBorderColors;
+  }
+}
+
 void* 
 nsStyleBorder::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
   void* result = aContext->AllocateFromShell(sz);
   if (result)
     memset(result, 0, sz);
   return result;
 }
   
@@ -411,17 +429,17 @@ nsStyleBorder::Destroy(nsPresContext* aC
 }
 
 
 nsChangeHint nsStyleBorder::CalcDifference(const nsStyleBorder& aOther) const
 {
   // Note that differences in mBorder don't affect rendering (which should only
   // use mComputedBorder), so don't need to be tested for here.
   if (mTwipsPerPixel == aOther.mTwipsPerPixel &&
-      mActualBorder == aOther.mActualBorder && 
+      mComputedBorder == aOther.mComputedBorder && 
       mFloatEdge == aOther.mFloatEdge) {
     // Note that mBorderStyle stores not only the border style but also
     // color-related flags.  Given that we've already done an mComputedBorder
     // comparison, border-style differences can only lead to a VISUAL hint.  So
     // it's OK to just compare the values directly -- if either the actual
     // style or the color flags differ we want to repaint.
     NS_FOR_CSS_SIDES(ix) {
       if (mBorderStyle[ix] != aOther.mBorderStyle[ix] || 
@@ -457,16 +475,35 @@ nsChangeHint nsStyleBorder::CalcDifferen
 #ifdef DEBUG
 /* static */
 nsChangeHint nsStyleBorder::MaxDifference()
 {
   return NS_STYLE_HINT_REFLOW;
 }
 #endif
 
+PRBool
+nsStyleBorder::ImageBorderDiffers() const
+{
+  return mComputedBorder !=
+           (mHaveBorderImageWidth ? mBorderImageWidth : mBorder);
+}
+
+const nsMargin&
+nsStyleBorder::GetActualBorder() const
+{
+  if (IsBorderImageLoaded())
+    if (mHaveBorderImageWidth)
+      return mBorderImageWidth;
+    else
+      return mBorder;
+  else
+    return mComputedBorder;
+}
+
 nsStyleOutline::nsStyleOutline(nsPresContext* aPresContext)
 {
   // spacing values not inherited
   nsStyleCoord zero(0);
   NS_FOR_CSS_SIDES(side) {
     mOutlineRadius.Set(side, zero);
   }
 
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -17,16 +17,17 @@
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Mats Palmgren <mats.palmgren@bredband.net>
  *   Masayuki Nakano <masayuki@d-toybox.com>
+ *   Rob Arnold <robarnold@mozilla.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
@@ -187,16 +188,17 @@ struct nsStyleBackground {
     return (mBackgroundFlags &
             (NS_STYLE_BG_COLOR_TRANSPARENT | NS_STYLE_BG_IMAGE_NONE)) ==
             (NS_STYLE_BG_COLOR_TRANSPARENT | NS_STYLE_BG_IMAGE_NONE);
   }
 
   // We have to take slower codepaths for fixed background attachment,
   // but we don't want to do that when there's no image.
   // Not inline because it uses an nsCOMPtr<imgIRequest>
+  // FIXME: Should be in nsStyleStructInlines.h.
   PRBool HasFixedBackground() const;
 };
 
 #define BORDER_COLOR_TRANSPARENT  0x40
 #define BORDER_COLOR_FOREGROUND   0x20
 #define OUTLINE_COLOR_INITIAL     0x80
 // TRANSPARENT | FOREGROUND | INITIAL(OUTLINE)
 #define BORDER_COLOR_SPECIAL      0xE0
@@ -394,37 +396,37 @@ class nsCSSShadowArray {
 #define NS_ROUND_OFFSET_TO_PIXELS(l,tpp) \
   (((l) == 0) ? 0 : \
     ((l) > 0) ? PR_MAX( (tpp), ((l) + ((tpp) / 2)) / (tpp) * (tpp)) : \
                 PR_MIN(-(tpp), ((l) - ((tpp) / 2)) / (tpp) * (tpp)))
 
 struct nsStyleBorder {
   nsStyleBorder(nsPresContext* aContext);
   nsStyleBorder(const nsStyleBorder& aBorder);
-  ~nsStyleBorder(void) {
-    if (mBorderColors) {
-      for (PRInt32 i = 0; i < 4; i++)
-        delete mBorderColors[i];
-      delete []mBorderColors;
-    }
-  }
+  ~nsStyleBorder();
 
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW;
   void Destroy(nsPresContext* aContext);
 
   nsChangeHint CalcDifference(const nsStyleBorder& aOther) const;
 #ifdef DEBUG
   static nsChangeHint MaxDifference();
 #endif
+  PRBool ImageBorderDiffers() const;
  
   nsStyleSides  mBorderRadius;    // [reset] length, percent
+  nsStyleSides  mBorderImageSplit; // [reset] integer, percent
   PRUint8       mFloatEdge;       // [reset] see nsStyleConsts.h
+  PRUint8       mBorderImageHFill; // [reset]
+  PRUint8       mBorderImageVFill; // [reset]
   nsBorderColors** mBorderColors; // [reset] multiple levels of color for a border.
   nsRefPtr<nsCSSShadowArray> mBoxShadow; // [reset] NULL for 'none'
-
+  PRBool        mHaveBorderImageWidth; // [reset]
+  nsMargin      mBorderImageWidth; // [reset]
+  
   void EnsureBorderColors() {
     if (!mBorderColors) {
       mBorderColors = new nsBorderColors*[4];
       if (mBorderColors)
         for (PRInt32 i = 0; i < 4; i++)
           mBorderColors[i] = nsnull;
     }
   }
@@ -433,64 +435,62 @@ struct nsStyleBorder {
     if (mBorderColors[aSide]) {
       delete mBorderColors[aSide];
       mBorderColors[aSide] = nsnull;
     }
   }
 
   // Return whether aStyle is a visible style.  Invisible styles cause
   // the relevant computed border width to be 0.
-  static PRBool IsVisibleStyle(PRUint8 aStyle) {
-    return aStyle != NS_STYLE_BORDER_STYLE_NONE &&
-           aStyle != NS_STYLE_BORDER_STYLE_HIDDEN;
-  }
+  // Note that this does *not* consider the effects of 'border-image':
+  // if border-style is none, but there is a loaded border image,
+  // HasVisibleStyle will be false even though there *is* a border.
+  // Defined in nsStyleStructInlines.h.
+  inline PRBool HasVisibleStyle(PRUint8 aSide);
 
   // aBorderWidth is in twips
-  void SetBorderWidth(PRUint8 aSide, nscoord aBorderWidth)
+  // Defined in nsStyleStructInlines.h.
+  inline void SetBorderWidth(PRUint8 aSide, nscoord aBorderWidth);
+  inline void SetBorderImageWidthOverride(PRUint8 aSide, nscoord aBorderWidth);
+
+  // Get the actual border, in twips.  (If there is no border-image
+  // loaded, this is the same as GetComputedBorder.  If there is a
+  // border-image loaded, it uses the border-image width overrides if
+  // present, and otherwise mBorder, which is GetComputedBorder without
+  // considering border-style: none.)
+  const nsMargin& GetActualBorder() const;
+  
+  // Get the computed border (plus rounding).  This does consider the
+  // effects of 'border-style: none', but does not consider
+  // 'border-image'.
+  const nsMargin& GetComputedBorder() const
   {
-    mBorder.side(aSide) = aBorderWidth;
-    if (IsVisibleStyle(GetBorderStyle(aSide))) {
-      mActualBorder.side(aSide) =
-        NS_ROUND_BORDER_TO_PIXELS(aBorderWidth, mTwipsPerPixel);
-    }
-  }
-
-  // Get the actual border, in twips.
-  const nsMargin& GetBorder() const
-  {
-    return mActualBorder;
+    return mComputedBorder;
   }
 
   // Get the actual border width for a particular side, in twips.  Note that
   // this is zero if and only if there is no border to be painted for this
   // side.  That is, this value takes into account the border style and the
   // value is rounded to the nearest device pixel by NS_ROUND_BORDER_TO_PIXELS.
-  nscoord GetBorderWidth(PRUint8 aSide) const
+  nscoord GetActualBorderWidth(PRUint8 aSide) const
   {
-    return mActualBorder.side(aSide);
+    return GetActualBorder().side(aSide);
   }
 
   PRUint8 GetBorderStyle(PRUint8 aSide) const
   {
     NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); 
     return (mBorderStyle[aSide] & BORDER_STYLE_MASK); 
   }
 
-  void SetBorderStyle(PRUint8 aSide, PRUint8 aStyle)
-  {
-    NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); 
-    mBorderStyle[aSide] &= ~BORDER_STYLE_MASK; 
-    mBorderStyle[aSide] |= (aStyle & BORDER_STYLE_MASK);
-    if (IsVisibleStyle(aStyle)) {
-      mActualBorder.side(aSide) =
-        NS_ROUND_BORDER_TO_PIXELS(mBorder.side(aSide), mTwipsPerPixel);
-    } else {
-      mActualBorder.side(aSide) = 0;
-    }
-  }
+  // Defined in nsStyleStructInlines.h.
+  inline void RebuildActualBorderSide(PRUint8 aSide);
+  inline void SetBorderStyle(PRUint8 aSide, PRUint8 aStyle);
+  inline void RebuildActualBorder();
+  inline PRBool IsBorderImageLoaded() const;
 
   void GetBorderColor(PRUint8 aSide, nscolor& aColor,
                       PRBool& aTransparent, PRBool& aForeground) const
   {
     aTransparent = aForeground = PR_FALSE;
     NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); 
     if ((mBorderStyle[aSide] & BORDER_COLOR_SPECIAL) == 0)
       aColor = mBorderColor[aSide]; 
@@ -502,16 +502,20 @@ struct nsStyleBorder {
 
   void SetBorderColor(PRUint8 aSide, nscolor aColor) 
   {
     NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); 
     mBorderColor[aSide] = aColor; 
     mBorderStyle[aSide] &= ~BORDER_COLOR_SPECIAL;
   }
 
+  // These are defined in nsStyleStructInlines.h
+  inline void SetBorderImage(imgIRequest* aImage);
+  inline imgIRequest* GetBorderImage() const;
+
   void GetCompositeColors(PRInt32 aIndex, nsBorderColors** aColors) const
   {
     if (!mBorderColors)
       *aColors = nsnull;
     else
       *aColors = mBorderColors[aIndex];
   }
 
@@ -540,36 +544,44 @@ struct nsStyleBorder {
   void SetBorderToForeground(PRUint8 aSide)
   {
     NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); 
     mBorderStyle[aSide] &= ~BORDER_COLOR_SPECIAL;
     mBorderStyle[aSide] |= BORDER_COLOR_FOREGROUND; 
   }
 
 protected:
-  // mActualBorder holds the CSS2.1 actual border-width values.  In
+  // mComputedBorder holds the CSS2.1 computed border-width values.  In
   // particular, these widths take into account the border-style for the
-  // relevant side and the values are rounded to the nearest device pixel.
-  nsMargin      mActualBorder;
+  // relevant side and the values are rounded to the nearest device
+  // pixel.  They are also rounded (which is not part of the definition
+  // of computed values).  However, they do *not* take into account the
+  // presence of border-image.  See GetActualBorder above for how to
+  // really get the actual border.
+  nsMargin      mComputedBorder;
 
   // mBorder holds the nscoord values for the border widths as they would be if
   // all the border-style values were visible (not hidden or none).  This
-  // member exists solely so that when we create structs using the copy
+  // member exists so that when we create structs using the copy
   // constructor during style resolution the new structs will know what the
   // specified values of the border were in case they have more specific rules
   // setting the border style.  Note that this isn't quite the CSS specified
   // value, since this has had the enumerated border widths converted to
   // lengths, and all lengths converted to twips.  But it's not quite the
-  // computed value either.
+  // computed value either. The values are rounded to the nearest device pixel
+  // We also use these values when we have a loaded border-image that
+  // does not have width overrides.
   nsMargin      mBorder;
 
   PRUint8       mBorderStyle[4];  // [reset] See nsStyleConsts.h
   nscolor       mBorderColor[4];  // [reset] the colors to use for a simple border.  not used
                                   // if -moz-border-colors is specified
 
+  nsCOMPtr<imgIRequest> mBorderImage; // [reset]
+
   nscoord       mTwipsPerPixel;
 };
 
 
 struct nsStyleOutline {
   nsStyleOutline(nsPresContext* aPresContext);
   nsStyleOutline(const nsStyleOutline& aOutline);
   ~nsStyleOutline(void) {}
new file mode 100644
--- /dev/null
+++ b/layout/style/nsStyleStructInlines.h
@@ -0,0 +1,115 @@
+/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
+/* ***** 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 nsStyleStructInlines.h.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation (original author)
+ *   Rob Arnold <robarnold@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either 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 ***** */
+
+/*
+ * Inline methods that belong in nsStyleStruct.h, except that they
+ * require more headers.
+ */
+
+#ifndef nsStyleStructInlines_h_
+#define nsStyleStructInlines_h_
+
+#include "nsStyleStruct.h"
+#include "imgIRequest.h"
+
+inline void
+nsStyleBorder::SetBorderImage(imgIRequest* aImage)
+{
+  mBorderImage = aImage;
+  RebuildActualBorder();
+}
+
+inline imgIRequest*
+nsStyleBorder::GetBorderImage() const
+{
+  return mBorderImage;
+}
+
+inline PRBool nsStyleBorder::HasVisibleStyle(PRUint8 aSide)
+{
+  PRUint8 style = GetBorderStyle(aSide);
+  return (style != NS_STYLE_BORDER_STYLE_NONE &&
+          style != NS_STYLE_BORDER_STYLE_HIDDEN);
+}
+
+inline void nsStyleBorder::SetBorderWidth(PRUint8 aSide, nscoord aBorderWidth)
+{
+  nscoord roundedWidth =
+    NS_ROUND_BORDER_TO_PIXELS(aBorderWidth, mTwipsPerPixel);
+  mBorder.side(aSide) = roundedWidth;
+  if (HasVisibleStyle(aSide))
+    mComputedBorder.side(aSide) = roundedWidth;
+}
+
+inline void nsStyleBorder::SetBorderImageWidthOverride(PRUint8 aSide,
+                                                       nscoord aBorderWidth)
+{
+  mBorderImageWidth.side(aSide) =
+    NS_ROUND_BORDER_TO_PIXELS(aBorderWidth, mTwipsPerPixel);
+}
+
+inline void nsStyleBorder::RebuildActualBorderSide(PRUint8 aSide)
+{
+  mComputedBorder.side(aSide) =
+    (HasVisibleStyle(aSide) ? mBorder.side(aSide) : 0);
+}
+
+inline void nsStyleBorder::SetBorderStyle(PRUint8 aSide, PRUint8 aStyle)
+{
+  NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); 
+  mBorderStyle[aSide] &= ~BORDER_STYLE_MASK; 
+  mBorderStyle[aSide] |= (aStyle & BORDER_STYLE_MASK);
+  RebuildActualBorderSide(aSide);
+}
+
+inline void nsStyleBorder::RebuildActualBorder()
+{
+  NS_FOR_CSS_SIDES(side) {
+    RebuildActualBorderSide(side);
+  }
+}
+
+inline PRBool nsStyleBorder::IsBorderImageLoaded() const
+{
+  PRUint32 status;
+  return mBorderImage &&
+         NS_SUCCEEDED(mBorderImage->GetImageStatus(&status)) &&
+         (status & imgIRequest::STATUS_FRAME_COMPLETE);
+}
+
+#endif /* !defined(nsStyleStructInlines_h_) */
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -144,16 +144,33 @@ var gCSSProperties = {
 		inherited: false,
 		type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
 		get_computed: logical_box_prop_get_computed,
 		prerequisites: { "-moz-border-end-style": "solid" },
 		initial_values: [ "medium", "3px" ],
 		other_values: [ "thin", "thick", "1px", "2em" ],
 		invalid_values: [ "5%" ]
 	},
+	"-moz-border-image": {
+		domProp: "MozBorderImage",
+		inherited: false,
+		type: CSS_TYPE_LONGHAND,
+		initial_values: [ "none" ],
+		other_values: [ "url('border.png') 27 27 27 27",
+		                "url('border.png') 27",
+		                "url('border.png') 27 27 27 27 repeat",
+		                "url('border.png') 27 27 27 27 / 1em",
+		                "url('border.png') 27 27 27 27 / 1em 1em 1em 1em repeat",
+		                "url('border.png') 27 27 27 27 / 1em 1em 1em 1em stretch round" ],
+		invalid_values: [ "url('border.png')",
+		                  "url('border.png') 27 27 27 27 27",
+		                  "url('border.png') 27 27 27 27 / 1em 1em 1em 1em 1em",
+		                  "url('border.png') / repeat",
+		                  "url('border.png') 27 27 27 27 /" ]
+	},
 	"-moz-border-left-colors": {
 		domProp: "MozBorderLeftColors",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "none" ],
 		other_values: [ "red green", "red #fc3", "#ff00cc", "currentColor", "blue currentColor orange currentColor" ],
 		invalid_values: [ "red none", "red inherit", "red, green" ]
 	},
--- a/layout/style/test/test_value_storage.html
+++ b/layout/style/test/test_value_storage.html
@@ -194,24 +194,24 @@ function test_property(property)
     var step1comps = [];
     if (test_computed && info.type != CSS_TYPE_TRUE_SHORTHAND)
       step1comp = gComputedStyle.getPropertyValue(property);
     if (test_computed && "subproperties" in info)
       for (idx in info.subproperties)
         step1comps.push(gComputedStyle.getPropertyValue(info.subproperties[idx]));
 
     func = xfail_accepted(property, value) ? todo_isnot : isnot;
-    func(step1val, "", "setting '" + value + "' on '" + property);
+    func(step1val, "", "setting '" + value + "' on '" + property + "'");
     if ("subproperties" in info)
       for (idx in info.subproperties) {
         var subprop = info.subproperties[idx];
         func = xfail_accepted_split(property, subprop, value)
                  ? todo_isnot : isnot;
         func(gDeclaration.getPropertyValue(subprop), "",
-             "setting '" + value + "' on '" + property);
+             "setting '" + value + "' on '" + property + "'");
       }
 
     // We don't care particularly about the whitespace or the placement of
     // semicolons, but for simplicity we'll test the current behavior.
     func = xfail_ser_val(property, value) ? todo_is : is;
     var expected_serialization = "";
     if (step1val != "")
       expected_serialization = property + ": " + step1val + ";";
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -1035,17 +1035,17 @@ NS_NewTableCellFrame(nsIPresShell*   aPr
     return new (aPresShell) nsBCTableCellFrame(aContext);
   else
     return new (aPresShell) nsTableCellFrame(aContext);
 }
 
 nsMargin* 
 nsTableCellFrame::GetBorderWidth(nsMargin&  aBorder) const
 {
-  aBorder = GetStyleBorder()->GetBorder();
+  aBorder = GetStyleBorder()->GetActualBorder();
   return &aBorder;
 }
 
 nsIAtom*
 nsTableCellFrame::GetType() const
 {
   return nsGkAtoms::tableCellFrame;
 }
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -2541,17 +2541,17 @@ static
 void GetSeparateModelBorderPadding(const nsHTMLReflowState* aReflowState,
                                    nsStyleContext&          aStyleContext,
                                    nsMargin&                aBorderPadding)
 {
   // XXXbz Either we _do_ have a reflow state and then we can use its
   // mComputedBorderPadding or we don't and then we get the padding
   // wrong!
   const nsStyleBorder* border = aStyleContext.GetStyleBorder();
-  aBorderPadding = border->GetBorder();
+  aBorderPadding = border->GetActualBorder();
   if (aReflowState) {
     aBorderPadding += aReflowState->mComputedPadding;
   }
 }
 
 nsMargin 
 nsTableFrame::GetChildAreaOffset(const nsHTMLReflowState* aReflowState) const
 {
@@ -4643,17 +4643,17 @@ GetColorAndStyle(const nsIFrame*  aFrame
   if(!aTableIsLTR) { // revert the directions
     if (NS_SIDE_RIGHT == aSide) {
       aSide = NS_SIDE_LEFT;
     }
     else if (NS_SIDE_LEFT == aSide) {
       aSide = NS_SIDE_RIGHT;
     }
   }
-  width = styleData->GetBorderWidth(aSide);
+  width = styleData->GetActualBorderWidth(aSide);
   aWidth = nsPresContext::AppUnitsToIntCSSPixels(width);
 }
  
  
 /* BCCellBorder represents a border segment which can be either a horizontal
  * or a vertical segment. For each segment we need to know the color, width,
  * style, who owns it and how long it is in cellmap coordinates.
  * Ownership of these segments is  important to calculate which corners should
--- a/layout/xul/base/src/nsBox.cpp
+++ b/layout/xul/base/src/nsBox.cpp
@@ -350,17 +350,17 @@ nsBox::GetBorder(nsMargin& aMargin)
       aMargin.top = context->DevPixelsToAppUnits(margin.top);
       aMargin.right = context->DevPixelsToAppUnits(margin.right);
       aMargin.bottom = context->DevPixelsToAppUnits(margin.bottom);
       aMargin.left = context->DevPixelsToAppUnits(margin.left);
       return NS_OK;
     }
   }
 
-  aMargin = GetStyleBorder()->GetBorder();
+  aMargin = GetStyleBorder()->GetActualBorder();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBox::GetPadding(nsMargin& aMargin)
 {
   const nsStyleDisplay *disp = GetStyleDisplay();
--- a/layout/xul/base/src/nsBoxObject.cpp
+++ b/layout/xul/base/src/nsBoxObject.cpp
@@ -192,23 +192,23 @@ nsBoxObject::GetOffsetRect(nsRect& aRect
       // Add the parent's origin to our own to get to the
       // right coordinate system
       origin += next->GetPositionOfChildIgnoringScrolling(parent);
       parent = next;
     }
   
     // For the origin, add in the border for the frame
     const nsStyleBorder* border = frame->GetStyleBorder();
-    origin.x += border->GetBorderWidth(NS_SIDE_LEFT);
-    origin.y += border->GetBorderWidth(NS_SIDE_TOP);
+    origin.x += border->GetActualBorderWidth(NS_SIDE_LEFT);
+    origin.y += border->GetActualBorderWidth(NS_SIDE_TOP);
 
     // And subtract out the border for the parent
     const nsStyleBorder* parentBorder = parent->GetStyleBorder();
-    origin.x -= parentBorder->GetBorderWidth(NS_SIDE_LEFT);
-    origin.y -= parentBorder->GetBorderWidth(NS_SIDE_TOP);
+    origin.x -= parentBorder->GetActualBorderWidth(NS_SIDE_LEFT);
+    origin.y -= parentBorder->GetActualBorderWidth(NS_SIDE_TOP);
 
     aRect.x = nsPresContext::AppUnitsToIntCSSPixels(origin.x);
     aRect.y = nsPresContext::AppUnitsToIntCSSPixels(origin.y);
     
     // Get the union of all rectangles in this and continuation frames.
     // It doesn't really matter what we use as aRelativeTo here, since
     // we only care about the size. Using 'parent' might make things
     // a bit faster by speeding up the internal GetOffsetTo operations.
--- a/layout/xul/base/src/nsGroupBoxFrame.cpp
+++ b/layout/xul/base/src/nsGroupBoxFrame.cpp
@@ -146,17 +146,17 @@ nsGroupBoxFrame::BuildDisplayList(nsDisp
 }
 
 void
 nsGroupBoxFrame::PaintBorderBackground(nsIRenderingContext& aRenderingContext,
     nsPoint aPt, const nsRect& aDirtyRect) {
   PRIntn skipSides = 0;
   const nsStyleBorder* borderStyleData = GetStyleBorder();
   const nsStylePadding* paddingStyleData = GetStylePadding();
-  const nsMargin& border = borderStyleData->GetBorder();
+  const nsMargin& border = borderStyleData->GetActualBorder();
   nscoord yoff = 0;
   nsPresContext* presContext = PresContext();
 
   nsRect groupRect;
   nsIBox* groupBox = GetCaptionBox(presContext, groupRect);
 
   if (groupBox) {        
     // if the border is smaller than the legend. Move the border down
--- a/layout/xul/base/src/nsListBoxBodyFrame.cpp
+++ b/layout/xul/base/src/nsListBoxBodyFrame.cpp
@@ -771,17 +771,17 @@ nsListBoxBodyFrame::ComputeIntrinsicWidt
     styleContext = presContext->StyleSet()->
       ResolveStyleFor(firstRowContent, nsnull);
 
     nscoord width = 0;
     nsMargin margin(0,0,0,0);
 
     if (styleContext->GetStylePadding()->GetPadding(margin))
       width += margin.LeftRight();
-    width += styleContext->GetStyleBorder()->GetBorder().LeftRight();
+    width += styleContext->GetStyleBorder()->GetActualBorder().LeftRight();
     if (styleContext->GetStyleMargin()->GetMargin(margin))
       width += margin.LeftRight();
 
     nsIContent* listbox = mContent->GetBindingParent();
     NS_ENSURE_TRUE(listbox, largestWidth);
 
     PRUint32 childCount = listbox->GetChildCount();
 
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
@@ -190,17 +190,17 @@ nsTreeBodyFrame::Release(void)
 
 static void
 GetBorderPadding(nsStyleContext* aContext, nsMargin& aMargin)
 {
   aMargin.SizeTo(0, 0, 0, 0);
   if (!aContext->GetStylePadding()->GetPadding(aMargin)) {
     NS_NOTYETIMPLEMENTED("percentage padding");
   }
-  aMargin += aContext->GetStyleBorder()->GetBorder();
+  aMargin += aContext->GetStyleBorder()->GetActualBorder();
 }
 
 static void
 AdjustForBorderPadding(nsStyleContext* aContext, nsRect& aRect)
 {
   nsMargin borderPadding(0, 0, 0, 0);
   GetBorderPadding(aContext, borderPadding);
   aRect.Deflate(borderPadding);