b=382613, moz-border-radius of background color isn't clamped to 50%, r+sr=roc
authorvladimir@pobox.com
Wed, 18 Jul 2007 07:14:53 -0700
changeset 3608 6bb8b4f48ee51b555b8044e190163bcdcfb77c4e
parent 3607 c8bd7becfd03aa55d2ca46393bc64d053577291b
child 3609 b93288890e5d4bfb9d12fad843f7affb622e90cb
push idunknown
push userunknown
push dateunknown
bugs382613
milestone1.9a7pre
b=382613, moz-border-radius of background color isn't clamped to 50%, r+sr=roc
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -2169,16 +2169,74 @@ DrawBorderSides(gfxContext *ctx,        
   ctx->Rectangle(oRect);
   ctx->Stroke();
   ctx->NewPath();
   ctx->Rectangle(iRect);
   ctx->Stroke();
 #endif
 }
 
+/*
+ * Compute the float-pixel radii that should be used for drawing
+ * this border/outline, given the various input bits.
+ *
+ * If a side is skipped via skipSides, its corners are forced to 0,
+ * otherwise the resulting radius is the smaller of the specified
+ * radius and half of each adjacent side's length.
+ */
+static void
+ComputePixelRadii(const nscoord *aTwipsRadii,
+                  const nsRect& outerRect,
+                  const nsMargin& borderMargin,
+                  PRIntn skipSides,
+                  nscoord twipsPerPixel,
+                  gfxFloat *oBorderRadii)
+{
+  nscoord twipsRadii[4] = { aTwipsRadii[0], aTwipsRadii[1], aTwipsRadii[2], aTwipsRadii[3] };
+  nsMargin border(borderMargin);
+
+  if (skipSides & SIDE_BIT_TOP) {
+    border.top = 0;
+    twipsRadii[C_TL] = 0;
+    twipsRadii[C_TR] = 0;
+  }
+
+  if (skipSides & SIDE_BIT_RIGHT) {
+    border.right = 0;
+    twipsRadii[C_TR] = 0;
+    twipsRadii[C_BR] = 0;
+  }
+
+  if (skipSides & SIDE_BIT_BOTTOM) {
+    border.bottom = 0;
+    twipsRadii[C_BR] = 0;
+    twipsRadii[C_BL] = 0;
+  }
+
+  if (skipSides & SIDE_BIT_LEFT) {
+    border.left = 0;
+    twipsRadii[C_BL] = 0;
+    twipsRadii[C_TL] = 0;
+  }
+
+  nsRect innerRect(outerRect);
+  innerRect.Deflate(border);
+
+  // make sure the corner radii don't get too big
+  nsMargin maxRadiusSize(innerRect.width/2 + border.left,
+                         innerRect.height/2 + border.top,
+                         innerRect.width/2 + border.right,
+                         innerRect.height/2 + border.bottom);
+
+  oBorderRadii[C_TL] = gfxFloat(PR_MIN(twipsRadii[C_TL], PR_MIN(maxRadiusSize.top, maxRadiusSize.left))) / twipsPerPixel;
+  oBorderRadii[C_TR] = gfxFloat(PR_MIN(twipsRadii[C_TR], PR_MIN(maxRadiusSize.top, maxRadiusSize.right))) / twipsPerPixel;
+  oBorderRadii[C_BL] = gfxFloat(PR_MIN(twipsRadii[C_BL], PR_MIN(maxRadiusSize.bottom, maxRadiusSize.left))) / twipsPerPixel;
+  oBorderRadii[C_BR] = gfxFloat(PR_MIN(twipsRadii[C_BR], PR_MIN(maxRadiusSize.bottom, maxRadiusSize.right))) / twipsPerPixel;
+}
+
 static void
 DrawDashedSide(gfxContext *ctx,
                PRUint8 side,
                const gfxRect& iRect,
                const gfxRect& oRect,
                PRUint8 style,
                gfxFloat borderWidth,
                nscolor borderColor,
@@ -2615,44 +2673,20 @@ nsCSSRendering::PaintBorder(nsPresContex
         break;
 
       default:
         break;
     }
   }
 
   // Turn off rendering for all of the zero sized sides
-  if (border.top == 0) aSkipSides |= SIDE_BIT_TOP;
-  if (border.right == 0) aSkipSides |= SIDE_BIT_RIGHT;
-  if (border.bottom == 0) aSkipSides |= SIDE_BIT_BOTTOM;
-  if (border.left == 0) aSkipSides |= SIDE_BIT_LEFT;
-
-  if (aSkipSides & SIDE_BIT_TOP) {
-    border.top = 0;
-    twipsRadii[C_TL] = 0;
-    twipsRadii[C_TR] = 0;
-  }
-
-  if (aSkipSides & SIDE_BIT_RIGHT) {
-    border.right = 0;
-    twipsRadii[C_TR] = 0;
-    twipsRadii[C_BR] = 0;
-  }
-
-  if (aSkipSides & SIDE_BIT_BOTTOM) {
-    border.bottom = 0;
-    twipsRadii[C_BR] = 0;
-    twipsRadii[C_BL] = 0;
-  }
-
-  if (aSkipSides & SIDE_BIT_LEFT) {
-    border.left = 0;
-    twipsRadii[C_BL] = 0;
-    twipsRadii[C_TL] = 0;
-  }
+  if (aSkipSides & SIDE_BIT_TOP) border.top = 0;
+  if (aSkipSides & SIDE_BIT_RIGHT) border.right = 0;
+  if (aSkipSides & SIDE_BIT_BOTTOM) border.bottom = 0;
+  if (aSkipSides & SIDE_BIT_LEFT) border.left = 0;
 
   // get the inside and outside parts of the border
   nsRect outerRect(aBorderArea), innerRect(aBorderArea);
   innerRect.Deflate(border);
 
   SF(" innerRect: %d %d %d %d\n", innerRect.x, innerRect.y, innerRect.width, innerRect.height);
   SF(" outerRect: %d %d %d %d\n", outerRect.x, outerRect.y, outerRect.width, outerRect.height);
 
@@ -2673,49 +2707,34 @@ nsCSSRendering::PaintBorder(nsPresContex
   // content is being painted), then we can skip out now
   // XXX this isn't exactly true for rounded borders, where the inner curves may
   // encroach into the content area.  A safer calculation would be to
   // shorten innerRect by the radius one each side before performing this test.
   if (innerRect.Contains(aDirtyRect)) {
     return;
   }
 
-  // make sure the corner radii don't get too big
-  nsMargin maxRadiusSize(innerRect.width/2 + border.left,
-                         innerRect.height/2 + border.top,
-                         innerRect.width/2 + border.right,
-                         innerRect.height/2 + border.bottom);
-  
-  twipsRadii[C_TL] = PR_MIN(twipsRadii[C_TL], PR_MIN(maxRadiusSize.top, maxRadiusSize.left));
-  twipsRadii[C_TR] = PR_MIN(twipsRadii[C_TR], PR_MIN(maxRadiusSize.top, maxRadiusSize.right));
-  twipsRadii[C_BL] = PR_MIN(twipsRadii[C_BL], PR_MIN(maxRadiusSize.bottom, maxRadiusSize.left));
-  twipsRadii[C_BR] = PR_MIN(twipsRadii[C_BR], PR_MIN(maxRadiusSize.bottom, maxRadiusSize.right));
-
-  SF(" borderRadii: %d %d %d %d\n", twipsRadii[0], twipsRadii[1], twipsRadii[2], twipsRadii[3]);
-
   // we can assume that we're already clipped to aDirtyRect -- I think? (!?)
 
   // Get our conversion values
   nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
 
   // convert outer and inner rects
   gfxRect oRect(RectToGfxRect(outerRect, twipsPerPixel));
   gfxRect iRect(RectToGfxRect(innerRect, twipsPerPixel));
 
   // convert the border widths
   gfxFloat borderWidths[4] = { border.top / twipsPerPixel,
                                border.right / twipsPerPixel,
                                border.bottom / twipsPerPixel,
                                border.left / twipsPerPixel };
 
   // convert the radii
-  gfxFloat borderRadii[4] = { gfxFloat(twipsRadii[0]) / twipsPerPixel,
-                              gfxFloat(twipsRadii[1]) / twipsPerPixel,
-                              gfxFloat(twipsRadii[2]) / twipsPerPixel,
-                              gfxFloat(twipsRadii[3]) / twipsPerPixel };
+  gfxFloat borderRadii[4];
+  ComputePixelRadii(twipsRadii, outerRect, border, aSkipSides, twipsPerPixel, borderRadii);
 
   PRUint8 borderStyles[4];
   nscolor borderColors[4];
   nsBorderColors *compositeColors[4];
 
   // pull out styles, colors, composite colors
   for (int i = 0; i < 4; i++) {
     PRBool transparent, foreground;
@@ -2818,19 +2837,16 @@ nsCSSRendering::PaintOutline(nsPresConte
 
       case eStyleUnit_Coord:
         twipsRadii[i] = bordStyleRadius[i].GetCoordValue();
         break;
 
       default:
         break;
     }
-
-    if (twipsRadii[i])
-      twipsRadii[i] = PR_MIN(twipsRadii[i], PR_MIN(aBorderArea.width / 2, aBorderArea.height / 2));
   }
 
   nsRect overflowArea = aForFrame->GetOverflowRect();
 
   // get the offset for our outline
   aOutlineStyle.GetOutlineOffset(offset);
   nsRect outerRect(overflowArea + aBorderArea.TopLeft());
   nsRect innerRect(outerRect);
@@ -2860,20 +2876,19 @@ nsCSSRendering::PaintOutline(nsPresConte
   // Get our conversion values
   nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
 
   // get the inner and outer rectangles
   gfxRect oRect(RectToGfxRect(outerRect, twipsPerPixel));
   gfxRect iRect(RectToGfxRect(innerRect, twipsPerPixel));
 
   // convert the radii
-  gfxFloat outlineRadii[4] = { gfxFloat(twipsRadii[0]) / twipsPerPixel,
-                               gfxFloat(twipsRadii[1]) / twipsPerPixel,
-                               gfxFloat(twipsRadii[2]) / twipsPerPixel,
-                               gfxFloat(twipsRadii[3]) / twipsPerPixel };
+  nsMargin outlineMargin(width, width, width, width);
+  gfxFloat outlineRadii[4];
+  ComputePixelRadii(twipsRadii, outerRect, outlineMargin, 0, twipsPerPixel, outlineRadii);
 
   PRUint8 outlineStyle = aOutlineStyle.GetOutlineStyle();
   PRUint8 outlineStyles[4] = { outlineStyle,
                                outlineStyle,
                                outlineStyle,
                                outlineStyle };
 
   nscolor outlineColor;
@@ -3812,17 +3827,17 @@ nsCSSRendering::PaintBackgroundColor(nsP
   // PaintBackgroundWithSC before the first call to PaintBackgroundColor.
   if ((aColor.mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) &&
       (aCanPaintNonWhite || aColor.IsTransparent())) {
     // nothing to paint
     return;
   }
 
   nsStyleCoord bordStyleRadius[4];
-  PRInt16 borderRadii[4];
+  nscoord borderRadii[4];
   nsRect bgClipArea(aBgClipArea);
 
   // get the radius for our border
   aBorder.mBorderRadius.GetTop(bordStyleRadius[NS_SIDE_TOP]);       // topleft
   aBorder.mBorderRadius.GetRight(bordStyleRadius[NS_SIDE_RIGHT]);   // topright
   aBorder.mBorderRadius.GetBottom(bordStyleRadius[NS_SIDE_BOTTOM]); // bottomright
   aBorder.mBorderRadius.GetLeft(bordStyleRadius[NS_SIDE_LEFT]);     // bottomleft
 
@@ -3882,17 +3897,17 @@ nsCSSRendering::PaintBackgroundColor(nsP
  */
 void
 nsCSSRendering::PaintRoundedBackground(nsPresContext* aPresContext,
                                        nsIRenderingContext& aRenderingContext,
                                        nsIFrame* aForFrame,
                                        const nsRect& aBgClipArea,
                                        const nsStyleBackground& aColor,
                                        const nsStyleBorder& aBorder,
-                                       PRInt16 aTheRadius[4],
+                                       nscoord aTheRadius[4],
                                        PRBool aCanPaintNonWhite)
 {
   nsRefPtr<gfxContext> ctx = (gfxContext*)
     aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
 
   // needed for our border thickness
   nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
 
@@ -3916,20 +3931,23 @@ nsCSSRendering::PaintRoundedBackground(n
 
   // the bgClipArea is the outside
   gfxRect oRect(RectToGfxRect(aBgClipArea, appUnitsPerPixel));
   oRect.Round();
   oRect.Condition();
   if (oRect.IsEmpty())
     return;
 
-  gfxFloat radii[4] = { gfxFloat(aTheRadius[0]) / appUnitsPerPixel,
-                        gfxFloat(aTheRadius[1]) / appUnitsPerPixel,
-                        gfxFloat(aTheRadius[2]) / appUnitsPerPixel,
-                        gfxFloat(aTheRadius[3]) / appUnitsPerPixel };
+  // convert the radii
+  gfxFloat radii[4];
+  nsMargin border = aBorder.GetBorder();
+
+  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
   // background should have identical coverage, and the border should
   // overlay the background exactly.  The way to avoid this is by using
   // a supersampling scheme, but we don't have the mechanism in place to do
   // this.  So, this will do for now.
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -210,17 +210,17 @@ protected:
                                    PRBool aCanPaintNonWhite);
 
   static void PaintRoundedBackground(nsPresContext* aPresContext,
                                      nsIRenderingContext& aRenderingContext,
                                      nsIFrame* aForFrame,
                                      const nsRect& aBorderArea,
                                      const nsStyleBackground& aColor,
                                      const nsStyleBorder& aBorder,
-                                     PRInt16 aTheRadius[4],
+                                     nscoord aTheRadius[4],
                                      PRBool aCanPaintNonWhite);
 
   static nscolor MakeBevelColor(PRIntn whichSide, PRUint8 style,
                                 nscolor aBackgroundColor,
                                 nscolor aBorderColor);
 
   static void DrawLine (nsIRenderingContext& aContext, 
                         nscoord aX1, nscoord aY1, nscoord aX2, nscoord aY2,
@@ -229,103 +229,9 @@ protected:
   static void FillPolygon (nsIRenderingContext& aContext, 
                            const nsPoint aPoints[],
                            PRInt32 aNumPoints,
                            nsRect* aGap);
 
 };
 
 
-
-/** ---------------------------------------------------
- *  Class QBCurve, a quadratic bezier curve, used to implement the rounded rectangles
- *	@update 3/26/99 dwc
- */
-class QBCurve
-{
-
-public:
-	nsFloatPoint	mAnc1;
-	nsFloatPoint	mCon;
-	nsFloatPoint mAnc2;
-
-  QBCurve() {mAnc1.x=0;mAnc1.y=0;mCon=mAnc2=mAnc1;}
-  void SetControls(nsFloatPoint &aAnc1,nsFloatPoint &aCon,nsFloatPoint &aAnc2) { mAnc1 = aAnc1; mCon = aCon; mAnc2 = aAnc2;}
-  void SetPoints(float a1x,float a1y,float acx,float acy,float a2x,float a2y) {mAnc1.MoveTo(a1x,a1y),mCon.MoveTo(acx,acy),mAnc2.MoveTo(a2x,a2y);}
-
-/** ---------------------------------------------------
- *  Divide a Quadratic curve into line segments if it is not smaller than a certain size
- *  else it is so small that it can be approximated by 2 lineto calls
- *  @param aRenderingContext -- The RenderingContext to use to draw with
- *  @param aPointArray[] -- A list of points we can put line calls into instead of drawing.  If null, lines are drawn
- *  @param aCurInex -- a pointer to an Integer that tells were to put the points into the array, incremented when finished
- *	@update 3/26/99 dwc
- */
-  void SubDivide(nsIRenderingContext *aRenderingContext,nsPoint  aPointArray[],PRInt32 *aCurIndex);
-
-/** ---------------------------------------------------
- *  Divide a Quadratic Bezier curve at the mid-point
- *	@update 3/26/99 dwc
- *  @param aCurve1 -- Curve 1 as a result of the division
- *  @param aCurve2 -- Curve 2 as a result of the division
- */
-  void MidPointDivide(QBCurve *A,QBCurve *B);
-};
-
-
-/** ---------------------------------------------------
- *  Class RoundedRect, A class to encapsulate all the rounded rect functionality, 
- *  which are based on the QBCurve
- *	@update 4/13/99 dwc
- */
-class RoundedRect
-{
-
-public:
-  PRInt32 mRoundness[4];
-
-  PRBool  mDoRound;
-
-  PRInt32 mLeft;
-  PRInt32 mRight;
-  PRInt32 mTop;
-  PRInt32 mBottom;
-
-  /** 
-   *  Construct a rounded rectangle object
-   *  @update 4/19/99
-   */
-  void  RoundRect() {mRoundness[0]=0;}
-
-  /**
-   *  Set the curves boundaries and then break it up into the curve pieces for rendering
-   *  @update 4/13/99 dwc
-   *  @param aLeft -- Left side of bounding box
-   *  @param aTop -- Top side of bounding box
-   *  @param aWidth -- Width of bounding box
-   *  @param aHeight -- Height of bounding box
-   *  @param aRadius -- radius for the rounding
-   */
-  void  Set(nscoord aLeft,nscoord aTop,PRInt32  aWidth,PRInt32 aHeight,PRInt16 aRadius[4],PRInt16 aNumTwipPerPix);
-
-
-  /**
-   *  Calculate the inset of a curve based on a border
-   *  @update 4/13/99 dwc
-   *  @param aLeft -- Left side of bounding box
-   *  @param aTop -- Top side of bounding box
-   */
-  void  CalcInsetCurves(QBCurve &aULCurve,QBCurve &aURCurve,QBCurve &aLLCurve,QBCurve &aLRCurve,nsMargin &aBorder);
-
-  /** ---------------------------------------------------
-   *  set the passed in curves to the rounded borders of the rectangle
-   *	@update 4/13/99 dwc
-   *  @param aULCurve -- upperleft curve
-   *  @param aURCurve -- upperright curve
-   *  @param aLRCurve -- lowerright curve
-   *  @param aLLCurve -- lowerleft curve
-   */
-  void GetRoundedBorders(QBCurve &aULCurve,QBCurve &aURCurve,QBCurve &aLLCurve,QBCurve &aLRCurve);
-
-};
-
-
 #endif /* nsCSSRendering_h___ */