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