Backing out bug 455364
authorRobert O'Callahan <robert@ocallahan.org>
Sat, 07 Feb 2009 23:38:22 +1300
changeset 24728 7d5ec02ef5ff04b98696b6996c8cfea38373a987
parent 24726 fc8d54ab29a6dfaadea8944aaa5b0a4001aa893c (current diff)
parent 24727 37b331bbc983793d308f232a4e7624c07d6275eb (diff)
child 24729 6ebf4afe67d22879596af8a2e35f5a4df43eb331
push idunknown
push userunknown
push dateunknown
bugs455364
milestone1.9.2a1pre
Backing out bug 455364
layout/reftests/border-image/center-scaling-1-ref.png
layout/reftests/border-image/center-scaling-1.html
layout/reftests/border-image/center-scaling-2-ref.png
layout/reftests/border-image/center-scaling-2.html
layout/reftests/border-image/center-scaling-3-ref.png
layout/reftests/border-image/center-scaling-3.html
layout/reftests/border-image/diamonds.png
layout/reftests/border-image/different-h-v-1.html
layout/reftests/border-image/different-h-v-2.html
layout/reftests/border-image/different-h-v-ref.html
layout/reftests/border-image/reticule.png
layout/reftests/border-image/solid-image-2a.html
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -261,27 +261,26 @@ protected:
   }
 };
 
 /* Local functions */
 static void DrawBorderImage(nsPresContext* aPresContext,
                             nsIRenderingContext& aRenderingContext,
                             nsIFrame* aForFrame,
                             const nsRect& aBorderArea,
-                            const nsStyleBorder& aBorderStyle,
-                            const nsRect& aDirtyRect);
+                            const nsStyleBorder& aBorderStyle);
 
-static void DrawBorderImageComponent(nsIRenderingContext& aRenderingContext,
-                                     nsIImage* aImage,
-                                     const nsRect& aDirtyRect,
-                                     const nsRect& aFill,
-                                     const nsIntRect& aSrc,
-                                     PRUint8 aHFill,
-                                     PRUint8 aVFill,
-                                     const nsSize& aUnitSize);
+static void DrawBorderImageSide(gfxContext *aThebesContext,
+                                nsIDeviceContext* aDeviceContext,
+                                imgIContainer* aImage,
+                                gfxRect& aDestRect,
+                                gfxSize aInterSize,
+                                gfxRect& aSourceRect,
+                                PRUint8 aHFillType,
+                                PRUint8 aVFillType);
 
 static nscolor MakeBevelColor(PRIntn whichSide, PRUint8 style,
                               nscolor aBackgroundColor,
                               nscolor aBorderColor);
 
 static gfxRect GetTextDecorationRectInternal(const gfxPoint& aPt,
                                              const gfxSize& aLineSize,
                                              const gfxFloat aAscent,
@@ -474,17 +473,17 @@ nsCSSRendering::PaintBorder(nsPresContex
   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, aDirtyRect);
+                    aBorderArea, aBorderStyle);
     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
@@ -1600,277 +1599,404 @@ nsCSSRendering::PaintBackgroundWithSC(ns
   }
   fillArea.IntersectRect(fillArea, bgClipArea);
 
   nsLayoutUtils::DrawImage(&aRenderingContext, image,
       destArea, fillArea, anchor + aBorderArea.TopLeft(), dirtyRect);
 }
 
 static void
-DrawBorderImage(nsPresContext*       aPresContext,
+DrawBorderImage(nsPresContext* aPresContext,
                 nsIRenderingContext& aRenderingContext,
-                nsIFrame*            aForFrame,
-                const nsRect&        aBorderArea,
-                const nsStyleBorder& aBorderStyle,
-                const nsRect&        aDirtyRect)
+                nsIFrame* aForFrame, const nsRect& aBorderArea,
+                const nsStyleBorder& aBorderStyle)
 {
-  if (aDirtyRect.IsEmpty())
-    return;
+    float percent;
+    nsStyleCoord borderImageSplit[4];
+    PRInt32 borderImageSplitInt[4];
+    nsMargin border;
+    gfxFloat borderTop, borderRight, borderBottom, borderLeft;
+    gfxFloat borderImageSplitGfx[4];
 
-  // Clone the image loader and set up animation notifications.
-  imgIRequest *req =
-    aPresContext->LoadBorderImage(aBorderStyle.GetBorderImage(), aForFrame);
-#ifdef DEBUG
-  {
-    PRUint32 status = imgIRequest::STATUS_ERROR;
-    if (req)
-      req->GetImageStatus(&status);
+    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));
 
-    NS_ASSERTION(req && (status & imgIRequest::STATUS_FRAME_COMPLETE),
-                 "no image to draw");
-  }
-#endif
-
-  // Get the actual image, and determine where the split points are.
-  // Note that mBorderImageSplit is in image pixels, not necessarily
-  // CSS pixels.
+    nsSize imageSize;
+    image->GetWidth(&imageSize.width);
+    image->GetHeight(&imageSize.height);
+    imageSize.width = nsPresContext::CSSPixelsToAppUnits(imageSize.width);
+    imageSize.height = nsPresContext::CSSPixelsToAppUnits(imageSize.height);
 
-  nsCOMPtr<imgIContainer> imgContainer;
-  req->GetImage(getter_AddRefs(imgContainer));
+    // 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;
+      }
+    }
 
-  nsIntSize imageSize;
-  imgContainer->GetWidth(&imageSize.width);
-  imgContainer->GetHeight(&imageSize.height);
-
-  nsCOMPtr<gfxIImageFrame> imgFrame;
-  imgContainer->GetCurrentFrame(getter_AddRefs(imgFrame));
-
-  nsIntRect innerRect;
-  imgFrame->GetRect(innerRect);
+    gfxContext *thebesCtx = aRenderingContext.ThebesContext();
+    nsCOMPtr<nsIDeviceContext> dc;
+    aRenderingContext.GetDeviceContext(*getter_AddRefs(dc));
 
-  nsCOMPtr<nsIImage> img(do_GetInterface(imgFrame));
-  // The inner rectangle should precisely enclose the image pixels for
-  // this frame.
-  NS_ASSERTION(innerRect.width == img->GetWidth(), "img inner width off");
-  NS_ASSERTION(innerRect.height == img->GetHeight(), "img inner height off");
+    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);
+    if (thebesCtx->UserToDevicePixelSnapped(clipRect))
+      clipRect = thebesCtx->DeviceToUser(clipRect);
+
+    thebesCtx->Save();
+    thebesCtx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
+
+    gfxSize middleSize(clipRect.size.width - (borderLeft + borderRight),
+                       clipRect.size.height - (borderTop + borderBottom));
 
-  // Convert percentages and clamp values to the image size.
-  nsIntMargin split;
-  NS_FOR_CSS_SIDES(s) {
-    nsStyleCoord coord = aBorderStyle.mBorderImageSplit.Get(s);
-    PRInt32 imgDimension = ((s == NS_SIDE_TOP || s == NS_SIDE_BOTTOM)
-                            ? imageSize.height
-                            : imageSize.width);
-    double value;
-    switch (coord.GetUnit()) {
-      case eStyleUnit_Percent:
-        value = coord.GetPercentValue() * imgDimension;
-        break;
-      case eStyleUnit_Factor:
-        value = coord.GetFactorValue();
-        break;
-      default:
-        NS_ASSERTION(coord.GetUnit() == eStyleUnit_Null,
-                     "unexpected CSS unit for image split");
-        value = 0;
-        break;
+    // 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 (value < 0)
-      value = 0;
-    if (value > imgDimension)
-      value = imgDimension;
-    split.side(s) = NS_lround(value);
-  }
-
-  nsMargin border(aBorderStyle.GetActualBorder());
 
-  // Compute the special scale factors for the middle component.
-  // Step 1 of the scaling algorithm in css3-background section 4.4,
-  // fourth bullet point:
-  //     The middle image's width is scaled by the same factor as
-  //     the top image unless that factor is zero or infinity, in
-  //     which case the scaling factor of the bottom is substituted,
-  //     and failing that, the width is not scaled. The height of
-  //     the middle image is scaled by the same factor as the left
-  //     image unless that factor is zero or infinity, in which case
-  //     the scaling factor of the right image is substituted, and
-  //     failing that, the height is not scaled.
-  gfxFloat hFactor, vFactor;
+    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;
 
-  if (0 < border.left && 0 < split.left)
-    vFactor = gfxFloat(border.left)/split.left;
-  else if (0 < border.right && 0 < split.right)
-    vFactor = gfxFloat(border.right)/split.right;
-  else
-    vFactor = 1.0;
+    interSizeLeft.width = borderLeft;
+    interSizeLeft.height = middleSizeSource.height*leftScale;
 
-  if (0 < border.top && 0 < split.top)
-    hFactor = gfxFloat(border.top)/split.top;
-  else if (0 < border.bottom && 0 < split.bottom)
-    hFactor = gfxFloat(border.bottom)/split.bottom;
-  else
-    hFactor = 1.0;
+    interSizeRight.width = borderRight;
+    interSizeRight.height = middleSizeSource.height*rightScale;
+
+    interSizeMiddle.width = middleSizeSource.width*middleScaleH;
+    interSizeMiddle.height = middleSizeSource.height*middleScaleV;
 
-  // These helper tables recharacterize the 'split' and 'border' margins
-  // in a more convenient form: they are the x/y/width/height coords
-  // required for various bands of the border, and they have been transformed
-  // to be relative to the innerRect (for 'split') or the page (for 'border').
-  enum {
-    LEFT, MIDDLE, RIGHT,
-    TOP = LEFT, BOTTOM = RIGHT
-  };
-  const nscoord borderX[3] = {
-    aBorderArea.x + 0,
-    aBorderArea.x + border.left,
-    aBorderArea.x + aBorderArea.width - border.right,
-  };
-  const nscoord borderY[3] = {
-    aBorderArea.y + 0,
-    aBorderArea.y + border.top,
-    aBorderArea.y + aBorderArea.height - border.bottom,
-  };
-  const nscoord borderWidth[3] = {
-    border.left,
-    aBorderArea.width - border.left - border.right,
-    border.right,
-  };
-  const nscoord borderHeight[3] = {
-    border.top,
-    aBorderArea.height - border.top - border.bottom,
-    border.bottom,
-  };
+    // 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);
 
-  const PRInt32 splitX[3] = {
-    -innerRect.x + 0,
-    -innerRect.x + split.left,
-    -innerRect.x + imageSize.width - split.right,
-  };
-  const PRInt32 splitY[3] = {
-    -innerRect.y + 0,
-    -innerRect.y + split.top,
-    -innerRect.y + imageSize.height - split.bottom,
-  };
-  const PRInt32 splitWidth[3] = {
-    split.left,
-    imageSize.width - split.left - split.right,
-    split.right,
-  };
-  const PRInt32 splitHeight[3] = {
-    split.top,
-    imageSize.height - split.top - split.bottom,
-    split.bottom,
-  };
-
-  for (int i = LEFT; i <= RIGHT; i++) {
-    for (int j = TOP; j <= BOTTOM; j++) {
-      nsRect destArea(borderX[i], borderY[j], borderWidth[i], borderHeight[j]);
-      nsIntRect subArea(splitX[i], splitY[j], splitWidth[i], splitHeight[j]);
+    // 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);
 
-      // Corners are always stretched to fit the corner.
-      // Sides are always stretched to the thickness of their border.
-      PRUint8 fillStyleH = (i == 1
-                            ? aBorderStyle.mBorderImageHFill
-                            : NS_STYLE_BORDER_IMAGE_STRETCH);
-      PRUint8 fillStyleV = (j == 1
-                            ? aBorderStyle.mBorderImageVFill
-                            : NS_STYLE_BORDER_IMAGE_STRETCH);
+    // 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);
 
-      // For everything except the middle, whichever axis is always
-      // stretched determines the size of the 'unit square' for tiling.
-      // The middle uses the special scale factors calculated above.
-      nsSize unitSize;
-      if (i == MIDDLE && j == MIDDLE) {
-        unitSize.width = splitWidth[i]*hFactor;
-        unitSize.height = splitHeight[j]*vFactor;
-      } else if (i == MIDDLE) {
-        unitSize.width = borderHeight[j];
-        unitSize.height = borderHeight[j];
-      } else if (j == MIDDLE) {
-        unitSize.width = borderWidth[i];
-        unitSize.height = borderWidth[i];
-      } else {
-        unitSize.width = borderWidth[i];
-        unitSize.height = borderHeight[j];
-      }
-
-      DrawBorderImageComponent(aRenderingContext, img, aDirtyRect,
-                               destArea, subArea,
-                               fillStyleH, fillStyleV, unitSize);
-    }
-  }
+    thebesCtx->PopGroupToSource();
+    thebesCtx->SetOperator(gfxContext::OPERATOR_OVER);
+    thebesCtx->Paint();
+    thebesCtx->Restore();
 }
 
 static void
-DrawBorderImageComponent(nsIRenderingContext& aRenderingContext,
-                         nsIImage*            aImage,
-                         const nsRect&        aDirtyRect,
-                         const nsRect&        aFill,
-                         const nsIntRect&     aSrc,
-                         PRUint8              aHFill,
-                         PRUint8              aVFill,
-                         const nsSize&        aUnitSize)
+DrawBorderImageSide(gfxContext *aThebesContext,
+                    nsIDeviceContext* aDeviceContext,
+                    imgIContainer* aImage,
+                    gfxRect& aDestRect,
+                    gfxSize aInterSize, // non-ref to allow aliasing
+                    gfxRect& aSourceRect,
+                    PRUint8 aHFillType,
+                    PRUint8 aVFillType)
 {
-  if (aFill.IsEmpty() || aSrc.IsEmpty())
-    return;
-
-  nsCOMPtr<nsIImage> subImage;
-  if (NS_FAILED(aImage->Extract(aSrc, getter_AddRefs(subImage))))
-    return;
-
-  // If we have no tiling in either direction, we can skip the intermediate
-  // scaling step.
-  if (aHFill == NS_STYLE_BORDER_IMAGE_STRETCH &&
-      aVFill == NS_STYLE_BORDER_IMAGE_STRETCH) {
-    nsLayoutUtils::DrawSingleImage(&aRenderingContext, subImage,
-                                   aFill, aDirtyRect);
+  if (aDestRect.size.width < 1.0 || aDestRect.size.height < 1.0 ||
+      aSourceRect.size.width < 1.0 || aSourceRect.size.height < 1.0) {
     return;
   }
 
-  // Compute the scale and position of the master copy of the image.
-  nsRect tile;
-  switch (aHFill) {
-  case NS_STYLE_BORDER_IMAGE_STRETCH:
-    tile.x = aFill.x;
-    tile.width = aFill.width;
-    break;
-  case NS_STYLE_BORDER_IMAGE_REPEAT:
-    tile.x = aFill.x + aFill.width/2 - aUnitSize.width/2;
-    tile.width = aUnitSize.width;
-    break;
+  gfxIntSize gfxSourceSize((PRInt32)aSourceRect.size.width,
+                           (PRInt32)aSourceRect.size.height);
+
+  // where the actual border ends up being rendered
+  if (aThebesContext->UserToDevicePixelSnapped(aDestRect))
+    aDestRect = aThebesContext->DeviceToUser(aDestRect);
+  if (aThebesContext->UserToDevicePixelSnapped(aSourceRect))
+    aSourceRect = aThebesContext->DeviceToUser(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);
 
-  case NS_STYLE_BORDER_IMAGE_ROUND:
-    tile.x = aFill.x;
-    tile.width = aFill.width / ceil(gfxFloat(aFill.width)/aUnitSize.width);
-    break;
+  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;
 
-  default:
-    NS_NOTREACHED("unrecognized border-image fill style");
+    // 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;
+
   }
 
-  switch (aVFill) {
-  case NS_STYLE_BORDER_IMAGE_STRETCH:
-    tile.y = aFill.y;
-    tile.height = aFill.height;
-    break;
-  case NS_STYLE_BORDER_IMAGE_REPEAT:
-    tile.y = aFill.y + aFill.height/2 - aUnitSize.height/2;
-    tile.height = aUnitSize.height;
-    break;
+  // 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);
 
-  case NS_STYLE_BORDER_IMAGE_ROUND:
-    tile.y = aFill.y;
-    tile.height = aFill.height/ceil(gfxFloat(aFill.height)/aUnitSize.height);
-    break;
-
-  default:
-    NS_NOTREACHED("unrecognized border-image fill style");
+  nsRefPtr<gfxPattern> pattern = new gfxPattern(interSurface);
+  pattern->SetExtend(gfxPattern::EXTEND_PAD_EDGE);
+  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;
   }
 
-  nsLayoutUtils::DrawImage(&aRenderingContext, subImage,
-                           tile, aFill, tile.TopLeft(), aDirtyRect);
+  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();
 }
 
 // Begin table border-collapsing section
 // These functions were written to not disrupt the normal ones and yet satisfy some additional requirements
 // At some point, all functions should be unified to include the additional functionality that these provide
 
 static nscoord
 RoundIntToPixel(nscoord aValue, 
deleted file mode 100644
index 7276260655f82866cd4d23008c958fab41655a20..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/layout/reftests/border-image/center-scaling-1.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!doctype html>
-<style>
-body { margin: 5px }
-div {
-  border-width: 27px;
-  -moz-border-image: url("reticule.png") 27 round;
-  width: 270px;
-  height: 135px;
-}
-</style>
-<div></div>
deleted file mode 100644
index b38c596c3de6374845029f8cea4bc5d01d168bfd..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/layout/reftests/border-image/center-scaling-2.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!doctype html>
-<style>
-body { margin: 5px 2px }
-div {
-  border-width: 27px 54px;
-  -moz-border-image: url("reticule.png") 27 round;
-  width: 270px;
-  height: 135px;
-}
-</style>
-<div></div>
deleted file mode 100644
index a8f5fbd5afdb2d90a9e90257c5406effd9f7290a..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/layout/reftests/border-image/center-scaling-3.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!doctype html>
-<style>
-body { margin: 2px 5px }
-div {
-  border-width: 54px 27px;
-  -moz-border-image: url("reticule.png") 27 round;
-  width: 270px;
-  height: 135px;
-}
-</style>
-<div></div>
deleted file mode 100644
index 7fe5da5e608699e970bf0b2602d3881aae7bc09d..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/layout/reftests/border-image/different-h-v-1.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!doctype html>
-<html><head>
-<style>
-div { 
-  margin: 27px;
-  border-width: 1em;
-  -moz-border-image: url("diamonds.png") 27 stretch round;
-  width: 270px;
-  height: 135px;
-}
-</style>
-<body>
-<div></div>
-</body></html>
deleted file mode 100644
--- a/layout/reftests/border-image/different-h-v-2.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!doctype html>
-<html><head>
-<style>
-div { 
-  margin: 27px;
-  border-width: 1em;
-  -moz-border-image: url("diamonds.png") 27 round stretch;
-  width: 270px;
-  height: 135px;
-}
-</style>
-<body>
-<div></div>
-</body></html>
deleted file mode 100644
--- a/layout/reftests/border-image/different-h-v-ref.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!doctype html>
-<html><head>
-<style>
-div { 
-  margin: 27px;
-  border-width: 1em;
-  -moz-border-image: url("diamonds.png") 27 stretch;
-  width: 270px;
-  height: 135px;
-}
-</style>
-<body>
-<div></div>
-</body></html>
--- a/layout/reftests/border-image/reftest.list
+++ b/layout/reftests/border-image/reftest.list
@@ -1,16 +1,9 @@
 fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == solid-image-1.html solid-image-1-ref.html # bug 445911
 == transparent-image-1.html transparent-image-1-ref.html
 fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == solid-image-2.html solid-image-2-ref.html # bug 445911
-fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == solid-image-2a.html solid-image-2-ref.html # bug 445911
 == 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
 == multicolor-image-4.html multicolor-image-4-ref.html
 == multicolor-image-5.html multicolor-image-5-ref.html
 != repeat-image-1.html repeat-image-1-ref.html
-!= different-h-v-1.html different-h-v-ref.html
-!= different-h-v-2.html different-h-v-ref.html
-!= different-h-v-1.html different-h-v-2.html
-== center-scaling-1.html center-scaling-1-ref.png
-== center-scaling-2.html center-scaling-2-ref.png
-== center-scaling-3.html center-scaling-3-ref.png
deleted file mode 100644
index 8992232af81acad28b144953eee54c6d4bb5fd8d..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/layout/reftests/border-image/solid-image-2a.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!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 repeat;
-    -khtml-border-image: url('3x3green-1DD813.png') 1 1 1 1 / 10px repeat;
-    border-image: url('3x3green-1DD813.png') 1 1 1 1 / 10px repeat;
-    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>