Back to index

lightning-sunbird  0.9+nobinonly
nsCSSRendering.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 // vim:cindent:ts=2:et:sw=2:
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Takeshi Ichimaru <ayakawa.m@gmail.com>
00025  *   Masayuki Nakano <masayuki@d-toybox.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 #include "nsStyleConsts.h"
00041 #include "nsPresContext.h"
00042 #include "nsIImage.h"
00043 #include "nsIFrame.h"
00044 #include "nsPoint.h"
00045 #include "nsRect.h"
00046 #include "nsIViewManager.h"
00047 #include "nsIPresShell.h"
00048 #include "nsFrameManager.h"
00049 #include "nsStyleContext.h"
00050 #include "nsIScrollableView.h"
00051 #include "nsLayoutAtoms.h"
00052 #include "nsIDrawingSurface.h"
00053 #include "nsTransform2D.h"
00054 #include "nsIDeviceContext.h"
00055 #include "nsIContent.h"
00056 #include "nsHTMLAtoms.h"
00057 #include "nsIDocument.h"
00058 #include "nsIScrollableFrame.h"
00059 #include "imgIRequest.h"
00060 #include "imgIContainer.h"
00061 #include "gfxIImageFrame.h"
00062 #include "nsCSSRendering.h"
00063 #include "nsCSSColorUtils.h"
00064 #include "nsITheme.h"
00065 #include "nsThemeConstants.h"
00066 #include "nsIServiceManager.h"
00067 #include "nsIDOMHTMLBodyElement.h"
00068 #include "nsIDOMHTMLDocument.h"
00069 #include "nsLayoutUtils.h"
00070 #include "nsINameSpaceManager.h"
00071 
00072 #define BORDER_FULL    0        //entire side
00073 #define BORDER_INSIDE  1        //inside half
00074 #define BORDER_OUTSIDE 2        //outside half
00075 
00076 //thickness of dashed line relative to dotted line
00077 #define DOT_LENGTH  1           //square
00078 #define DASH_LENGTH 3           //3 times longer than dot
00079 
00080 
00082 #define MAXPATHSIZE 12
00083 #define MAXPOLYPATHSIZE 1000
00084 
00085 enum ePathTypes{
00086   eOutside =0,
00087   eInside,
00088   eCalc,
00089   eCalcRev
00090 };
00091 
00092 // To avoid storing this data on nsInlineFrame (bloat) and to avoid
00093 // recalculating this for each frame in a continuation (perf), hold
00094 // a cache of various coordinate information that we need in order
00095 // to paint inline backgrounds.
00096 struct InlineBackgroundData
00097 {
00098   InlineBackgroundData()
00099       : mFrame(nsnull)
00100   {
00101   }
00102 
00103   ~InlineBackgroundData()
00104   {
00105   }
00106 
00107   void Reset()
00108   {
00109     mBoundingBox.SetRect(0,0,0,0);
00110     mContinuationPoint = mUnbrokenWidth = 0;
00111     mFrame = nsnull;    
00112   }
00113 
00114   nsRect GetContinuousRect(nsIFrame* aFrame)
00115   {
00116     SetFrame(aFrame);
00117 
00118     // Assume background-origin: border and return a rect with offsets
00119     // relative to (0,0).  If we have a different background-origin,
00120     // then our rect should be deflated appropriately by our caller.
00121     return nsRect(-mContinuationPoint, 0, mUnbrokenWidth, mFrame->GetSize().height);
00122   }
00123 
00124   nsRect GetBoundingRect(nsIFrame* aFrame)
00125   {
00126     SetFrame(aFrame);
00127 
00128     // Move the offsets relative to (0,0) which puts the bounding box into
00129     // our coordinate system rather than our parent's.  We do this by
00130     // moving it the back distance from us to the bounding box.
00131     // This also assumes background-origin: border, so our caller will
00132     // need to deflate us if needed.
00133     nsRect boundingBox(mBoundingBox);
00134     nsPoint point = mFrame->GetPosition();
00135     boundingBox.MoveBy(-point.x, -point.y);
00136 
00137     return boundingBox;
00138   }
00139 
00140 protected:
00141   nsIFrame*     mFrame;
00142   nscoord       mContinuationPoint;
00143   nscoord       mUnbrokenWidth;
00144   nsRect        mBoundingBox;
00145 
00146   void SetFrame(nsIFrame* aFrame)
00147   {
00148     NS_PRECONDITION(aFrame, "Need a frame");
00149 
00150     nsIFrame *prevInFlow = aFrame->GetPrevInFlow();
00151 
00152     if (!prevInFlow || mFrame != prevInFlow) {
00153       // Ok, we've got the wrong frame.  We have to start from scratch.
00154       Reset();
00155       Init(aFrame);
00156       return;
00157     }
00158 
00159     // Get our last frame's size and add its width to our continuation
00160     // point before we cache the new frame.
00161     mContinuationPoint += mFrame->GetSize().width;
00162 
00163     mFrame = aFrame;
00164   }
00165 
00166   void Init(nsIFrame* aFrame)
00167   {    
00168     // Start with the previous flow frame as our continuation point
00169     // is the total of the widths of the previous frames.
00170     nsIFrame* inlineFrame = aFrame->GetPrevInFlow();
00171 
00172     while (inlineFrame) {
00173       nsRect rect = inlineFrame->GetRect();
00174       mContinuationPoint += rect.width;
00175       mUnbrokenWidth += rect.width;
00176       mBoundingBox.UnionRect(mBoundingBox, rect);
00177       inlineFrame = inlineFrame->GetPrevInFlow();
00178     }
00179 
00180     // Next add this frame and subsequent frames to the bounding box and
00181     // unbroken width.
00182     inlineFrame = aFrame;
00183     while (inlineFrame) {
00184       nsRect rect = inlineFrame->GetRect();
00185       mUnbrokenWidth += rect.width;
00186       mBoundingBox.UnionRect(mBoundingBox, rect);
00187       inlineFrame = inlineFrame->GetNextInFlow();
00188     }
00189 
00190     mFrame = aFrame;
00191   }
00192 };
00193 
00194 static InlineBackgroundData gInlineBGData;
00195 
00196 static void GetPath(nsFloatPoint aPoints[],nsPoint aPolyPath[],PRInt32 *aCurIndex,ePathTypes  aPathType,PRInt32 &aC1Index,float aFrac=0);
00197 
00198 // FillRect or InvertRect depending on the renderingaInvert parameter
00199 static void FillOrInvertRect(nsIRenderingContext& aRC,nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aInvert);
00200 static void FillOrInvertRect(nsIRenderingContext& aRC,const nsRect& aRect, PRBool aInvert);
00201 
00202 // Draw a line, skipping that portion which crosses aGap. aGap defines a rectangle gap
00203 // This services fieldset legends and only works for coords defining horizontal lines.
00204 void nsCSSRendering::DrawLine (nsIRenderingContext& aContext, 
00205                                nscoord aX1, nscoord aY1, nscoord aX2, nscoord aY2,
00206                                nsRect* aGap)
00207 {
00208   if (nsnull == aGap) {
00209     aContext.DrawLine(aX1, aY1, aX2, aY2);
00210   } else {
00211     nscoord x1 = (aX1 < aX2) ? aX1 : aX2;
00212     nscoord x2 = (aX1 < aX2) ? aX2 : aX1;
00213     nsPoint gapUpperRight(aGap->x + aGap->width, aGap->y);
00214     nsPoint gapLowerRight(aGap->x + aGap->width, aGap->y + aGap->height);
00215     if ((aGap->y <= aY1) && (gapLowerRight.y >= aY2)) {
00216       if ((aGap->x > x1) && (aGap->x < x2)) {
00217         aContext.DrawLine(x1, aY1, aGap->x, aY1);
00218       } 
00219       if ((gapLowerRight.x > x1) && (gapLowerRight.x < x2)) {
00220         aContext.DrawLine(gapUpperRight.x, aY2, x2, aY2);
00221       } 
00222     } else {
00223       aContext.DrawLine(aX1, aY1, aX2, aY2);
00224     }
00225   }
00226 }
00227 
00228 // Fill a polygon, skipping that portion which crosses aGap. aGap defines a rectangle gap
00229 // This services fieldset legends and only works for points defining a horizontal rectangle 
00230 void nsCSSRendering::FillPolygon (nsIRenderingContext& aContext, 
00231                                   const nsPoint aPoints[],
00232                                   PRInt32 aNumPoints,
00233                                   nsRect* aGap)
00234 {
00235 #ifdef DEBUG
00236   nsPenMode penMode;
00237   if (NS_SUCCEEDED(aContext.GetPenMode(penMode)) &&
00238       penMode == nsPenMode_kInvert) {
00239     NS_WARNING( "Invert mode ignored in FillPolygon" );
00240   }
00241 #endif
00242 
00243   if (nsnull == aGap) {
00244     aContext.FillPolygon(aPoints, aNumPoints);
00245   } else if (4 == aNumPoints) {
00246     nsPoint gapUpperRight(aGap->x + aGap->width, aGap->y);
00247     nsPoint gapLowerRight(aGap->x + aGap->width, aGap->y + aGap->height);
00248 
00249     // sort the 4 points by x
00250     nsPoint points[4];
00251     for (PRInt32 pX = 0; pX < 4; pX++) {
00252       points[pX] = aPoints[pX];
00253     }
00254     for (PRInt32 i = 0; i < 3; i++) {
00255       for (PRInt32 j = i+1; j < 4; j++) { 
00256         if (points[j].x < points[i].x) {
00257           nsPoint swap = points[i];
00258           points[i] = points[j];
00259           points[j] = swap;
00260         }
00261       }
00262     }
00263 
00264     nsPoint upperLeft  = (points[0].y <= points[1].y) ? points[0] : points[1];
00265     nsPoint lowerLeft  = (points[0].y <= points[1].y) ? points[1] : points[0];
00266     nsPoint upperRight = (points[2].y <= points[3].y) ? points[2] : points[3];
00267     nsPoint lowerRight = (points[2].y <= points[3].y) ? points[3] : points[2];
00268 
00269 
00270     if ((aGap->y <= upperLeft.y) && (gapLowerRight.y >= lowerRight.y)) {
00271       if ((aGap->x > upperLeft.x) && (aGap->x < upperRight.x)) {
00272         nsPoint leftRect[4];
00273         leftRect[0] = upperLeft;
00274         leftRect[1] = nsPoint(aGap->x, upperLeft.y);
00275         leftRect[2] = nsPoint(aGap->x, lowerLeft.y);
00276         leftRect[3] = lowerLeft;
00277         aContext.FillPolygon(leftRect, 4);
00278       } 
00279       if ((gapUpperRight.x > upperLeft.x) && (gapUpperRight.x < upperRight.x)) {
00280         nsPoint rightRect[4];
00281         rightRect[0] = nsPoint(gapUpperRight.x, upperRight.y);
00282         rightRect[1] = upperRight;
00283         rightRect[2] = lowerRight;
00284         rightRect[3] = nsPoint(gapLowerRight.x, lowerRight.y);
00285         aContext.FillPolygon(rightRect, 4);
00286       } 
00287     } else {
00288       aContext.FillPolygon(aPoints, aNumPoints);
00289     }      
00290   }
00291 }
00292 
00296 nscolor nsCSSRendering::MakeBevelColor(PRIntn whichSide, PRUint8 style,
00297                                        nscolor aBackgroundColor,
00298                                        nscolor aBorderColor,
00299                                        PRBool aSpecialCase)
00300 {
00301 
00302   nscolor colors[2];
00303   nscolor theColor;
00304 
00305   // Given a background color and a border color
00306   // calculate the color used for the shading
00307   if(aSpecialCase)
00308     NS_GetSpecial3DColors(colors, aBackgroundColor, aBorderColor);
00309   else
00310     NS_Get3DColors(colors, aBackgroundColor);
00311  
00312   if ((style == NS_STYLE_BORDER_STYLE_BG_OUTSET) ||
00313       (style == NS_STYLE_BORDER_STYLE_OUTSET) ||
00314       (style == NS_STYLE_BORDER_STYLE_RIDGE)) {
00315     // Flip colors for these three border styles
00316     switch (whichSide) {
00317     case NS_SIDE_BOTTOM: whichSide = NS_SIDE_TOP;    break;
00318     case NS_SIDE_RIGHT:  whichSide = NS_SIDE_LEFT;   break;
00319     case NS_SIDE_TOP:    whichSide = NS_SIDE_BOTTOM; break;
00320     case NS_SIDE_LEFT:   whichSide = NS_SIDE_RIGHT;  break;
00321     }
00322   }
00323 
00324   switch (whichSide) {
00325   case NS_SIDE_BOTTOM:
00326     theColor = colors[1];
00327     break;
00328   case NS_SIDE_RIGHT:
00329     theColor = colors[1];
00330     break;
00331   case NS_SIDE_TOP:
00332     theColor = colors[0];
00333     break;
00334   case NS_SIDE_LEFT:
00335   default:
00336     theColor = colors[0];
00337     break;
00338   }
00339   return theColor;
00340 }
00341 
00342 // Maximum poly points in any of the polygons we generate below
00343 #define MAX_POLY_POINTS 4
00344 
00345 #define ACTUAL_THICKNESS(outside, inside, frac, tpp) \
00346   (NSToCoordRound(((outside) - (inside)) * (frac) / (tpp)) * (tpp))
00347 
00348 // a nifty helper function to create a polygon representing a
00349 // particular side of a border. This helps localize code for figuring
00350 // mitered edges. It is mainly used by the solid, inset, and outset
00351 // styles.
00352 //
00353 // If the side can be represented as a line segment (because the thickness
00354 // is one pixel), then a line with two endpoints is returned
00355 PRIntn nsCSSRendering::MakeSide(nsPoint aPoints[],
00356                                 nsIRenderingContext& aContext,
00357                                 PRIntn aWhichSide,
00358                                 const nsRect& aOutside, const nsRect& aInside,
00359                                 PRIntn aSkipSides,
00360                                 PRIntn aBorderPart, float aBorderFrac,
00361                                 nscoord aTwipsPerPixel)
00362 {
00363   nscoord outsideEdge, insideEdge, outsideTL, insideTL, outsideBR, insideBR;
00364 
00365   // Initialize the following six nscoord's:
00366   // outsideEdge, insideEdge, outsideTL, insideTL, outsideBR, insideBR
00367   // so that outsideEdge is the x or y of the outside edge, etc., and
00368   // outsideTR is the y or x at the top or right end, etc., e.g.:
00369   //
00370   // outsideEdge ---  ----------------------------------------
00371   //                  \                                      /
00372   //                   \                                    /
00373   //                    \                                  /
00374   // insideEdge -------  ----------------------------------
00375   //                 |   |                                |   |
00376   //         outsideTL   insideTL                  insideBR   outsideBR       
00377   //
00378   // if we don't want the bevel, we'll get rid of it later by setting
00379   // outsideXX to insideXX
00380 
00381   switch (aWhichSide) {
00382   case NS_SIDE_TOP:
00383     // the TL points are the left end; the BR points are the right end
00384     outsideEdge = aOutside.y;
00385     insideEdge = aInside.y;
00386     outsideTL = aOutside.x;
00387     insideTL = aInside.x;
00388     insideBR = aInside.XMost();
00389     outsideBR = aOutside.XMost();
00390     break;
00391 
00392   case NS_SIDE_BOTTOM:
00393     // the TL points are the left end; the BR points are the right end
00394     outsideEdge = aOutside.YMost();
00395     insideEdge = aInside.YMost();
00396     outsideTL = aOutside.x;
00397     insideTL = aInside.x;
00398     insideBR = aInside.XMost();
00399     outsideBR = aOutside.XMost();
00400     break;
00401 
00402   case NS_SIDE_LEFT:
00403     // the TL points are the top end; the BR points are the bottom end
00404     outsideEdge = aOutside.x;
00405     insideEdge = aInside.x;
00406     outsideTL = aOutside.y;
00407     insideTL = aInside.y;
00408     insideBR = aInside.YMost();
00409     outsideBR = aOutside.YMost();
00410     break;
00411 
00412   default:
00413     NS_ASSERTION(aWhichSide == NS_SIDE_RIGHT, "aWhichSide is not a valid side");
00414     // the TL points are the top end; the BR points are the bottom end
00415     outsideEdge = aOutside.XMost();
00416     insideEdge = aInside.XMost();
00417     outsideTL = aOutside.y;
00418     insideTL = aInside.y;
00419     insideBR = aInside.YMost();
00420     outsideBR = aOutside.YMost();
00421     break;
00422   }
00423 
00424   // Don't draw the bevels if an adjacent side is skipped
00425 
00426   if ( (aWhichSide == NS_SIDE_TOP) || (aWhichSide == NS_SIDE_BOTTOM) ) {
00427     // a top or bottom side
00428     if ((1<<NS_SIDE_LEFT) & aSkipSides) {
00429       insideTL = outsideTL;
00430     }
00431     if ((1<<NS_SIDE_RIGHT) & aSkipSides) {
00432       insideBR = outsideBR;
00433     }
00434   } else {
00435     // a right or left side
00436     if ((1<<NS_SIDE_TOP) & aSkipSides) {
00437       insideTL = outsideTL;
00438     }
00439     if ((1<<NS_SIDE_BOTTOM) & aSkipSides) {
00440       insideBR = outsideBR;
00441     }
00442   }
00443 
00444   nscoord fullThickness;
00445   if (aWhichSide == NS_SIDE_TOP || aWhichSide == NS_SIDE_LEFT)
00446     fullThickness = insideEdge - outsideEdge;
00447   else
00448     fullThickness = outsideEdge - insideEdge;
00449   if (fullThickness != 0)
00450     fullThickness = NS_MAX(fullThickness, aTwipsPerPixel);
00451 
00452   nscoord thickness = fullThickness;
00453   if (aBorderFrac != 1.0f && fullThickness != 0) {
00454     thickness = aTwipsPerPixel *
00455       NS_MAX(NSToCoordRound(fullThickness * aBorderFrac / aTwipsPerPixel), 1);
00456     if ((aWhichSide == NS_SIDE_TOP) || (aWhichSide == NS_SIDE_LEFT)) {
00457       if (aBorderPart == BORDER_INSIDE)
00458         outsideEdge = insideEdge - thickness;
00459       else if (aBorderPart == BORDER_OUTSIDE)
00460         insideEdge = outsideEdge + thickness;
00461     } else {
00462       if (aBorderPart == BORDER_INSIDE)
00463         outsideEdge = insideEdge + thickness;
00464       else if (aBorderPart == BORDER_OUTSIDE)
00465         insideEdge = outsideEdge - thickness;
00466     }
00467 
00468     float actualFrac = (float)thickness / (float)fullThickness;
00469     if (aBorderPart == BORDER_INSIDE) {
00470       outsideTL = insideTL +
00471         ACTUAL_THICKNESS(outsideTL, insideTL, actualFrac, aTwipsPerPixel);
00472       outsideBR = insideBR +
00473         ACTUAL_THICKNESS(outsideBR, insideBR, actualFrac, aTwipsPerPixel);
00474     } else if (aBorderPart == BORDER_OUTSIDE) {
00475       insideTL = outsideTL -
00476         ACTUAL_THICKNESS(outsideTL, insideTL, actualFrac, aTwipsPerPixel);
00477       insideBR = outsideBR -
00478         ACTUAL_THICKNESS(outsideBR, insideBR, actualFrac, aTwipsPerPixel);
00479     }
00480   }
00481 
00482   // Base our thickness check on the segment being less than a pixel and 1/2
00483   aTwipsPerPixel += aTwipsPerPixel >> 2;
00484 
00485   // if returning a line, do it along inside edge for bottom or right borders
00486   // so that it's in the same place as it would be with polygons (why?)
00487   // XXX The previous version of the code shortened the right border too.
00488   if ( !((thickness >= aTwipsPerPixel) || (aBorderPart != BORDER_FULL)) &&
00489        ((aWhichSide == NS_SIDE_BOTTOM) || (aWhichSide == NS_SIDE_RIGHT))) {
00490     outsideEdge = insideEdge;
00491     }
00492 
00493   // return the appropriate line or trapezoid
00494   PRIntn np = 0;
00495   if ((aWhichSide == NS_SIDE_TOP) || (aWhichSide == NS_SIDE_BOTTOM)) {
00496     // top and bottom borders
00497     aPoints[np++].MoveTo(outsideTL,outsideEdge);
00498     aPoints[np++].MoveTo(outsideBR,outsideEdge);
00499     // XXX Making this condition only (thickness >= aTwipsPerPixel) will
00500     // improve double borders and some cases of groove/ridge,
00501     //  but will cause problems with table borders.  See last and third
00502     // from last tests in test4.htm
00503     // Doing it this way emulates the old behavior.  It might be worth
00504     // fixing.
00505     if ((thickness >= aTwipsPerPixel) || (aBorderPart != BORDER_FULL)) {
00506       aPoints[np++].MoveTo(insideBR,insideEdge);
00507       aPoints[np++].MoveTo(insideTL,insideEdge);
00508     }
00509   } else {
00510     // right and left borders
00511     // XXX Ditto above
00512     if ((thickness >= aTwipsPerPixel) || (aBorderPart != BORDER_FULL))  {
00513       aPoints[np++].MoveTo(insideEdge,insideBR);
00514       aPoints[np++].MoveTo(insideEdge,insideTL);
00515     }
00516     aPoints[np++].MoveTo(outsideEdge,outsideTL);
00517     aPoints[np++].MoveTo(outsideEdge,outsideBR);
00518   }
00519   return np;
00520 }
00521 
00522 void nsCSSRendering::DrawSide(nsIRenderingContext& aContext,
00523                               PRIntn whichSide,
00524                               const PRUint8 borderStyle,  
00525                               const nscolor borderColor,
00526                               const nscolor aBackgroundColor,
00527                               const nsRect& borderOutside,
00528                               const nsRect& borderInside,
00529                               PRIntn aSkipSides,
00530                               nscoord twipsPerPixel,
00531                               nsRect* aGap)
00532 {
00533   nsPoint theSide[MAX_POLY_POINTS];
00534   nscolor theColor = borderColor; 
00535   PRUint8 theStyle = borderStyle; 
00536   PRInt32 np;
00537   switch (theStyle) {
00538   case NS_STYLE_BORDER_STYLE_NONE:
00539   case NS_STYLE_BORDER_STYLE_HIDDEN:
00540     return;
00541 
00542   case NS_STYLE_BORDER_STYLE_DOTTED:    //handled a special case elsewhere
00543   case NS_STYLE_BORDER_STYLE_DASHED:    //handled a special case elsewhere
00544     break; // That was easy...
00545 
00546   case NS_STYLE_BORDER_STYLE_GROOVE:
00547   case NS_STYLE_BORDER_STYLE_RIDGE:
00548     np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, aSkipSides,
00549                    BORDER_INSIDE, 0.5f, twipsPerPixel);
00550     aContext.SetColor ( MakeBevelColor (whichSide, 
00551                                         ((theStyle == NS_STYLE_BORDER_STYLE_RIDGE) ?
00552                                          NS_STYLE_BORDER_STYLE_GROOVE :
00553                                          NS_STYLE_BORDER_STYLE_RIDGE), 
00554                                          aBackgroundColor, theColor, 
00555                                          PR_TRUE));
00556     if (2 == np) {
00557       //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
00558       DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
00559     } else {
00560       //aContext.FillPolygon (theSide, np);
00561       FillPolygon (aContext, theSide, np, aGap);
00562     }
00563     np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
00564                    BORDER_OUTSIDE, 0.5f, twipsPerPixel);
00565     aContext.SetColor ( MakeBevelColor (whichSide, theStyle, aBackgroundColor, 
00566                                         theColor, PR_TRUE));
00567     if (2 == np) {
00568       //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
00569       DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
00570     } else {
00571       //aContext.FillPolygon (theSide, np);
00572       FillPolygon (aContext, theSide, np, aGap);
00573     }
00574     break;
00575 
00576   case NS_STYLE_BORDER_STYLE_AUTO:
00577   case NS_STYLE_BORDER_STYLE_SOLID:
00578     np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
00579                    BORDER_FULL, 1.0f, twipsPerPixel);
00580     aContext.SetColor (borderColor);  
00581     if (2 == np) {
00582       //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
00583       DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
00584     } else {
00585       //aContext.FillPolygon (theSide, np);
00586       FillPolygon (aContext, theSide, np, aGap);
00587     }
00588     break;
00589 
00590   case NS_STYLE_BORDER_STYLE_BG_SOLID:
00591     np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, aSkipSides,
00592                    BORDER_FULL, 1.0f, twipsPerPixel);
00593     nscolor colors[2]; 
00594     NS_Get3DColors(colors, aBackgroundColor); 
00595     aContext.SetColor (colors[0]);
00596     if (2 == np) {
00597       DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
00598     } else {
00599       FillPolygon (aContext, theSide, np, aGap);
00600     }
00601     break;
00602 
00603   case NS_STYLE_BORDER_STYLE_DOUBLE:
00604     np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
00605                    BORDER_INSIDE, 0.333333f, twipsPerPixel);
00606     aContext.SetColor (borderColor);
00607     if (2 == np) {
00608       //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
00609       DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
00610     } else {
00611       //aContext.FillPolygon (theSide, np);
00612       FillPolygon (aContext, theSide, np, aGap);
00613    }
00614     np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
00615                    BORDER_OUTSIDE, 0.333333f, twipsPerPixel);
00616     if (2 == np) {
00617       //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
00618       DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
00619     } else {
00620       //aContext.FillPolygon (theSide, np);
00621       FillPolygon (aContext, theSide, np, aGap);
00622     }
00623     break;
00624 
00625   case NS_STYLE_BORDER_STYLE_BG_OUTSET:
00626   case NS_STYLE_BORDER_STYLE_BG_INSET:
00627     np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
00628                    BORDER_FULL, 1.0f, twipsPerPixel);
00629     aContext.SetColor ( MakeBevelColor (whichSide, theStyle, aBackgroundColor,
00630                                         theColor, PR_FALSE));
00631     if (2 == np) {
00632       //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
00633       DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
00634     } else {
00635       //aContext.FillPolygon (theSide, np);
00636       FillPolygon (aContext, theSide, np, aGap);
00637     }
00638     break;
00639   case NS_STYLE_BORDER_STYLE_OUTSET:
00640   case NS_STYLE_BORDER_STYLE_INSET:
00641     np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
00642                    BORDER_FULL, 1.0f, twipsPerPixel);
00643     aContext.SetColor ( MakeBevelColor (whichSide, theStyle, aBackgroundColor, 
00644                                         theColor, PR_TRUE));
00645     if (2 == np) {
00646       //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
00647       DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
00648     } else {
00649       //aContext.FillPolygon (theSide, np);
00650       FillPolygon (aContext, theSide, np, aGap);
00651     }
00652     break;
00653   }
00654 }
00655 
00656 
00660 //XXX dashes which span more than two edges are not handled properly MMP
00661 void nsCSSRendering::DrawDashedSides(PRIntn startSide,
00662                                      nsIRenderingContext& aContext,
00663                    /* XXX unused */  const nsRect& aDirtyRect,
00664                                      const PRUint8 borderStyles[],  
00665                                      const nscolor borderColors[],  
00666                                      const nsRect& borderOutside,
00667                                      const nsRect& borderInside,
00668                                      PRIntn aSkipSides,
00669                    /* XXX unused */  nsRect* aGap)
00670 {
00671 PRIntn  dashLength;
00672 nsRect  dashRect, firstRect, currRect;
00673 PRBool  bSolid = PR_TRUE;
00674 float   over = 0.0f;
00675 PRUint8 style = borderStyles[startSide];  
00676 PRBool  skippedSide = PR_FALSE;
00677 
00678   for (PRIntn whichSide = startSide; whichSide < 4; whichSide++) {
00679     PRUint8 prevStyle = style;
00680     style = borderStyles[whichSide];  
00681     if ((1<<whichSide) & aSkipSides) {
00682       // Skipped side
00683       skippedSide = PR_TRUE;
00684       continue;
00685     }
00686     if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
00687         (style == NS_STYLE_BORDER_STYLE_DOTTED))
00688     {
00689       if ((style != prevStyle) || skippedSide) {
00690         //style discontinuity
00691         over = 0.0f;
00692         bSolid = PR_TRUE;
00693       }
00694 
00695       // XXX units for dash & dot?
00696       if (style == NS_STYLE_BORDER_STYLE_DASHED) {
00697         dashLength = DASH_LENGTH;
00698       } else {
00699         dashLength = DOT_LENGTH;
00700       }
00701 
00702       aContext.SetColor(borderColors[whichSide]);  
00703       switch (whichSide) {
00704       case NS_SIDE_LEFT:
00705         //XXX need to properly handle wrap around from last edge to first edge
00706         //(this is the first edge) MMP
00707         dashRect.width = borderInside.x - borderOutside.x;
00708         dashRect.height = nscoord(dashRect.width * dashLength);
00709         dashRect.x = borderOutside.x;
00710         dashRect.y = borderInside.YMost() - dashRect.height;
00711 
00712         if (over > 0.0f) {
00713           firstRect.x = dashRect.x;
00714           firstRect.width = dashRect.width;
00715           firstRect.height = nscoord(dashRect.height * over);
00716           firstRect.y = dashRect.y + (dashRect.height - firstRect.height);
00717           over = 0.0f;
00718           currRect = firstRect;
00719         } else {
00720           currRect = dashRect;
00721         }
00722 
00723         while (currRect.YMost() > borderInside.y) {
00724           //clip if necessary
00725           if (currRect.y < borderInside.y) {
00726             over = float(borderInside.y - dashRect.y) /
00727               float(dashRect.height);
00728             currRect.height = currRect.height - (borderInside.y - currRect.y);
00729             currRect.y = borderInside.y;
00730           }
00731 
00732           //draw if necessary
00733           if (bSolid) {
00734             aContext.FillRect(currRect);
00735           }
00736 
00737           //setup for next iteration
00738           if (over == 0.0f) {
00739             bSolid = PRBool(!bSolid);
00740           }
00741           dashRect.y = dashRect.y - currRect.height;
00742           currRect = dashRect;
00743         }
00744         break;
00745 
00746       case NS_SIDE_TOP:
00747         //if we are continuing a solid rect, fill in the corner first
00748         if (bSolid) {
00749           aContext.FillRect(borderOutside.x, borderOutside.y,
00750                             borderInside.x - borderOutside.x,
00751                             borderInside.y - borderOutside.y);
00752         }
00753 
00754         dashRect.height = borderInside.y - borderOutside.y;
00755         dashRect.width = dashRect.height * dashLength;
00756         dashRect.x = borderInside.x;
00757         dashRect.y = borderOutside.y;
00758 
00759         if (over > 0.0f) {
00760           firstRect.x = dashRect.x;
00761           firstRect.y = dashRect.y;
00762           firstRect.width = nscoord(dashRect.width * over);
00763           firstRect.height = dashRect.height;
00764           over = 0.0f;
00765           currRect = firstRect;
00766         } else {
00767           currRect = dashRect;
00768         }
00769 
00770         while (currRect.x < borderInside.XMost()) {
00771           //clip if necessary
00772           if (currRect.XMost() > borderInside.XMost()) {
00773             over = float(dashRect.XMost() - borderInside.XMost()) /
00774               float(dashRect.width);
00775             currRect.width = currRect.width -
00776               (currRect.XMost() - borderInside.XMost());
00777           }
00778 
00779           //draw if necessary
00780           if (bSolid) {
00781             aContext.FillRect(currRect);
00782           }
00783 
00784           //setup for next iteration
00785           if (over == 0.0f) {
00786             bSolid = PRBool(!bSolid);
00787           }
00788           dashRect.x = dashRect.x + currRect.width;
00789           currRect = dashRect;
00790         }
00791         break;
00792 
00793       case NS_SIDE_RIGHT:
00794         //if we are continuing a solid rect, fill in the corner first
00795         if (bSolid) {
00796           aContext.FillRect(borderInside.XMost(), borderOutside.y,
00797                             borderOutside.XMost() - borderInside.XMost(),
00798                             borderInside.y - borderOutside.y);
00799         }
00800 
00801         dashRect.width = borderOutside.XMost() - borderInside.XMost();
00802         dashRect.height = nscoord(dashRect.width * dashLength);
00803         dashRect.x = borderInside.XMost();
00804         dashRect.y = borderInside.y;
00805 
00806         if (over > 0.0f) {
00807           firstRect.x = dashRect.x;
00808           firstRect.y = dashRect.y;
00809           firstRect.width = dashRect.width;
00810           firstRect.height = nscoord(dashRect.height * over);
00811           over = 0.0f;
00812           currRect = firstRect;
00813         } else {
00814           currRect = dashRect;
00815         }
00816 
00817         while (currRect.y < borderInside.YMost()) {
00818           //clip if necessary
00819           if (currRect.YMost() > borderInside.YMost()) {
00820             over = float(dashRect.YMost() - borderInside.YMost()) /
00821               float(dashRect.height);
00822             currRect.height = currRect.height -
00823               (currRect.YMost() - borderInside.YMost());
00824           }
00825 
00826           //draw if necessary
00827           if (bSolid) {
00828             aContext.FillRect(currRect);
00829           }
00830 
00831           //setup for next iteration
00832           if (over == 0.0f) {
00833             bSolid = PRBool(!bSolid);
00834           }
00835           dashRect.y = dashRect.y + currRect.height;
00836           currRect = dashRect;
00837         }
00838         break;
00839 
00840       case NS_SIDE_BOTTOM:
00841         //if we are continuing a solid rect, fill in the corner first
00842         if (bSolid) {
00843           aContext.FillRect(borderInside.XMost(), borderInside.YMost(),
00844                             borderOutside.XMost() - borderInside.XMost(),
00845                             borderOutside.YMost() - borderInside.YMost());
00846         }
00847 
00848         dashRect.height = borderOutside.YMost() - borderInside.YMost();
00849         dashRect.width = nscoord(dashRect.height * dashLength);
00850         dashRect.x = borderInside.XMost() - dashRect.width;
00851         dashRect.y = borderInside.YMost();
00852 
00853         if (over > 0.0f) {
00854           firstRect.y = dashRect.y;
00855           firstRect.width = nscoord(dashRect.width * over);
00856           firstRect.height = dashRect.height;
00857           firstRect.x = dashRect.x + (dashRect.width - firstRect.width);
00858           over = 0.0f;
00859           currRect = firstRect;
00860         } else {
00861           currRect = dashRect;
00862         }
00863 
00864         while (currRect.XMost() > borderInside.x) {
00865           //clip if necessary
00866           if (currRect.x < borderInside.x) {
00867             over = float(borderInside.x - dashRect.x) / float(dashRect.width);
00868             currRect.width = currRect.width - (borderInside.x - currRect.x);
00869             currRect.x = borderInside.x;
00870           }
00871 
00872           //draw if necessary
00873           if (bSolid) {
00874             aContext.FillRect(currRect);
00875           }
00876 
00877           //setup for next iteration
00878           if (over == 0.0f) {
00879             bSolid = PRBool(!bSolid);
00880           }
00881           dashRect.x = dashRect.x - currRect.width;
00882           currRect = dashRect;
00883         }
00884         break;
00885       }
00886     }
00887     skippedSide = PR_FALSE;
00888   }
00889 }
00890 
00895 void nsCSSRendering::DrawDashedSides(PRIntn startSide,
00896                                      nsIRenderingContext& aContext,
00897                                      const nsRect& aDirtyRect,
00898                                      const nsStyleColor* aColorStyle,
00899                                      const nsStyleBorder* aBorderStyle,  
00900                                      const nsStyleOutline* aOutlineStyle,  
00901                                      PRBool aDoOutline,
00902                                      const nsRect& borderOutside,
00903                                      const nsRect& borderInside,
00904                                      PRIntn aSkipSides,
00905                    /* XXX unused */  nsRect* aGap)
00906 {
00907 
00908 PRIntn  dashLength;
00909 nsRect  dashRect, currRect;
00910 nscoord temp, temp1, adjust;
00911 PRBool  bSolid = PR_TRUE;
00912 float   over = 0.0f;
00913 PRBool  skippedSide = PR_FALSE;
00914 const nscolor kBlackColor = NS_RGB(0,0,0);
00915 
00916   NS_ASSERTION((aDoOutline && aOutlineStyle) || (!aDoOutline && aBorderStyle), "null params not allowed");
00917   PRUint8 style = aDoOutline
00918                   ? aOutlineStyle->GetOutlineStyle()
00919                   : aBorderStyle->GetBorderStyle(startSide);  
00920 
00921   // find the x and y width
00922   nscoord xwidth = aDirtyRect.XMost();
00923   nscoord ywidth = aDirtyRect.YMost();
00924 
00925   for (PRIntn whichSide = startSide; whichSide < 4; whichSide++) {
00926     PRUint8 prevStyle = style;
00927     style = aDoOutline
00928               ? aOutlineStyle->GetOutlineStyle()
00929               : aBorderStyle->GetBorderStyle(whichSide);  
00930     if ((1<<whichSide) & aSkipSides) {
00931       // Skipped side
00932       skippedSide = PR_TRUE;
00933       continue;
00934     }
00935     if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
00936         (style == NS_STYLE_BORDER_STYLE_DOTTED))
00937     {
00938       if ((style != prevStyle) || skippedSide) {
00939         //style discontinuity
00940         over = 0.0f;
00941         bSolid = PR_TRUE;
00942       }
00943 
00944       if (style == NS_STYLE_BORDER_STYLE_DASHED) {
00945         dashLength = DASH_LENGTH;
00946       } else {
00947         dashLength = DOT_LENGTH;
00948       }
00949 
00950       nscolor sideColor(kBlackColor); // default to black in case color cannot be resolved
00951                                       // (because invert is not supported on cur platform)
00952       PRBool  isInvert=PR_FALSE;
00953       if (aDoOutline) {
00954         // see if the outline color is 'invert'
00955         if (aOutlineStyle->GetOutlineInvert()) { 
00956           isInvert = PR_TRUE;
00957         } else {
00958           aOutlineStyle->GetOutlineColor(sideColor);
00959         }
00960       } else {
00961         PRBool transparent; 
00962         PRBool foreground;
00963         aBorderStyle->GetBorderColor(whichSide, sideColor, transparent, foreground);
00964         if (foreground)
00965           sideColor = aColorStyle->mColor;
00966         if (transparent)
00967           continue; // side is transparent
00968       }
00969       aContext.SetColor(sideColor);  
00970 
00971       switch (whichSide) {
00972       case NS_SIDE_RIGHT:
00973       case NS_SIDE_LEFT:
00974         bSolid = PR_FALSE;
00975         
00976         // This is our dot or dash..
00977         if(whichSide==NS_SIDE_LEFT){ 
00978           dashRect.width = borderInside.x - borderOutside.x;
00979         } else {
00980           dashRect.width = borderOutside.XMost() - borderInside.XMost();
00981         }
00982         if( dashRect.width >0 ) {
00983           dashRect.height = dashRect.width * dashLength;
00984           dashRect.y = borderOutside.y;
00985 
00986           if(whichSide == NS_SIDE_RIGHT){
00987             dashRect.x = borderInside.XMost();
00988           } else {
00989             dashRect.x = borderOutside.x;
00990           }
00991 
00992           temp = borderOutside.YMost();
00993           temp1 = temp/dashRect.height;
00994 
00995           currRect = dashRect;
00996 
00997           if((temp1%2)==0){
00998             adjust = (dashRect.height-(temp%dashRect.height))/2; // adjust back
00999             // draw in the left and right
01000             FillOrInvertRect(aContext,  dashRect.x, borderOutside.y,dashRect.width, dashRect.height-adjust,isInvert);
01001             FillOrInvertRect(aContext,dashRect.x,(borderOutside.YMost()-(dashRect.height-adjust)),dashRect.width, dashRect.height-adjust,isInvert);
01002             currRect.y += (dashRect.height-adjust);
01003             temp = temp-= (dashRect.height-adjust);
01004           } else {
01005             adjust = (temp%dashRect.width)/2;                   // adjust a tad longer
01006             // draw in the left and right
01007             FillOrInvertRect(aContext, dashRect.x, borderOutside.y,dashRect.width, dashRect.height+adjust,isInvert);
01008             FillOrInvertRect(aContext, dashRect.x,(borderOutside.YMost()-(dashRect.height+adjust)),dashRect.width, dashRect.height+adjust,isInvert);
01009             currRect.y += (dashRect.height+adjust);
01010             temp = temp-= (dashRect.height+adjust);
01011           }
01012         
01013           if( temp > ywidth)
01014             temp = ywidth;
01015 
01016           // get the currRect's x into the view before we start
01017           if( currRect.y < aDirtyRect.y){
01018             temp1 = NSToCoordFloor((float)((aDirtyRect.y-currRect.y)/dashRect.height));
01019             currRect.y += temp1*dashRect.height;
01020             if((temp1%2)==1){
01021               bSolid = PR_TRUE;
01022             }
01023          }
01024 
01025           while(currRect.y<temp) {
01026             //draw if necessary
01027             if (bSolid) {
01028               FillOrInvertRect(aContext, currRect,isInvert);
01029             }
01030 
01031             bSolid = PRBool(!bSolid);
01032             currRect.y += dashRect.height;
01033           }
01034         }
01035         break;
01036 
01037       case NS_SIDE_BOTTOM:
01038       case NS_SIDE_TOP:
01039         bSolid = PR_FALSE;
01040         
01041         // This is our dot or dash..
01042 
01043         if(whichSide==NS_SIDE_TOP){ 
01044           dashRect.height = borderInside.y - borderOutside.y;
01045         } else {
01046           dashRect.height = borderOutside.YMost() - borderInside.YMost();
01047         }
01048         if( dashRect.height >0 ) {
01049           dashRect.width = dashRect.height * dashLength;
01050           dashRect.x = borderOutside.x;
01051 
01052           if(whichSide == NS_SIDE_BOTTOM){
01053             dashRect.y = borderInside.YMost();
01054           } else {
01055             dashRect.y = borderOutside.y;
01056           }
01057 
01058           temp = borderOutside.XMost();
01059           temp1 = temp/dashRect.width;
01060 
01061           currRect = dashRect;
01062 
01063           if((temp1%2)==0){
01064             adjust = (dashRect.width-(temp%dashRect.width))/2;     // even, adjust back
01065             // draw in the left and right
01066             FillOrInvertRect(aContext, borderOutside.x,dashRect.y,dashRect.width-adjust,dashRect.height,isInvert);
01067             FillOrInvertRect(aContext, (borderOutside.XMost()-(dashRect.width-adjust)),dashRect.y,dashRect.width-adjust,dashRect.height,isInvert);
01068             currRect.x += (dashRect.width-adjust);
01069             temp = temp-= (dashRect.width-adjust);
01070           } else {
01071             adjust = (temp%dashRect.width)/2;
01072             // draw in the left and right
01073             FillOrInvertRect(aContext, borderOutside.x,dashRect.y,dashRect.width+adjust,dashRect.height,isInvert);
01074             FillOrInvertRect(aContext, (borderOutside.XMost()-(dashRect.width+adjust)),dashRect.y,dashRect.width+adjust,dashRect.height,isInvert);
01075             currRect.x += (dashRect.width+adjust);
01076             temp = temp-= (dashRect.width+adjust);
01077           }
01078        
01079 
01080           if( temp > xwidth)
01081             temp = xwidth;
01082 
01083           // get the currRect's x into the view before we start
01084           if( currRect.x < aDirtyRect.x){
01085             temp1 = NSToCoordFloor((float)((aDirtyRect.x-currRect.x)/dashRect.width));
01086             currRect.x += temp1*dashRect.width;
01087             if((temp1%2)==1){
01088               bSolid = PR_TRUE;
01089             }
01090           }
01091 
01092           while(currRect.x<temp) {
01093             //draw if necessary
01094             if (bSolid) {
01095               FillOrInvertRect(aContext, currRect,isInvert);
01096             }
01097 
01098             bSolid = PRBool(!bSolid);
01099             currRect.x += dashRect.width;
01100           }
01101         }
01102       break;
01103       }
01104     }
01105     skippedSide = PR_FALSE;
01106   }
01107 }
01108 
01109 /* draw the portions of the border described in aBorderEdges that are dashed.
01110  * a border has 4 edges.  Each edge has 1 or more segments. 
01111  * "inside edges" are drawn differently than "outside edges" so the shared edges will match up.
01112  * in the case of table collapsing borders, the table edge is the "outside" edge and
01113  * cell edges are always "inside" edges (so adjacent cells have 2 shared "inside" edges.)
01114  * There is a case for each of the four sides.  Only the left side is well documented.  The others
01115  * are very similar.
01116  */
01117 // XXX: doesn't do corners or junctions well at all.  Just uses logic stolen 
01118 //      from DrawDashedSides which is insufficient
01119 void nsCSSRendering::DrawDashedSegments(nsIRenderingContext& aContext,
01120                                         const nsRect& aBounds,
01121                                         nsBorderEdges * aBorderEdges,
01122                                         PRIntn aSkipSides,
01123                       /* XXX unused */  nsRect* aGap)
01124 {
01125 PRIntn dashLength;
01126 nsRect dashRect, currRect;
01127 
01128 PRBool  bSolid = PR_TRUE;
01129 float   over = 0.0f;
01130 PRBool  skippedSide = PR_FALSE;
01131 PRIntn  whichSide=0;
01132 
01133 
01134   // do this just to set up initial condition for loop
01135   // "segment" is the current portion of the edge we are computing
01136   nsBorderEdge * segment =  (nsBorderEdge *)(aBorderEdges->mEdges[whichSide].ElementAt(0));
01137   PRUint8 style = segment->mStyle;  
01138   for ( ; whichSide < 4; whichSide++) 
01139   {
01140     if ((1<<whichSide) & aSkipSides) {
01141       // Skipped side
01142       skippedSide = PR_TRUE;
01143       continue;
01144     }
01145     nscoord x=0;  nscoord y=0;
01146     PRInt32 i;
01147     PRInt32 segmentCount = aBorderEdges->mEdges[whichSide].Count();
01148     nsBorderEdges * neighborBorderEdges=nsnull;
01149     PRIntn neighborEdgeCount=0; // keeps track of which inside neighbor is shared with an outside segment
01150     for (i=0; i<segmentCount; i++)
01151     {
01152       bSolid=PR_TRUE;
01153       over = 0.0f;
01154       segment =  (nsBorderEdge *)(aBorderEdges->mEdges[whichSide].ElementAt(i));
01155       style = segment->mStyle;
01156 
01157       // XXX units for dash & dot?
01158       if (style == NS_STYLE_BORDER_STYLE_DASHED) {
01159         dashLength = DASH_LENGTH;
01160       } else {
01161         dashLength = DOT_LENGTH;
01162       }
01163 
01164       aContext.SetColor(segment->mColor);  
01165       switch (whichSide) {
01166       case NS_SIDE_LEFT:
01167       { // draw left segment i
01168         nsBorderEdge * topEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(0));
01169         if (0==y)
01170         { // y is the offset to the top of this segment.  0 means its the topmost left segment
01171           y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
01172           if (PR_TRUE==aBorderEdges->mOutsideEdge)
01173             y += topEdge->mWidth;
01174         }
01175         // the x offset is the x position offset by the max width of the left edge minus this segment's width
01176         x = aBounds.x + (aBorderEdges->mMaxBorderWidth.left - segment->mWidth);
01177         nscoord height = segment->mLength;
01178         // the space between borderOutside and borderInside inclusive is the segment.
01179         nsRect borderOutside(x, y, aBounds.width, height);
01180         y += segment->mLength;  // keep track of the y offset for the next segment
01181         if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
01182             (style == NS_STYLE_BORDER_STYLE_DOTTED))
01183         {
01184           nsRect borderInside(borderOutside);
01185           nsMargin outsideMargin(segment->mWidth, 0, 0, 0);
01186           borderInside.Deflate(outsideMargin);
01187           nscoord totalLength = segment->mLength; // the computed length of this segment
01188           // outside edges need info from their inside neighbor.  The following code keeps track
01189           // of which segment of the inside neighbor's shared edge we should use for this outside segment
01190           if (PR_TRUE==aBorderEdges->mOutsideEdge)
01191           {
01192             if (segment->mInsideNeighbor == neighborBorderEdges)
01193             {
01194               neighborEdgeCount++;
01195             }
01196             else 
01197             {
01198               neighborBorderEdges = segment->mInsideNeighbor;
01199               neighborEdgeCount=0;
01200             }
01201             nsBorderEdge * neighborLeft = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_LEFT].ElementAt(neighborEdgeCount));
01202             totalLength = neighborLeft->mLength;
01203           }
01204           dashRect.width = borderInside.x - borderOutside.x;
01205           dashRect.height = nscoord(dashRect.width * dashLength);
01206           dashRect.x = borderOutside.x;
01207           dashRect.y = borderOutside.y + (totalLength/2) - dashRect.height;
01208           if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
01209             dashRect.y -= topEdge->mWidth;  // account for the topmost left edge corner with the leftmost top edge
01210           if (0)
01211           {
01212             printf("  L: totalLength = %d, borderOutside.y = %d, midpoint %d, dashRect.y = %d\n", 
01213             totalLength, borderOutside.y, borderOutside.y +(totalLength/2), dashRect.y); 
01214           }
01215           currRect = dashRect;
01216 
01217           // we draw the segment in 2 halves to get the inside and outside edges to line up on the
01218           // centerline of the shared edge.
01219 
01220           // draw the top half
01221           while (currRect.YMost() > borderInside.y) {
01222             //clip if necessary
01223             if (currRect.y < borderInside.y) {
01224               over = float(borderInside.y - dashRect.y) /
01225                 float(dashRect.height);
01226               currRect.height = currRect.height - (borderInside.y - currRect.y);
01227               currRect.y = borderInside.y;
01228             }
01229 
01230             //draw if necessary
01231             if (0)
01232             {
01233               printf("DASHED LEFT: xywh in loop currRect = %d %d %d %d %s\n", 
01234                    currRect.x, currRect.y, currRect.width, currRect.height, bSolid?"TRUE":"FALSE");
01235             }
01236             if (bSolid) {
01237               aContext.FillRect(currRect);
01238             }
01239 
01240             //setup for next iteration
01241             if (over == 0.0f) {
01242               bSolid = PRBool(!bSolid);
01243             }
01244             dashRect.y = dashRect.y - currRect.height;
01245             currRect = dashRect;
01246           }
01247 
01248           // draw the bottom half
01249           dashRect.y = borderOutside.y + (totalLength/2) + dashRect.height;
01250           if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
01251             dashRect.y -= topEdge->mWidth;
01252           currRect = dashRect;
01253           bSolid=PR_TRUE;
01254           over = 0.0f;
01255           while (currRect.YMost() < borderInside.YMost()) {
01256             //clip if necessary
01257             if (currRect.y < borderInside.y) {
01258               over = float(borderInside.y - dashRect.y) /
01259                 float(dashRect.height);
01260               currRect.height = currRect.height - (borderInside.y - currRect.y);
01261               currRect.y = borderInside.y;
01262             }
01263 
01264             //draw if necessary
01265             if (0)
01266             {
01267               printf("DASHED LEFT: xywh in loop currRect = %d %d %d %d %s\n", 
01268                    currRect.x, currRect.y, currRect.width, currRect.height, bSolid?"TRUE":"FALSE");
01269             }
01270             if (bSolid) {
01271               aContext.FillRect(currRect);
01272             }
01273 
01274             //setup for next iteration
01275             if (over == 0.0f) {
01276               bSolid = PRBool(!bSolid);
01277             }
01278             dashRect.y = dashRect.y + currRect.height;
01279             currRect = dashRect;
01280           }
01281         }
01282       }
01283       break;
01284 
01285       case NS_SIDE_TOP:
01286       { // draw top segment i
01287         if (0==x)
01288         {
01289           nsBorderEdge * leftEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
01290           x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
01291         }
01292         y = aBounds.y;
01293         if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are bottom-aligned
01294           y += aBorderEdges->mMaxBorderWidth.top - segment->mWidth;
01295         nsRect borderOutside(x, y, segment->mLength, aBounds.height);
01296         x += segment->mLength;
01297         if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
01298             (style == NS_STYLE_BORDER_STYLE_DOTTED))
01299         {
01300           nsRect borderInside(borderOutside);
01301           nsBorderEdge * neighbor;
01302           // XXX Adding check to make sure segment->mInsideNeighbor is not null
01303           // so it will do the else part, at this point we are assuming this is an
01304           // ok thing to do (Bug 52130)
01305           if (PR_TRUE==aBorderEdges->mOutsideEdge && segment->mInsideNeighbor)
01306             neighbor = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_LEFT].ElementAt(0));
01307           else
01308             neighbor = (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
01309           nsMargin outsideMargin(neighbor->mWidth, segment->mWidth, 0, segment->mWidth);
01310           borderInside.Deflate(outsideMargin);
01311           nscoord firstRectWidth = 0;
01312           if (PR_TRUE==aBorderEdges->mOutsideEdge && 0==i)
01313           {
01314             firstRectWidth = borderInside.x - borderOutside.x;
01315             aContext.FillRect(borderOutside.x, borderOutside.y,
01316                               firstRectWidth,
01317                               borderInside.y - borderOutside.y);
01318           }
01319 
01320           dashRect.height = borderInside.y - borderOutside.y;
01321           dashRect.width = dashRect.height * dashLength;
01322           dashRect.x = borderOutside.x + firstRectWidth;
01323           dashRect.y = borderOutside.y;
01324           currRect = dashRect;
01325 
01326           while (currRect.x < borderInside.XMost()) {
01327             //clip if necessary
01328             if (currRect.XMost() > borderInside.XMost()) {
01329               over = float(dashRect.XMost() - borderInside.XMost()) /
01330                 float(dashRect.width);
01331               currRect.width = currRect.width -
01332                 (currRect.XMost() - borderInside.XMost());
01333             }
01334 
01335             //draw if necessary
01336             if (bSolid) {
01337               aContext.FillRect(currRect);
01338             }
01339 
01340             //setup for next iteration
01341             if (over == 0.0f) {
01342               bSolid = PRBool(!bSolid);
01343             }
01344             dashRect.x = dashRect.x + currRect.width;
01345             currRect = dashRect;
01346           }
01347         }
01348       }
01349       break;
01350 
01351       case NS_SIDE_RIGHT:
01352       { // draw right segment i
01353         nsBorderEdge * topEdge =  (nsBorderEdge *)
01354             (aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(aBorderEdges->mEdges[NS_SIDE_TOP].Count()-1));
01355         if (0==y)
01356         {
01357           y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
01358           if (PR_TRUE==aBorderEdges->mOutsideEdge)
01359             y += topEdge->mWidth;
01360         }
01361         nscoord width;
01362         if (PR_TRUE==aBorderEdges->mOutsideEdge)
01363         {
01364           width = aBounds.width - aBorderEdges->mMaxBorderWidth.right;
01365           width += segment->mWidth;
01366         }
01367         else
01368         {
01369           width = aBounds.width;
01370         }
01371         nscoord height = segment->mLength;
01372         nsRect borderOutside(aBounds.x, y, width, height);
01373         y += segment->mLength;
01374         if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
01375             (style == NS_STYLE_BORDER_STYLE_DOTTED))
01376         {
01377           nsRect borderInside(borderOutside);
01378           nsMargin outsideMargin(segment->mWidth, 0, (segment->mWidth), 0);
01379           borderInside.Deflate(outsideMargin);
01380           nscoord totalLength = segment->mLength;
01381           if (PR_TRUE==aBorderEdges->mOutsideEdge)
01382           {
01383             if (segment->mInsideNeighbor == neighborBorderEdges)
01384             {
01385               neighborEdgeCount++;
01386             }
01387             else 
01388             {
01389               neighborBorderEdges = segment->mInsideNeighbor;
01390               neighborEdgeCount=0;
01391             }
01392             nsBorderEdge * neighborRight = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_RIGHT].ElementAt(neighborEdgeCount));
01393             totalLength = neighborRight->mLength;
01394           }
01395           dashRect.width = borderOutside.XMost() - borderInside.XMost();
01396           dashRect.height = nscoord(dashRect.width * dashLength);
01397           dashRect.x = borderInside.XMost();
01398           dashRect.y = borderOutside.y + (totalLength/2) - dashRect.height;
01399           if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
01400             dashRect.y -= topEdge->mWidth;
01401           currRect = dashRect;
01402 
01403           // draw the top half
01404           while (currRect.YMost() > borderInside.y) {
01405             //clip if necessary
01406             if (currRect.y < borderInside.y) {
01407               over = float(borderInside.y - dashRect.y) /
01408                 float(dashRect.height);
01409               currRect.height = currRect.height - (borderInside.y - currRect.y);
01410               currRect.y = borderInside.y;
01411             }
01412 
01413             //draw if necessary
01414             if (bSolid) {
01415               aContext.FillRect(currRect);
01416             }
01417 
01418             //setup for next iteration
01419             if (over == 0.0f) {
01420               bSolid = PRBool(!bSolid);
01421             }
01422             dashRect.y = dashRect.y - currRect.height;
01423             currRect = dashRect;
01424           }
01425 
01426           // draw the bottom half
01427           dashRect.y = borderOutside.y + (totalLength/2) + dashRect.height;
01428           if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
01429             dashRect.y -= topEdge->mWidth;
01430           currRect = dashRect;
01431           bSolid=PR_TRUE;
01432           over = 0.0f;
01433           while (currRect.YMost() < borderInside.YMost()) {
01434             //clip if necessary
01435             if (currRect.y < borderInside.y) {
01436               over = float(borderInside.y - dashRect.y) /
01437                 float(dashRect.height);
01438               currRect.height = currRect.height - (borderInside.y - currRect.y);
01439               currRect.y = borderInside.y;
01440             }
01441 
01442             //draw if necessary
01443             if (bSolid) {
01444               aContext.FillRect(currRect);
01445             }
01446 
01447             //setup for next iteration
01448             if (over == 0.0f) {
01449               bSolid = PRBool(!bSolid);
01450             }
01451             dashRect.y = dashRect.y + currRect.height;
01452             currRect = dashRect;
01453           }
01454 
01455         }
01456       }
01457       break;
01458 
01459       case NS_SIDE_BOTTOM:
01460       {  // draw bottom segment i
01461         if (0==x)
01462         {
01463           nsBorderEdge * leftEdge =  (nsBorderEdge *)
01464             (aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(aBorderEdges->mEdges[NS_SIDE_LEFT].Count()-1));
01465           x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
01466         }
01467         y = aBounds.y;
01468         if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are top-aligned
01469           y -= aBorderEdges->mMaxBorderWidth.bottom - segment->mWidth;
01470         nsRect borderOutside(x, y, segment->mLength, aBounds.height);
01471         x += segment->mLength;
01472         if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
01473             (style == NS_STYLE_BORDER_STYLE_DOTTED))
01474         {
01475           nsRect borderInside(borderOutside);
01476           nsBorderEdge * neighbor;
01477           if (PR_TRUE==aBorderEdges->mOutsideEdge)
01478             neighbor = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_LEFT].ElementAt(0));
01479           else
01480             neighbor = (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
01481           nsMargin outsideMargin(neighbor->mWidth, segment->mWidth, 0, segment->mWidth);
01482           borderInside.Deflate(outsideMargin);
01483           nscoord firstRectWidth = 0;
01484           if (PR_TRUE==aBorderEdges->mOutsideEdge  &&  0==i)
01485           {
01486             firstRectWidth = borderInside.x - borderOutside.x;
01487             aContext.FillRect(borderOutside.x, borderInside.YMost(),
01488                               firstRectWidth,
01489                               borderOutside.YMost() - borderInside.YMost());
01490           }
01491 
01492           dashRect.height = borderOutside.YMost() - borderInside.YMost();
01493           dashRect.width = nscoord(dashRect.height * dashLength);
01494           dashRect.x = borderOutside.x + firstRectWidth;
01495           dashRect.y = borderInside.YMost();
01496           currRect = dashRect;
01497 
01498           while (currRect.x < borderInside.XMost()) {
01499             //clip if necessary
01500             if (currRect.XMost() > borderInside.XMost()) {
01501               over = float(dashRect.XMost() - borderInside.XMost()) / 
01502                 float(dashRect.width);
01503               currRect.width = currRect.width -
01504                 (currRect.XMost() - borderInside.XMost());
01505             }
01506 
01507             //draw if necessary
01508             if (bSolid) {
01509               aContext.FillRect(currRect);
01510             }
01511 
01512             //setup for next iteration
01513             if (over == 0.0f) {
01514               bSolid = PRBool(!bSolid);
01515             }
01516             dashRect.x = dashRect.x + currRect.width;
01517             currRect = dashRect;
01518           }
01519         }
01520       }
01521       break;
01522       }
01523     }
01524     skippedSide = PR_FALSE;
01525   }
01526 }
01527 
01528 nscolor
01529 nsCSSRendering::TransformColor(nscolor  aMapColor,PRBool aNoBackGround)
01530 {
01531 PRUint16  hue,sat,value;
01532 nscolor   newcolor;
01533 
01534   newcolor = aMapColor;
01535   if (PR_TRUE == aNoBackGround){
01536     // convert the RBG to HSV so we can get the lightness (which is the v)
01537     NS_RGB2HSV(newcolor,hue,sat,value);
01538     // The goal here is to send white to black while letting colored
01539     // stuff stay colored... So we adopt the following approach.
01540     // Something with sat = 0 should end up with value = 0.  Something
01541     // with a high sat can end up with a high value and it's ok.... At
01542     // the same time, we don't want to make things lighter.  Do
01543     // something simple, since it seems to work.
01544     if (value > sat) {
01545       value = sat;
01546       // convert this color back into the RGB color space.
01547       NS_HSV2RGB(newcolor,hue,sat,value);
01548     }
01549   }
01550   return newcolor;
01551 }
01552 
01553 // method GetBGColorForHTMLElement
01554 //
01555 // Now here's a *fun* hack: Nav4 uses the BODY element's background color for the 
01556 //                          background color on tables so we need to find that element's
01557 //                          color and use it... Actually, we can use the HTML element as well.
01558 //
01559 // Traverse from PresContext to PresShell to Document to RootContent. The RootContent is
01560 // then checked to ensure that it is the HTML or BODY element, and if it is, we get
01561 // it's primary frame and from that the style context and from that the color to use.
01562 //
01563 PRBool GetBGColorForHTMLElement( nsPresContext *aPresContext,
01564                                    const nsStyleBackground *&aBGColor )
01565 {
01566   NS_ASSERTION(aPresContext, "null params not allowed");
01567   PRBool result = PR_FALSE; // assume we did not find the HTML element
01568 
01569   nsIPresShell* shell = aPresContext->GetPresShell();
01570   if (shell) {
01571     nsIDocument *doc = shell->GetDocument();
01572     if (doc) {
01573       nsIContent *pContent;
01574       if ((pContent = doc->GetRootContent())) {
01575         // make sure that this is the HTML element
01576         nsIAtom *tag = pContent->Tag();
01577         NS_ASSERTION(tag, "Tag could not be retrieved from root content element");
01578         if (tag == nsHTMLAtoms::html ||
01579             tag == nsHTMLAtoms::body) {
01580           // use this guy's color
01581           nsIFrame *pFrame = nsnull;
01582           if (NS_SUCCEEDED(shell->GetPrimaryFrameFor(pContent, &pFrame)) &&
01583               pFrame) {
01584             nsStyleContext *pContext = pFrame->GetStyleContext();
01585             if (pContext) {
01586               const nsStyleBackground* color = pContext->GetStyleBackground();
01587               if (0 == (color->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT)) {
01588                 aBGColor = color;
01589                 // set the reslt to TRUE to indicate we mapped the color
01590                 result = PR_TRUE;
01591               }
01592             }// if context
01593           }// if frame
01594         }// if tag == html or body
01595 #ifdef DEBUG
01596         else {
01597           printf( "Root Content is not HTML or BODY: cannot get bgColor of HTML or BODY\n");
01598         }
01599 #endif
01600       }// if content
01601     }// if doc
01602   } // if shell
01603 
01604   return result;
01605 }
01606 
01607 // helper macro to determine if the borderstyle 'a' is a MOZ-BG-XXX style
01608 #define MOZ_BG_BORDER(a)\
01609 ((a==NS_STYLE_BORDER_STYLE_BG_INSET) || (a==NS_STYLE_BORDER_STYLE_BG_OUTSET)\
01610                                      || (a==NS_STYLE_BORDER_STYLE_BG_SOLID))
01611 
01612 static
01613 PRBool GetBorderColor(const nsStyleColor* aColor, const nsStyleBorder& aBorder, PRUint8 aSide, nscolor& aColorVal,
01614                       nsBorderColors** aCompositeColors = nsnull)
01615 {
01616   PRBool transparent;
01617   PRBool foreground;
01618 
01619   if (aCompositeColors) {
01620     aBorder.GetCompositeColors(aSide, aCompositeColors);
01621     if (*aCompositeColors)
01622       return PR_TRUE;
01623   }
01624 
01625   aBorder.GetBorderColor(aSide, aColorVal, transparent, foreground);
01626   if (foreground)
01627     aColorVal = aColor->mColor;
01628 
01629   return !transparent;
01630 }
01631 
01632 // XXX improve this to constrain rendering to the damaged area
01633 void nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
01634                                  nsIRenderingContext& aRenderingContext,
01635                                  nsIFrame* aForFrame,
01636                                  const nsRect& aDirtyRect,
01637                                  const nsRect& aBorderArea,
01638                                  const nsStyleBorder& aBorderStyle,
01639                                  nsStyleContext* aStyleContext,
01640                                  PRIntn aSkipSides,
01641                                  nsRect* aGap,
01642                                  nscoord aHardBorderSize,
01643                                  PRBool  aShouldIgnoreRounded)
01644 {
01645   PRIntn              cnt;
01646   nsMargin            border;
01647   nsStyleCoord        bordStyleRadius[4];
01648   PRInt16             borderRadii[4],i;
01649   float               percent;
01650   nsCompatibility     compatMode = aPresContext->CompatibilityMode();
01651   PRBool              forceSolid;
01652 
01653   // Check to see if we have an appearance defined.  If so, we let the theme
01654   // renderer draw the border.  DO not get the data from aForFrame, since the passed in style context
01655   // may be different!  Always use |aStyleContext|!
01656   const nsStyleDisplay* displayData = aStyleContext->GetStyleDisplay();
01657   if (displayData->mAppearance) {
01658     nsITheme *theme = aPresContext->GetTheme();
01659     if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame, displayData->mAppearance))
01660       return; // Let the theme handle it.
01661   }
01662   // Get our style context's color struct.
01663   const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
01664 
01665   // in NavQuirks mode we want to use the parent's context as a starting point 
01666   // for determining the background color
01667   const nsStyleBackground* bgColor = 
01668     nsCSSRendering::FindNonTransparentBackground(aStyleContext, 
01669                                             compatMode == eCompatibility_NavQuirks ? PR_TRUE : PR_FALSE); 
01670 
01671   // mozBGColor is used instead of bgColor when the display type is BG_INSET or BG_OUTSET
01672   // or BG_SOLID, and, in quirk mode, it is set to the BODY element's background color
01673   // instead of the nearest ancestor's background color.
01674   const nsStyleBackground* mozBGColor = bgColor;
01675 
01676   // now check if we are in Quirks mode and have a border style of BG_INSET or OUTSET
01677   // or BG_SOLID - if so we use the bgColor from the HTML element instead of the
01678   // nearest ancestor
01679   if (compatMode == eCompatibility_NavQuirks) {
01680     PRBool bNeedBodyBGColor = PR_FALSE;
01681     if (aStyleContext) {
01682       for (cnt=0; cnt<4;cnt++) {
01683         bNeedBodyBGColor = MOZ_BG_BORDER(aBorderStyle.GetBorderStyle(cnt));
01684         if (bNeedBodyBGColor) {
01685           break;
01686         }
01687       }
01688     }
01689     if (bNeedBodyBGColor) {
01690       GetBGColorForHTMLElement(aPresContext, mozBGColor);
01691     } 
01692   }
01693 
01694   if (aHardBorderSize > 0) {
01695     border.SizeTo(aHardBorderSize, aHardBorderSize, aHardBorderSize, aHardBorderSize);
01696   } else {
01697     aBorderStyle.CalcBorderFor(aForFrame, border);
01698   }
01699   if ((0 == border.left) && (0 == border.right) &&
01700       (0 == border.top) && (0 == border.bottom)) {
01701     // Empty border area
01702     return;
01703   }
01704 
01705 
01706   // get the radius for our border
01707   aBorderStyle.mBorderRadius.GetTop(bordStyleRadius[0]);      //topleft
01708   aBorderStyle.mBorderRadius.GetRight(bordStyleRadius[1]);    //topright
01709   aBorderStyle.mBorderRadius.GetBottom(bordStyleRadius[2]);   //bottomright
01710   aBorderStyle.mBorderRadius.GetLeft(bordStyleRadius[3]);     //bottomleft
01711 
01712   for(i=0;i<4;i++) {
01713     borderRadii[i] = 0;
01714     switch ( bordStyleRadius[i].GetUnit()) {
01715     case eStyleUnit_Percent:
01716       percent = bordStyleRadius[i].GetPercentValue();
01717       borderRadii[i] = (nscoord)(percent * aBorderArea.width);
01718       break;
01719     case eStyleUnit_Coord:
01720       borderRadii[i] = bordStyleRadius[i].GetCoordValue();
01721       break;
01722     default:
01723       break;
01724     }
01725   }
01726 
01727   // rounded version of the outline
01728   // check for any corner that is rounded
01729   for(i=0;i<4;i++){
01730     if(borderRadii[i] > 0 && !aBorderStyle.mBorderColors){
01731       PaintRoundedBorder(aPresContext,aRenderingContext,aForFrame,aDirtyRect,aBorderArea,&aBorderStyle,nsnull,aStyleContext,aSkipSides,borderRadii,aGap,PR_FALSE);
01732       return;
01733     }
01734   }
01735 
01736   // Turn off rendering for all of the zero sized sides
01737   if (0 == border.top) aSkipSides |= (1 << NS_SIDE_TOP);
01738   if (0 == border.right) aSkipSides |= (1 << NS_SIDE_RIGHT);
01739   if (0 == border.bottom) aSkipSides |= (1 << NS_SIDE_BOTTOM);
01740   if (0 == border.left) aSkipSides |= (1 << NS_SIDE_LEFT);
01741 
01742   // get the inside and outside parts of the border
01743   nsRect outerRect(aBorderArea);
01744   nsRect innerRect(outerRect);
01745   innerRect.Deflate(border);
01746 
01747   if (border.left + border.right > aBorderArea.width) {
01748     innerRect.x = outerRect.x;
01749     innerRect.width = outerRect.width;
01750   }
01751   if (border.top + border.bottom > aBorderArea.height) {
01752     innerRect.y = outerRect.y;
01753     innerRect.height = outerRect.height;
01754   }
01755 
01756 
01757 
01758   // If the dirty rect is completely inside the border area (e.g., only the
01759   // content is being painted), then we can skip out now
01760   if (innerRect.Contains(aDirtyRect)) {
01761     return;
01762   }
01763  
01764   //see if any sides are dotted or dashed
01765   for (cnt = 0; cnt < 4; cnt++) {
01766     if ((aBorderStyle.GetBorderStyle(cnt) == NS_STYLE_BORDER_STYLE_DOTTED) || 
01767         (aBorderStyle.GetBorderStyle(cnt) == NS_STYLE_BORDER_STYLE_DASHED))  {
01768       break;
01769     }
01770   }
01771   if (cnt < 4) {
01772     DrawDashedSides(cnt, aRenderingContext,aDirtyRect, ourColor, &aBorderStyle,nsnull, PR_FALSE,
01773                     outerRect, innerRect, aSkipSides, aGap);
01774   }
01775 
01776   // dont clip the borders for composite borders, they use the inner and 
01777   // outer rect to compute the diagonale to cross the border radius
01778   nsRect compositeInnerRect(innerRect);
01779   nsRect compositeOuterRect(outerRect);
01780 
01781   // Draw all the other sides
01782   if (!aDirtyRect.Contains(outerRect)) {
01783     // Border leaks out of the dirty rectangle - lets clip it but with care
01784     if (innerRect.y < aDirtyRect.y) {
01785       aSkipSides |= (1 << NS_SIDE_TOP);
01786       PRUint32 shortenBy =
01787         PR_MIN(innerRect.height, aDirtyRect.y - innerRect.y);
01788       innerRect.y += shortenBy;
01789       innerRect.height -= shortenBy;
01790       outerRect.y += shortenBy;
01791       outerRect.height -= shortenBy;
01792     }
01793     if (aDirtyRect.YMost() < innerRect.YMost()) {
01794       aSkipSides |= (1 << NS_SIDE_BOTTOM);
01795       PRUint32 shortenBy =
01796         PR_MIN(innerRect.height, innerRect.YMost() - aDirtyRect.YMost());
01797       innerRect.height -= shortenBy;
01798       outerRect.height -= shortenBy;
01799     }
01800     if (innerRect.x < aDirtyRect.x) {
01801       aSkipSides |= (1 << NS_SIDE_LEFT);
01802       PRUint32 shortenBy =
01803         PR_MIN(innerRect.width, aDirtyRect.x - innerRect.x);
01804       innerRect.x += shortenBy;
01805       innerRect.width -= shortenBy;
01806       outerRect.x += shortenBy;
01807       outerRect.width -= shortenBy;
01808     }
01809     if (aDirtyRect.XMost() < innerRect.XMost()) {
01810       aSkipSides |= (1 << NS_SIDE_RIGHT);
01811       PRUint32 shortenBy =
01812         PR_MIN(innerRect.width, innerRect.XMost() - aDirtyRect.XMost());
01813       innerRect.width -= shortenBy;
01814       outerRect.width -= shortenBy;
01815     }
01816   }
01817   /* Get our conversion values */
01818   nscoord twipsPerPixel = aPresContext->IntScaledPixelsToTwips(1);
01819 
01820   static PRUint8 sideOrder[] = { NS_SIDE_BOTTOM, NS_SIDE_LEFT, NS_SIDE_TOP, NS_SIDE_RIGHT };
01821   nscolor sideColor;
01822   nsBorderColors* compositeColors = nsnull;
01823 
01824   for (cnt = 0; cnt < 4; cnt++) {
01825     PRUint8 side = sideOrder[cnt];
01826 
01827     // If a side needs a double/groove/ridge border but will be less than two
01828     // pixels, force it to be solid (see bug 1781 and bug 310124).
01829     if (aBorderStyle.GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_DOUBLE ||
01830         aBorderStyle.GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_GROOVE ||
01831         aBorderStyle.GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_RIDGE) {
01832       nscoord widths[] = { border.top, border.right, border.bottom, border.left };
01833       forceSolid = (widths[side]/twipsPerPixel < 2);
01834     } else 
01835       forceSolid = PR_FALSE;
01836 
01837     if (0 == (aSkipSides & (1<<side))) {
01838       if (GetBorderColor(ourColor, aBorderStyle, side, sideColor, &compositeColors)) {
01839         if (compositeColors)
01840           DrawCompositeSide(aRenderingContext, side, compositeColors, compositeOuterRect, 
01841                             compositeInnerRect, borderRadii, twipsPerPixel, aGap);
01842         else
01843           DrawSide(aRenderingContext, side,
01844                    forceSolid ? NS_STYLE_BORDER_STYLE_SOLID : aBorderStyle.GetBorderStyle(side),
01845                    sideColor,
01846                    MOZ_BG_BORDER(aBorderStyle.GetBorderStyle(side)) ? 
01847                     mozBGColor->mBackgroundColor :
01848                     bgColor->mBackgroundColor,
01849                    outerRect,innerRect, aSkipSides,
01850                    twipsPerPixel, aGap);
01851       }
01852     }
01853   }
01854 }
01855 
01856 void nsCSSRendering::DrawCompositeSide(nsIRenderingContext& aRenderingContext,
01857                                        PRIntn aWhichSide,
01858                                        nsBorderColors* aCompositeColors,
01859                                        const nsRect& aOuterRect,
01860                                        const nsRect& aInnerRect,
01861                                        PRInt16* aBorderRadii,
01862                                        nscoord twipsPerPixel,
01863                                        nsRect* aGap)
01864 
01865 {
01866   // Loop over each color and at each iteration shrink the length of the
01867   // lines that we draw.
01868   nsRect currOuterRect(aOuterRect);
01869 
01870   // XXXdwh This border radius code is rather hacky and will only work for
01871   // small radii, but it will be sufficient to get a major performance
01872   // improvement in themes with small curvature (like Modern).
01873   // Still, this code should be rewritten if/when someone chooses to pick
01874   // up the -moz-border-radius gauntlet.
01875   // Alternatively we could add support for a -moz-border-diagonal property, which is
01876   // what this code actually draws (instead of a curve).
01877 
01878   // determine the the number of pixels we need to draw for this side
01879   // and the start and end radii
01880   nscoord shrinkage, startRadius, endRadius;
01881   if (aWhichSide == NS_SIDE_TOP) {
01882     shrinkage = aInnerRect.y - aOuterRect.y;
01883     startRadius = aBorderRadii[0];
01884     endRadius = aBorderRadii[1];
01885   } else if (aWhichSide == NS_SIDE_BOTTOM) {
01886     shrinkage = (aOuterRect.height+aOuterRect.y) - (aInnerRect.height+aInnerRect.y);
01887     startRadius = aBorderRadii[3];
01888     endRadius = aBorderRadii[2];
01889   } else if (aWhichSide == NS_SIDE_RIGHT) {
01890     shrinkage = (aOuterRect.width+aOuterRect.x) - (aInnerRect.width+aInnerRect.x);
01891     startRadius = aBorderRadii[1];
01892     endRadius = aBorderRadii[2];
01893   } else {
01894     NS_ASSERTION(aWhichSide == NS_SIDE_LEFT, "incorrect aWhichSide");
01895     shrinkage = aInnerRect.x - aOuterRect.x;
01896     startRadius = aBorderRadii[0];
01897     endRadius = aBorderRadii[3];
01898   }
01899 
01900   while (shrinkage > 0) {
01901     nscoord xshrink = 0;
01902     nscoord yshrink = 0;
01903     nscoord widthshrink = 0;
01904     nscoord heightshrink = 0;
01905 
01906     if (startRadius || endRadius) {
01907       if (aWhichSide == NS_SIDE_TOP || aWhichSide == NS_SIDE_BOTTOM) {
01908         xshrink = startRadius;
01909         widthshrink = startRadius + endRadius;
01910       }
01911       else if (aWhichSide == NS_SIDE_LEFT || aWhichSide == NS_SIDE_RIGHT) {
01912         yshrink = startRadius-1;
01913         heightshrink = yshrink + endRadius;
01914       }
01915     }
01916 
01917     // subtract any rounded pixels from the outer rect
01918     nsRect newOuterRect(currOuterRect);
01919     newOuterRect.x += xshrink;
01920     newOuterRect.y += yshrink;
01921     newOuterRect.width -= widthshrink;
01922     newOuterRect.height -= heightshrink;
01923 
01924     nsRect borderInside(currOuterRect);
01925     
01926     // try to subtract one pixel from each side of the outer rect, but only if 
01927     // that side has any extra space left to shrink
01928     if (aInnerRect.x > borderInside.x) { // shrink left
01929       borderInside.x += twipsPerPixel;
01930       borderInside.width -= twipsPerPixel;
01931     }
01932     if (borderInside.x+borderInside.width > aInnerRect.x+aInnerRect.width) // shrink right
01933       borderInside.width -= twipsPerPixel;
01934     
01935     if (aInnerRect.y > borderInside.y) { // shrink top
01936       borderInside.y += twipsPerPixel;
01937       borderInside.height -= twipsPerPixel;
01938     }
01939     if (borderInside.y+borderInside.height > aInnerRect.y+aInnerRect.height) // shrink bottom
01940       borderInside.height -= twipsPerPixel;
01941 
01942     if (!aCompositeColors->mTransparent) {
01943       nsPoint theSide[MAX_POLY_POINTS];
01944       PRInt32 np = MakeSide(theSide, aRenderingContext, aWhichSide, newOuterRect, borderInside, 0,
01945                             BORDER_FULL, 1.0f, twipsPerPixel);
01946       NS_ASSERTION(np == 2, "Composite border should always be single pixel!");
01947       aRenderingContext.SetColor(aCompositeColors->mColor);
01948       DrawLine(aRenderingContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
01949     
01950       if (aWhichSide == NS_SIDE_TOP) {
01951         if (startRadius) {
01952           // Connecting line between top/left
01953           nscoord distance = (startRadius+twipsPerPixel)/2;
01954           nscoord remainder = distance%twipsPerPixel;
01955           if (remainder) 
01956             distance += twipsPerPixel - remainder;
01957           DrawLine(aRenderingContext,
01958                    currOuterRect.x+startRadius,
01959                    currOuterRect.y, 
01960                    currOuterRect.x+startRadius-distance,
01961                    currOuterRect.y+distance,
01962                    aGap);
01963         }
01964         if (endRadius) {
01965           // Connecting line between top/right
01966           nscoord distance = (endRadius+twipsPerPixel)/2;
01967           nscoord remainder = distance%twipsPerPixel;
01968           if (remainder) 
01969             distance += twipsPerPixel - remainder;
01970           DrawLine(aRenderingContext,
01971                    currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel,
01972                    currOuterRect.y, 
01973                    currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel+distance,
01974                    currOuterRect.y+distance,
01975                    aGap);
01976         }
01977       }
01978       else if (aWhichSide == NS_SIDE_BOTTOM) {
01979         if (startRadius) {
01980           // Connecting line between bottom/left
01981           nscoord distance = (startRadius+twipsPerPixel)/2;
01982           nscoord remainder = distance%twipsPerPixel;
01983           if (remainder) 
01984             distance += twipsPerPixel - remainder;
01985           DrawLine(aRenderingContext,
01986                    currOuterRect.x+startRadius, 
01987                    currOuterRect.y+currOuterRect.height-twipsPerPixel,
01988                    currOuterRect.x+startRadius-distance, 
01989                    currOuterRect.y+currOuterRect.height-twipsPerPixel-distance,
01990                    aGap);
01991         }
01992         if (endRadius) {
01993           // Connecting line between bottom/right
01994           nscoord distance = (endRadius+twipsPerPixel)/2;
01995           nscoord remainder = distance%twipsPerPixel;
01996           if (remainder) 
01997             distance += twipsPerPixel - remainder;
01998           DrawLine(aRenderingContext,
01999                    currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel, 
02000                    currOuterRect.y+currOuterRect.height-twipsPerPixel, 
02001                    currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel+distance, 
02002                    currOuterRect.y+currOuterRect.height-twipsPerPixel-distance,
02003                    aGap);
02004         }
02005       }
02006       else if (aWhichSide == NS_SIDE_LEFT) {
02007         if (startRadius) {
02008           // Connecting line between left/top
02009           nscoord distance = (startRadius-twipsPerPixel)/2;
02010           nscoord remainder = distance%twipsPerPixel;
02011           if (remainder)
02012             distance -= remainder;
02013           DrawLine(aRenderingContext,
02014                    currOuterRect.x+distance,
02015                    currOuterRect.y+startRadius-distance, 
02016                    currOuterRect.x,
02017                    currOuterRect.y+startRadius,
02018                    aGap);
02019         }
02020         if (endRadius) {
02021           // Connecting line between left/bottom
02022           nscoord distance = (endRadius-twipsPerPixel)/2;
02023           nscoord remainder = distance%twipsPerPixel;
02024           if (remainder)
02025             distance -= remainder;
02026           DrawLine(aRenderingContext,
02027                    currOuterRect.x+distance,
02028                    currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius+distance,
02029                    currOuterRect.x,
02030                    currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius,
02031                    aGap);
02032         }
02033       }
02034       else if (aWhichSide == NS_SIDE_RIGHT) {
02035        if (startRadius) {
02036           // Connecting line between right/top
02037           nscoord distance = (startRadius-twipsPerPixel)/2;
02038           nscoord remainder = distance%twipsPerPixel;
02039           if (remainder)
02040             distance -= remainder;
02041           DrawLine(aRenderingContext,
02042                    currOuterRect.x+currOuterRect.width-twipsPerPixel-distance,
02043                    currOuterRect.y+startRadius-distance, 
02044                    currOuterRect.x+currOuterRect.width-twipsPerPixel,
02045                    currOuterRect.y+startRadius,
02046                    aGap);
02047         }
02048         if (endRadius) {
02049           // Connecting line between right/bottom
02050           nscoord distance = (endRadius-twipsPerPixel)/2;
02051           nscoord remainder = distance%twipsPerPixel;
02052           if (remainder)
02053             distance -= remainder;
02054           DrawLine(aRenderingContext,
02055                    currOuterRect.x+currOuterRect.width-twipsPerPixel-distance, 
02056                    currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius+distance,
02057                    currOuterRect.x+currOuterRect.width-twipsPerPixel, 
02058                    currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius,
02059                    aGap);
02060         }
02061       }
02062     }
02063     
02064     if (aCompositeColors->mNext)
02065       aCompositeColors = aCompositeColors->mNext;
02066 
02067     currOuterRect = borderInside;
02068     shrinkage -= twipsPerPixel;
02069     
02070     startRadius -= twipsPerPixel;
02071     if (startRadius < 0) startRadius = 0;
02072     endRadius -= twipsPerPixel;
02073     if (endRadius < 0) endRadius = 0;
02074   }
02075 }
02076 
02077 // XXX improve this to constrain rendering to the damaged area
02078 void nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
02079                                  nsIRenderingContext& aRenderingContext,
02080                                  nsIFrame* aForFrame,
02081                                  const nsRect& aDirtyRect,
02082                                  const nsRect& aBorderArea,
02083                                  const nsStyleBorder& aBorderStyle,
02084                                  const nsStyleOutline& aOutlineStyle,
02085                                  nsStyleContext* aStyleContext,
02086                                  PRIntn aSkipSides,
02087                                  nsRect* aGap)
02088 {
02089 nsStyleCoord        bordStyleRadius[4];
02090 PRInt16             borderRadii[4],i;
02091 float               percent;
02092 const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
02093 nscoord width, offset;
02094 
02095   // Get our style context's color struct.
02096   const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
02097 
02098   aOutlineStyle.GetOutlineWidth(width);
02099 
02100   if (0 == width) {
02101     // Empty outline
02102     return;
02103   }
02104 
02105   // get the radius for our outline
02106   aOutlineStyle.mOutlineRadius.GetTop(bordStyleRadius[0]);      //topleft
02107   aOutlineStyle.mOutlineRadius.GetRight(bordStyleRadius[1]);    //topright
02108   aOutlineStyle.mOutlineRadius.GetBottom(bordStyleRadius[2]);   //bottomright
02109   aOutlineStyle.mOutlineRadius.GetLeft(bordStyleRadius[3]);     //bottomleft
02110 
02111   for(i=0;i<4;i++) {
02112     borderRadii[i] = 0;
02113     switch ( bordStyleRadius[i].GetUnit()) {
02114     case eStyleUnit_Percent:
02115       percent = bordStyleRadius[i].GetPercentValue();
02116       borderRadii[i] = (nscoord)(percent * aBorderArea.width);
02117       break;
02118     case eStyleUnit_Coord:
02119       borderRadii[i] = bordStyleRadius[i].GetCoordValue();
02120       break;
02121     default:
02122       break;
02123     }
02124   }
02125 
02126   nsRect* overflowArea = aForFrame->GetOverflowAreaProperty(PR_FALSE);
02127   if (!overflowArea) {
02128     NS_WARNING("Hmm, outline painting should always find an overflow area here");
02129     return;
02130   }
02131 
02132   // get the offset for our outline
02133   aOutlineStyle.GetOutlineOffset(offset);
02134   nsRect outside(*overflowArea);
02135   nsRect inside(outside);
02136   if (width + offset >= 0) {
02137     // the overflow area is exactly the outside edge of the outline
02138     inside.Deflate(width, width);
02139   } else {
02140     // the overflow area is exactly the rectangle containing the frame and its
02141     // children; we can compute the outline directly
02142     inside.Deflate(-offset, -offset);
02143     if (inside.width < 0 || inside.height < 0) {
02144       return; // Protect against negative outline sizes
02145     }
02146     outside = inside;
02147     outside.Inflate(width, width);
02148   }
02149 
02150   // rounded version of the border
02151   for(i=0;i<4;i++){
02152     if(borderRadii[i] > 0){
02153       PaintRoundedBorder(aPresContext, aRenderingContext, aForFrame, aDirtyRect,
02154                          outside, nsnull, &aOutlineStyle, aStyleContext, 
02155                          aSkipSides, borderRadii, aGap, PR_TRUE);
02156       return;
02157     }
02158   }
02159 
02160 
02161   PRUint8 outlineStyle = aOutlineStyle.GetOutlineStyle();
02162   //see if any sides are dotted or dashed
02163   if ((outlineStyle == NS_STYLE_BORDER_STYLE_DOTTED) || 
02164       (outlineStyle == NS_STYLE_BORDER_STYLE_DASHED))  {
02165     DrawDashedSides(0, aRenderingContext, aDirtyRect, ourColor, nsnull, &aOutlineStyle, PR_TRUE,
02166                     outside, inside, aSkipSides, aGap);
02167     return;
02168   }
02169 
02170   // Draw all the other sides
02171 
02172   /* XXX something is misnamed here!!!! */
02173   nscoord twipsPerPixel;/* XXX */
02174   float p2t;/* XXX */
02175   p2t = aPresContext->PixelsToTwips();/* XXX */
02176   twipsPerPixel = (nscoord) p2t;/* XXX */
02177 
02178   nscolor outlineColor(NS_RGB(0,0,0)); // default to black in case it is invert color and the platform does not support that
02179   PRBool  canDraw = PR_FALSE;
02180   PRBool  modeChanged=PR_FALSE;
02181  
02182   // see if the outline color is 'invert' or can invert.
02183   if (aOutlineStyle.GetOutlineInvert()) {
02184     canDraw = PR_TRUE;
02185     if( NS_SUCCEEDED(aRenderingContext.SetPenMode(nsPenMode_kInvert)) ) {
02186       modeChanged=PR_TRUE;
02187      }
02188   } else {
02189     canDraw = aOutlineStyle.GetOutlineColor(outlineColor);
02190   }
02191 
02192   if (PR_TRUE == canDraw) {
02193     DrawSide(aRenderingContext, NS_SIDE_BOTTOM,
02194              outlineStyle,
02195              outlineColor,
02196              bgColor->mBackgroundColor, outside, inside, aSkipSides,
02197              twipsPerPixel, aGap);
02198 
02199     DrawSide(aRenderingContext, NS_SIDE_LEFT,
02200              outlineStyle, 
02201              outlineColor,
02202              bgColor->mBackgroundColor,outside, inside,aSkipSides,
02203              twipsPerPixel, aGap);
02204 
02205     DrawSide(aRenderingContext, NS_SIDE_TOP,
02206              outlineStyle,
02207              outlineColor,
02208              bgColor->mBackgroundColor,outside, inside,aSkipSides,
02209              twipsPerPixel, aGap);
02210 
02211     DrawSide(aRenderingContext, NS_SIDE_RIGHT,
02212              outlineStyle,
02213              outlineColor,
02214              bgColor->mBackgroundColor,outside, inside,aSkipSides,
02215              twipsPerPixel, aGap);
02216              
02217     if(modeChanged ) {
02218       aRenderingContext.SetPenMode(nsPenMode_kNone);
02219     }  
02220   }
02221 }
02222 
02223 /* draw the edges of the border described in aBorderEdges one segment at a time.
02224  * a border has 4 edges.  Each edge has 1 or more segments. 
02225  * "inside edges" are drawn differently than "outside edges" so the shared edges will match up.
02226  * in the case of table collapsing borders, the table edge is the "outside" edge and
02227  * cell edges are always "inside" edges (so adjacent cells have 2 shared "inside" edges.)
02228  * dashed segments are drawn by DrawDashedSegments().
02229  */
02230 // XXX: doesn't do corners or junctions well at all.  Just uses logic stolen 
02231 //      from PaintBorder which is insufficient
02232 
02233 void nsCSSRendering::PaintBorderEdges(nsPresContext* aPresContext,
02234                                       nsIRenderingContext& aRenderingContext,
02235                                       nsIFrame* aForFrame,
02236                                       const nsRect& aDirtyRect,
02237                                       const nsRect& aBorderArea,
02238                                       nsBorderEdges * aBorderEdges,
02239                                       nsStyleContext* aStyleContext,
02240                                       PRIntn aSkipSides,
02241                                       nsRect* aGap)
02242 {
02243   const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
02244   
02245   if (nsnull==aBorderEdges) {  // Empty border segments
02246     return;
02247   }
02248 
02249   // Turn off rendering for all of the zero sized sides
02250   if (0 == aBorderEdges->mMaxBorderWidth.top) 
02251     aSkipSides |= (1 << NS_SIDE_TOP);
02252   if (0 == aBorderEdges->mMaxBorderWidth.right) 
02253     aSkipSides |= (1 << NS_SIDE_RIGHT);
02254   if (0 == aBorderEdges->mMaxBorderWidth.bottom) 
02255     aSkipSides |= (1 << NS_SIDE_BOTTOM);
02256   if (0 == aBorderEdges->mMaxBorderWidth.left) 
02257     aSkipSides |= (1 << NS_SIDE_LEFT);
02258 
02259   // Draw any dashed or dotted segments separately
02260   DrawDashedSegments(aRenderingContext, aBorderArea, aBorderEdges, aSkipSides, aGap);
02261 
02262   // Draw all the other sides
02263   nscoord twipsPerPixel;
02264   float p2t;
02265   p2t = aPresContext->PixelsToTwips();
02266   twipsPerPixel = (nscoord) p2t;/* XXX huh!*/
02267 
02268   if (0 == (aSkipSides & (1<<NS_SIDE_TOP))) {
02269     PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_TOP].Count();
02270     PRInt32 i;
02271     nsBorderEdge * leftEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
02272     nscoord x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
02273     for (i=0; i<segmentCount; i++)
02274     {
02275       nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(i));
02276       nscoord y = aBorderArea.y;
02277       if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are bottom-aligned
02278         y += aBorderEdges->mMaxBorderWidth.top - borderEdge->mWidth;
02279       nsRect inside(x, y, borderEdge->mLength, aBorderArea.height);
02280       x += borderEdge->mLength;
02281       nsRect outside(inside);
02282       nsMargin outsideMargin(0, borderEdge->mWidth, 0, 0);
02283       outside.Deflate(outsideMargin);
02284       DrawSide(aRenderingContext, NS_SIDE_TOP,
02285                borderEdge->mStyle,
02286                borderEdge->mColor,
02287                bgColor->mBackgroundColor,
02288                inside, outside,aSkipSides,
02289                twipsPerPixel, aGap);
02290     }
02291   }
02292   if (0 == (aSkipSides & (1<<NS_SIDE_LEFT))) {
02293     PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_LEFT].Count();
02294     PRInt32 i;
02295     nsBorderEdge * topEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(0));
02296     nscoord y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
02297     for (i=0; i<segmentCount; i++)
02298     {
02299       nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(i));
02300       nscoord x = aBorderArea.x + (aBorderEdges->mMaxBorderWidth.left - borderEdge->mWidth);
02301       nsRect inside(x, y, aBorderArea.width, borderEdge->mLength);
02302       y += borderEdge->mLength;
02303       nsRect outside(inside);
02304       nsMargin outsideMargin(borderEdge->mWidth, 0, 0, 0);
02305       outside.Deflate(outsideMargin);
02306       DrawSide(aRenderingContext, NS_SIDE_LEFT,
02307                borderEdge->mStyle,
02308                borderEdge->mColor,
02309                bgColor->mBackgroundColor,
02310                inside, outside, aSkipSides,
02311                twipsPerPixel, aGap);
02312     }
02313   }
02314   if (0 == (aSkipSides & (1<<NS_SIDE_BOTTOM))) {
02315     PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_BOTTOM].Count();
02316     PRInt32 i;
02317     nsBorderEdge * leftEdge =  (nsBorderEdge *)
02318       (aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(aBorderEdges->mEdges[NS_SIDE_LEFT].Count()-1));
02319     nscoord x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
02320     for (i=0; i<segmentCount; i++)
02321     {
02322       nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_BOTTOM].ElementAt(i));
02323       nscoord y = aBorderArea.y;
02324       if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are top-aligned
02325         y -= (aBorderEdges->mMaxBorderWidth.bottom - borderEdge->mWidth);
02326       nsRect inside(x, y, borderEdge->mLength, aBorderArea.height);
02327       x += borderEdge->mLength;
02328       nsRect outside(inside);
02329       nsMargin outsideMargin(0, 0, 0, borderEdge->mWidth);
02330       outside.Deflate(outsideMargin);
02331       DrawSide(aRenderingContext, NS_SIDE_BOTTOM,
02332                borderEdge->mStyle,
02333                borderEdge->mColor,
02334                bgColor->mBackgroundColor,
02335                inside, outside,aSkipSides,
02336                twipsPerPixel, aGap);
02337     }
02338   }
02339   if (0 == (aSkipSides & (1<<NS_SIDE_RIGHT))) {
02340     PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_RIGHT].Count();
02341     PRInt32 i;
02342     nsBorderEdge * topEdge =  (nsBorderEdge *)
02343       (aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(aBorderEdges->mEdges[NS_SIDE_TOP].Count()-1));
02344     nscoord y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
02345     for (i=0; i<segmentCount; i++)
02346     {
02347       nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_RIGHT].ElementAt(i));
02348       nscoord width;
02349       if (PR_TRUE==aBorderEdges->mOutsideEdge)
02350       {
02351         width = aBorderArea.width - aBorderEdges->mMaxBorderWidth.right;
02352         width += borderEdge->mWidth;
02353       }
02354       else
02355       {
02356         width = aBorderArea.width;
02357       }
02358       nsRect inside(aBorderArea.x, y, width, borderEdge->mLength);
02359       y += borderEdge->mLength;
02360       nsRect outside(inside);
02361       nsMargin outsideMargin(0, 0, (borderEdge->mWidth), 0);
02362       outside.Deflate(outsideMargin);
02363       DrawSide(aRenderingContext, NS_SIDE_RIGHT,
02364                borderEdge->mStyle,
02365                borderEdge->mColor,
02366                bgColor->mBackgroundColor,
02367                inside, outside,aSkipSides,
02368                twipsPerPixel, aGap);
02369     }
02370   }
02371 }
02372 
02373 
02374 //----------------------------------------------------------------------
02375 
02376 // Returns the anchor point to use for the background image. The
02377 // anchor point is the (x, y) location where the first tile should
02378 // be placed
02379 //
02380 // For repeated tiling, the anchor values are normalized wrt to the upper-left
02381 // edge of the bounds, and are always in the range:
02382 // -(aTileWidth - 1) <= anchor.x <= 0
02383 // -(aTileHeight - 1) <= anchor.y <= 0
02384 //
02385 // i.e., they are either 0 or a negative number whose absolute value is
02386 // less than the tile size in that dimension
02387 //
02388 // aOriginBounds is the box to which the tiling position should be relative
02389 // aClipBounds is the box in which the tiling will actually be done
02390 // They should correspond to 'background-origin' and 'background-clip',
02391 // except when painting on the canvas, in which case the origin bounds
02392 // should be the bounds of the root element's frame and the clip bounds
02393 // should be the bounds of the canvas frame.
02394 static void
02395 ComputeBackgroundAnchorPoint(const nsStyleBackground& aColor,
02396                              const nsRect& aOriginBounds,
02397                              const nsRect& aClipBounds,
02398                              nscoord aTileWidth, nscoord aTileHeight,
02399                              nsPoint& aResult)
02400 {
02401   nscoord x;
02402   if (NS_STYLE_BG_X_POSITION_LENGTH & aColor.mBackgroundFlags) {
02403     x = aColor.mBackgroundXPosition.mCoord;
02404   }
02405   else if (NS_STYLE_BG_X_POSITION_PERCENT & aColor.mBackgroundFlags) {
02406     PRFloat64 percent = PRFloat64(aColor.mBackgroundXPosition.mFloat);
02407     nscoord tilePos = nscoord(percent * PRFloat64(aTileWidth));
02408     nscoord boxPos = nscoord(percent * PRFloat64(aOriginBounds.width));
02409     x = boxPos - tilePos;
02410   }
02411   else {
02412     x = 0;
02413   }
02414   x += aOriginBounds.x - aClipBounds.x;
02415   if (NS_STYLE_BG_REPEAT_X & aColor.mBackgroundRepeat) {
02416     // When we are tiling in the x direction the loop will run from
02417     // the left edge of the box to the right edge of the box. We need
02418     // to adjust the starting coordinate to lie within the band being
02419     // rendered.
02420     if (x < 0) {
02421       x = -x;
02422       if (x < 0) {
02423         // Some joker gave us max-negative-integer.
02424         x = 0;
02425       }
02426       x %= aTileWidth;
02427       x = -x;
02428     }
02429     else if (x != 0) {
02430       x %= aTileWidth;
02431       if (x > 0) {
02432         x = x - aTileWidth;
02433       }
02434     }
02435 
02436     NS_POSTCONDITION((x >= -(aTileWidth - 1)) && (x <= 0), "bad computed anchor value");
02437   }
02438   aResult.x = x;
02439 
02440   nscoord y;
02441   if (NS_STYLE_BG_Y_POSITION_LENGTH & aColor.mBackgroundFlags) {
02442     y = aColor.mBackgroundYPosition.mCoord;
02443   }
02444   else if (NS_STYLE_BG_Y_POSITION_PERCENT & aColor.mBackgroundFlags){
02445     PRFloat64 percent = PRFloat64(aColor.mBackgroundYPosition.mFloat);
02446     nscoord tilePos = nscoord(percent * PRFloat64(aTileHeight));
02447     nscoord boxPos = nscoord(percent * PRFloat64(aOriginBounds.height));
02448     y = boxPos - tilePos;
02449   }
02450   else {
02451     y = 0;
02452   }
02453   y += aOriginBounds.y - aClipBounds.y;
02454   if (NS_STYLE_BG_REPEAT_Y & aColor.mBackgroundRepeat) {
02455     // When we are tiling in the y direction the loop will run from
02456     // the top edge of the box to the bottom edge of the box. We need
02457     // to adjust the starting coordinate to lie within the band being
02458     // rendered.
02459     if (y < 0) {
02460       y = -y;
02461       if (y < 0) {
02462         // Some joker gave us max-negative-integer.
02463         y = 0;
02464       }
02465       y %= aTileHeight;
02466       y = -y;
02467     }
02468     else if (y != 0) {
02469       y %= aTileHeight;
02470       if (y > 0) {
02471         y = y - aTileHeight;
02472       }
02473     }
02474     
02475     NS_POSTCONDITION((y >= -(aTileHeight - 1)) && (y <= 0), "bad computed anchor value");
02476   }
02477   aResult.y = y;
02478 }
02479 
02480 // Returns the root scrollable frame, which is the first child of the root
02481 // frame.
02482 static nsIScrollableFrame*
02483 GetRootScrollableFrame(nsPresContext* aPresContext, nsIFrame* aRootFrame)
02484 {
02485   nsIScrollableFrame* scrollableFrame = nsnull;
02486 
02487   if (nsLayoutAtoms::viewportFrame == aRootFrame->GetType()) {
02488     nsIFrame* childFrame = aRootFrame->GetFirstChild(nsnull);
02489 
02490     if (childFrame) {
02491       if (nsLayoutAtoms::scrollFrame == childFrame->GetType()) {
02492         // Use this frame, even if we are using GFX frames for the
02493         // viewport, which contains another scroll frame below this
02494         // frame, since the GFX scrollport frame does not implement
02495         // nsIScrollableFrame.
02496         CallQueryInterface(childFrame, &scrollableFrame);
02497       }
02498     }
02499   }
02500 #ifdef DEBUG
02501   else {
02502     NS_WARNING("aRootFrame is not a viewport frame");
02503   }
02504 #endif // DEBUG
02505 
02506   return scrollableFrame;
02507 }
02508 
02509 const nsStyleBackground*
02510 nsCSSRendering::FindNonTransparentBackground(nsStyleContext* aContext,
02511                                              PRBool aStartAtParent /*= PR_FALSE*/)
02512 {
02513   NS_ASSERTION(aContext, "Cannot find NonTransparentBackground in a null context" );
02514   
02515   const nsStyleBackground* result = nsnull;
02516   nsStyleContext* context = nsnull;
02517   if (aStartAtParent) {
02518     context = aContext->GetParent();
02519   }
02520   if (!context) {
02521     context = aContext;
02522   }
02523   
02524   while (context) {
02525     result = context->GetStyleBackground();
02526     if (0 == (result->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT))
02527       break;
02528 
02529     context = context->GetParent();
02530   }
02531   return result;
02532 }
02533 
02534 
02566 // Returns nsnull if aFrame is not a canvas frame.
02567 // Otherwise, it returns the frame we should look for the background on.
02568 // This is normally aFrame but if aFrame is the viewport, we need to
02569 // look for the background starting at the scroll root (which shares
02570 // style context with the document root) or the document root itself.
02571 // We need to treat the viewport as canvas because, even though
02572 // it does not actually paint a background, we need to get the right
02573 // background style so we correctly detect transparent documents.
02574 inline nsIFrame*
02575 IsCanvasFrame(nsPresContext* aPresContext, nsIFrame *aFrame)
02576 {
02577   nsIAtom* frameType = aFrame->GetType();
02578   if (frameType == nsLayoutAtoms::canvasFrame ||
02579       frameType == nsLayoutAtoms::rootFrame ||
02580       frameType == nsLayoutAtoms::pageFrame) {
02581     return aFrame;
02582   } else if (frameType == nsLayoutAtoms::viewportFrame) {
02583     nsIFrame* firstChild = aFrame->GetFirstChild(nsnull);
02584     if (firstChild) {
02585       return firstChild;
02586     }
02587   }
02588   
02589   return nsnull;
02590 }
02591 
02592 inline PRBool
02593 FindCanvasBackground(nsPresContext* aPresContext,
02594                      nsIFrame* aForFrame,
02595                      const nsStyleBackground** aBackground)
02596 {
02597   // XXXldb What if the root element is positioned, etc.?  (We don't
02598   // allow that yet, do we?)
02599   nsIFrame *firstChild = aForFrame->GetFirstChild(nsnull);
02600   if (firstChild) {
02601     const nsStyleBackground* result = firstChild->GetStyleBackground();
02602     nsIFrame* topFrame = aForFrame;
02603 
02604     if (firstChild->GetType() == nsLayoutAtoms::pageContentFrame) {
02605       topFrame = firstChild->GetFirstChild(nsnull);
02606       NS_ASSERTION(topFrame,
02607                    "nsPageContentFrame is missing a normal flow child");
02608       if (!topFrame) {
02609         return PR_FALSE;
02610       }
02611       NS_ASSERTION(topFrame->GetContent(),
02612                    "nsPageContentFrame child without content");
02613       result = topFrame->GetStyleBackground();
02614     }
02615 
02616     // Check if we need to do propagation from BODY rather than HTML.
02617     if (result->IsTransparent()) {
02618       nsIContent* content = topFrame->GetContent();
02619       if (content) {
02620         // Use |GetOwnerDoc| so it works during destruction.
02621         nsIDocument* document = content->GetOwnerDoc();
02622         nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(document);
02623         if (htmlDoc) {
02624           if (!document->IsCaseSensitive()) { // HTML, not XHTML
02625             nsCOMPtr<nsIDOMHTMLElement> body;
02626             htmlDoc->GetBody(getter_AddRefs(body));
02627             nsCOMPtr<nsIContent> bodyContent = do_QueryInterface(body);
02628             // We need to null check the body node (bug 118829) since
02629             // there are cases, thanks to the fix for bug 5569, where we
02630             // will reflow a document with no body.  In particular, if a
02631             // SCRIPT element in the head blocks the parser and then has a
02632             // SCRIPT that does "document.location.href = 'foo'", then
02633             // nsParser::Terminate will call |DidBuildModel| methods
02634             // through to the content sink, which will call |StartLayout|
02635             // and thus |InitialReflow| on the pres shell.  See bug 119351
02636             // for the ugly details.
02637             if (bodyContent) {
02638               nsIFrame *bodyFrame;
02639               nsresult rv = aPresContext->PresShell()->
02640                 GetPrimaryFrameFor(bodyContent, &bodyFrame);
02641               if (NS_SUCCEEDED(rv) && bodyFrame)
02642                 result = bodyFrame->GetStyleBackground();
02643             }
02644           }
02645         }
02646       }
02647     }
02648 
02649     *aBackground = result;
02650   } else {
02651     // This should always give transparent, so we'll fill it in with the
02652     // default color if needed.  This seems to happen a bit while a page is
02653     // being loaded.
02654     *aBackground = aForFrame->GetStyleBackground();
02655   }
02656   
02657   return PR_TRUE;
02658 }
02659 
02660 inline PRBool
02661 FindElementBackground(nsPresContext* aPresContext,
02662                       nsIFrame* aForFrame,
02663                       const nsStyleBackground** aBackground)
02664 {
02665   nsIFrame *parentFrame = aForFrame->GetParent();
02666   // XXXldb We shouldn't have to null-check |parentFrame| here.
02667   if (parentFrame && IsCanvasFrame(aPresContext, parentFrame) == parentFrame) {
02668     // Check that we're really the root (rather than in another child list).
02669     nsIFrame *childFrame = parentFrame->GetFirstChild(nsnull);
02670     if (childFrame == aForFrame)
02671       return PR_FALSE; // Background was already drawn for the canvas.
02672   }
02673 
02674   *aBackground = aForFrame->GetStyleBackground();
02675 
02676   // Return true unless the frame is for a BODY element whose background
02677   // was propagated to the viewport.
02678 
02679   if (aForFrame->GetStyleContext()->GetPseudoType())
02680     return PR_TRUE; // A pseudo-element frame.
02681 
02682   nsIContent* content = aForFrame->GetContent();
02683   if (!content || !content->IsContentOfType(nsIContent::eHTML))
02684     return PR_TRUE;  // not frame for an HTML element
02685 
02686   if (!parentFrame)
02687     return PR_TRUE; // no parent to look at
02688 
02689   if (content->Tag() != nsHTMLAtoms::body)
02690     return PR_TRUE; // not frame for <BODY> element
02691 
02692   // We should only look at the <html> background if we're in an HTML document
02693   nsIDocument* document = content->GetOwnerDoc();
02694   nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(document);
02695   if (!htmlDoc)
02696     return PR_TRUE;
02697 
02698   if (document->IsCaseSensitive()) // XHTML, not HTML
02699     return PR_TRUE;
02700   
02701   const nsStyleBackground* htmlBG = parentFrame->GetStyleBackground();
02702   return !htmlBG->IsTransparent();
02703 }
02704 
02705 PRBool
02706 nsCSSRendering::FindBackground(nsPresContext* aPresContext,
02707                                nsIFrame* aForFrame,
02708                                const nsStyleBackground** aBackground,
02709                                PRBool* aIsCanvas)
02710 {
02711   nsIFrame* canvasFrame = IsCanvasFrame(aPresContext, aForFrame);
02712   *aIsCanvas = canvasFrame != nsnull;
02713   return canvasFrame
02714       ? FindCanvasBackground(aPresContext, canvasFrame, aBackground)
02715       : FindElementBackground(aPresContext, aForFrame, aBackground);
02716 }
02717 
02718 void
02719 nsCSSRendering::DidPaint()
02720 {
02721   gInlineBGData.Reset();
02722 }
02723 
02724 void
02725 nsCSSRendering::PaintBackground(nsPresContext* aPresContext,
02726                                 nsIRenderingContext& aRenderingContext,
02727                                 nsIFrame* aForFrame,
02728                                 const nsRect& aDirtyRect,
02729                                 const nsRect& aBorderArea,
02730                                 const nsStyleBorder& aBorder,
02731                                 const nsStylePadding& aPadding,
02732                                 PRBool aUsePrintSettings,
02733                                 nsRect* aBGClipRect)
02734 {
02735   NS_PRECONDITION(aForFrame,
02736                   "Frame is expected to be provided to PaintBackground");
02737 
02738   PRBool isCanvas;
02739   const nsStyleBackground *color;
02740 
02741   if (!FindBackground(aPresContext, aForFrame, &color, &isCanvas)) {
02742     // we don't want to bail out of moz-appearance is set on a root
02743     // node. If it has a parent content node, bail because it's not
02744     // a root, other wise keep going in order to let the theme stuff
02745     // draw the background. The canvas really should be drawing the
02746     // bg, but there's no way to hook that up via css.
02747     if (!aForFrame->GetStyleDisplay()->mAppearance) {
02748       return;
02749     }
02750 
02751     nsIContent* content = aForFrame->GetContent();
02752     if (!content || content->GetParent()) {
02753       return;
02754     }
02755         
02756     color = aForFrame->GetStyleBackground();
02757   }
02758   if (!isCanvas) {
02759     PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
02760                           aDirtyRect, aBorderArea, *color, aBorder,
02761                           aPadding, aUsePrintSettings, aBGClipRect);
02762     return;
02763   }
02764 
02765   if (!color)
02766     return;
02767   nsStyleBackground canvasColor(*color);
02768 
02769   nsIViewManager* vm = aPresContext->GetViewManager();
02770 
02771   if (canvasColor.mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) {
02772     nsIView* rootView;
02773     vm->GetRootView(rootView);
02774     if (!rootView->GetParent()) {
02775       PRBool widgetIsTranslucent = PR_FALSE;
02776 
02777       if (rootView->HasWidget()) {
02778         rootView->GetWidget()->GetWindowTranslucency(widgetIsTranslucent);
02779       }
02780       
02781       if (!widgetIsTranslucent) {
02782         // Ensure that we always paint a color for the root (in case there's
02783         // no background at all or a partly transparent image).
02784         canvasColor.mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT;
02785         canvasColor.mBackgroundColor = aPresContext->DefaultBackgroundColor();
02786       }
02787     }
02788   }
02789 
02790   vm->SetDefaultBackgroundColor(canvasColor.mBackgroundColor);
02791 
02792   // Since nsHTMLContainerFrame::CreateViewForFrame might have created
02793   // the view before we knew about the child with the fixed background
02794   // attachment (root or BODY) or the stylesheet specifying that
02795   // attachment, set the BitBlt flag here as well.
02796   if (canvasColor.mBackgroundAttachment == NS_STYLE_BG_ATTACHMENT_FIXED) {
02797     nsIView *view = aForFrame->GetView();
02798     if (view)
02799       vm->SetViewBitBltEnabled(view, PR_FALSE);
02800   }
02801 
02802   PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
02803                         aDirtyRect, aBorderArea, canvasColor,
02804                         aBorder, aPadding, aUsePrintSettings, aBGClipRect);
02805 }
02806 
02807 void
02808 nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
02809                                       nsIRenderingContext& aRenderingContext,
02810                                       nsIFrame* aForFrame,
02811                                       const nsRect& aDirtyRect,
02812                                       const nsRect& aBorderArea,
02813                                       const nsStyleBackground& aColor,
02814                                       const nsStyleBorder& aBorder,
02815                                       const nsStylePadding& aPadding,
02816                                       PRBool aUsePrintSettings,
02817                                       nsRect* aBGClipRect)
02818 {
02819   NS_PRECONDITION(aForFrame,
02820                   "Frame is expected to be provided to PaintBackground");
02821 
02822   PRBool canDrawBackgroundImage = PR_TRUE;
02823   PRBool canDrawBackgroundColor = PR_TRUE;
02824 
02825   if (aUsePrintSettings) {
02826     canDrawBackgroundImage = aPresContext->GetBackgroundImageDraw();
02827     canDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
02828   }
02829 
02830   // Check to see if we have an appearance defined.  If so, we let the theme
02831   // renderer draw the background and bail out.
02832   const nsStyleDisplay* displayData = aForFrame->GetStyleDisplay();
02833   if (displayData->mAppearance) {
02834     nsITheme *theme = aPresContext->GetTheme();
02835     if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame, displayData->mAppearance)) {
02836       theme->DrawWidgetBackground(&aRenderingContext, aForFrame, 
02837                                   displayData->mAppearance, aBorderArea, aDirtyRect); 
02838       return;
02839     }
02840   }
02841 
02842   nsRect bgClipArea;
02843   if (aBGClipRect) {
02844     bgClipArea = *aBGClipRect;
02845   }
02846   else {
02847     // The background is rendered over the 'background-clip' area.
02848     bgClipArea = aBorderArea;
02849     if (aColor.mBackgroundClip != NS_STYLE_BG_CLIP_BORDER) {
02850       NS_ASSERTION(aColor.mBackgroundClip == NS_STYLE_BG_CLIP_PADDING,
02851                    "unknown background-clip value");
02852       bgClipArea.Deflate(aBorder.GetBorder());
02853     }
02854   }
02855 
02856   // The actual dirty rect is the intersection of the 'background-clip'
02857   // area and the dirty rect we were given
02858   nsRect dirtyRect;
02859   if (!dirtyRect.IntersectRect(bgClipArea, aDirtyRect)) {
02860     // Nothing to paint
02861     return;
02862   }
02863 
02864   // if there is no background image or background images are turned off, try a color.
02865   if (!aColor.mBackgroundImage || !canDrawBackgroundImage) {
02866     PaintBackgroundColor(aPresContext, aRenderingContext, aForFrame, bgClipArea,
02867                          aColor, aBorder, aPadding, canDrawBackgroundColor);
02868     return;
02869   }
02870 
02871   // We have a background image
02872 
02873   // Lookup the image
02874   imgIRequest *req = aPresContext->LoadImage(aColor.mBackgroundImage,
02875                                              aForFrame);
02876 
02877   PRUint32 status = imgIRequest::STATUS_ERROR;
02878   if (req)
02879     req->GetImageStatus(&status);
02880 
02881   if (!req || !(status & imgIRequest::STATUS_FRAME_COMPLETE) || !(status & imgIRequest::STATUS_SIZE_AVAILABLE)) {
02882     PaintBackgroundColor(aPresContext, aRenderingContext, aForFrame, bgClipArea,
02883                          aColor, aBorder, aPadding, canDrawBackgroundColor);
02884     return;
02885   }
02886 
02887   nsCOMPtr<imgIContainer> image;
02888   req->GetImage(getter_AddRefs(image));
02889 
02890   nsSize imageSize;
02891   image->GetWidth(&imageSize.width);
02892   image->GetHeight(&imageSize.height);
02893 
02894   float p2t;
02895   p2t = aPresContext->ScaledPixelsToTwips();
02896   imageSize.width = NSIntPixelsToTwips(imageSize.width, p2t);
02897   imageSize.height = NSIntPixelsToTwips(imageSize.height, p2t);
02898 
02899   req = nsnull;
02900 
02901   nsRect bgOriginArea;
02902 
02903   nsIAtom* frameType = aForFrame->GetType();
02904   if (frameType == nsLayoutAtoms::inlineFrame) {
02905     switch (aColor.mBackgroundInlinePolicy) {
02906     case NS_STYLE_BG_INLINE_POLICY_EACH_BOX:
02907       bgOriginArea = aBorderArea;
02908       break;
02909     case NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX:
02910       bgOriginArea = gInlineBGData.GetBoundingRect(aForFrame);
02911       break;
02912     default:
02913       NS_ERROR("Unknown background-inline-policy value!  "
02914                "Please, teach me what to do.");
02915     case NS_STYLE_BG_INLINE_POLICY_CONTINUOUS:
02916       bgOriginArea = gInlineBGData.GetContinuousRect(aForFrame);
02917       break;
02918     }
02919   }
02920   else {
02921     bgOriginArea = aBorderArea;
02922   }
02923 
02924   // Background images are tiled over the 'background-clip' area
02925   // but the origin of the tiling is based on the 'background-origin' area
02926   if (aColor.mBackgroundOrigin != NS_STYLE_BG_ORIGIN_BORDER) {
02927     bgOriginArea.Deflate(aBorder.GetBorder());
02928     if (aColor.mBackgroundOrigin != NS_STYLE_BG_ORIGIN_PADDING) {
02929       nsMargin padding;
02930       // XXX CalcPaddingFor is deprecated, but we need it for percentage padding
02931       aPadding.CalcPaddingFor(aForFrame, padding);
02932       bgOriginArea.Deflate(padding);
02933       NS_ASSERTION(aColor.mBackgroundOrigin == NS_STYLE_BG_ORIGIN_CONTENT,
02934                    "unknown background-origin value");
02935     }
02936   }
02937 
02938   // Based on the repeat setting, compute how many tiles we should
02939   // lay down for each axis. The value computed is the maximum based
02940   // on the dirty rect before accounting for the background-position.
02941   nscoord tileWidth = imageSize.width;
02942   nscoord tileHeight = imageSize.height;
02943   PRBool  needBackgroundColor = !(aColor.mBackgroundFlags &
02944                                   NS_STYLE_BG_COLOR_TRANSPARENT);
02945   PRIntn  repeat = aColor.mBackgroundRepeat;
02946   nscoord xDistance, yDistance;
02947 
02948   switch (repeat) {
02949     case NS_STYLE_BG_REPEAT_X:
02950       xDistance = dirtyRect.width;
02951       yDistance = tileHeight;
02952       break;
02953     case NS_STYLE_BG_REPEAT_Y:
02954       xDistance = tileWidth;
02955       yDistance = dirtyRect.height;
02956       break;
02957     case NS_STYLE_BG_REPEAT_XY:
02958       xDistance = dirtyRect.width;
02959       yDistance = dirtyRect.height;
02960       if (needBackgroundColor) {
02961         // If the image is completely opaque, we do not need to paint the
02962         // background color
02963         nsCOMPtr<gfxIImageFrame> gfxImgFrame;
02964         image->GetCurrentFrame(getter_AddRefs(gfxImgFrame));
02965         if (gfxImgFrame) {
02966           gfxImgFrame->GetNeedsBackground(&needBackgroundColor);
02967 
02968           /* check for tiling of a image where frame smaller than container */
02969           nsSize iSize;
02970           image->GetWidth(&iSize.width);
02971           image->GetHeight(&iSize.height);
02972           nsRect iframeRect;
02973           gfxImgFrame->GetRect(iframeRect);
02974           if (iSize.width != iframeRect.width ||
02975               iSize.height != iframeRect.height) {
02976             needBackgroundColor = PR_TRUE;
02977           }
02978         }
02979       }
02980       break;
02981     case NS_STYLE_BG_REPEAT_OFF:
02982     default:
02983       NS_ASSERTION(repeat == NS_STYLE_BG_REPEAT_OFF, "unknown background-repeat value");
02984       xDistance = tileWidth;
02985       yDistance = tileHeight;
02986       break;
02987   }
02988 
02989   // The background color is rendered over the 'background-clip' area
02990   if (needBackgroundColor) {
02991     PaintBackgroundColor(aPresContext, aRenderingContext, aForFrame, bgClipArea,
02992                          aColor, aBorder, aPadding, canDrawBackgroundColor);
02993   }
02994 
02995   if ((tileWidth == 0) || (tileHeight == 0) || dirtyRect.IsEmpty()) {
02996     // Nothing left to paint
02997     return;
02998   }
02999 
03000   // Compute the anchor point.
03001   //
03002   // When tiling, the anchor coordinate values will be negative offsets
03003   // from the background-origin area.
03004 
03005   nsPoint anchor;
03006   if (NS_STYLE_BG_ATTACHMENT_FIXED == aColor.mBackgroundAttachment) {
03007     // If it's a fixed background attachment, then the image is placed 
03008     // relative to the viewport
03009     nsIView* viewportView = nsnull;
03010     nsRect viewportArea;
03011 
03012     nsIFrame* rootFrame =
03013       aPresContext->PresShell()->FrameManager()->GetRootFrame();
03014     NS_ASSERTION(rootFrame, "no root frame");
03015 
03016     if (aPresContext->IsPaginated()) {
03017       nsIFrame* page = nsLayoutUtils::GetPageFrame(aForFrame);
03018       NS_ASSERTION(page, "no page");
03019       rootFrame = page;
03020     }
03021 
03022     viewportView = rootFrame->GetView();
03023     NS_ASSERTION(viewportView, "no viewport view");
03024     viewportArea = viewportView->GetBounds();
03025     viewportArea.x = 0;
03026     viewportArea.y = 0;
03027 
03028     nsIScrollableFrame* scrollableFrame =
03029       GetRootScrollableFrame(aPresContext, rootFrame);
03030 
03031     if (scrollableFrame) {
03032       nsMargin scrollbars = scrollableFrame->GetActualScrollbarSizes();
03033       viewportArea.Deflate(scrollbars);
03034     }
03035 
03036     // Get the anchor point
03037     ComputeBackgroundAnchorPoint(aColor, viewportArea, viewportArea, tileWidth, tileHeight, anchor);
03038 
03039     // Convert the anchor point to aForFrame's coordinate space
03040     nsPoint offset(0, 0);
03041     nsIView* view = aForFrame->GetClosestView(&offset);
03042     anchor -= offset;
03043     NS_ASSERTION(view, "expected a view");
03044     anchor -= view->GetOffsetTo(viewportView);
03045   } else {
03046     if (frameType == nsLayoutAtoms::canvasFrame) {
03047       // If the frame is the canvas, the image is placed relative to
03048       // the root element's (first) frame (see bug 46446)
03049       nsRect firstRootElementFrameArea;
03050       nsIFrame* firstRootElementFrame = aForFrame->GetFirstChild(nsnull);
03051       NS_ASSERTION(firstRootElementFrame, "A canvas with a background "
03052         "image had no child frame, which is impossible according to CSS. "
03053         "Make sure there isn't a background image specified on the "
03054         "|:viewport| pseudo-element in |html.css|.");
03055 
03056       // temporary null check -- see bug 97226
03057       if (firstRootElementFrame) {
03058         firstRootElementFrameArea = firstRootElementFrame->GetRect();
03059 
03060         // Take the border out of the frame's rect
03061         const nsStyleBorder* borderStyle = firstRootElementFrame->GetStyleBorder();
03062         firstRootElementFrameArea.Deflate(borderStyle->GetBorder());
03063 
03064         // Get the anchor point
03065         ComputeBackgroundAnchorPoint(aColor, firstRootElementFrameArea, bgClipArea, tileWidth, tileHeight, anchor);
03066       } else {
03067         ComputeBackgroundAnchorPoint(aColor, bgOriginArea, bgClipArea, tileWidth, tileHeight, anchor);
03068       }
03069     } else {
03070       // Otherwise, it is the normal case, and the background is
03071       // simply placed relative to the frame's background-clip area
03072       ComputeBackgroundAnchorPoint(aColor, bgOriginArea, bgClipArea, tileWidth, tileHeight, anchor);
03073     }
03074   }
03075 
03076 
03077 #if (!defined(XP_UNIX) && !defined(XP_BEOS)) || defined(XP_MACOSX)
03078   // Setup clipping so that rendering doesn't leak out of the computed
03079   // dirty rect
03080   aRenderingContext.PushState();
03081   aRenderingContext.SetClipRect(dirtyRect, nsClipCombine_kIntersect);
03082 #endif
03083 
03084   // Compute the x and y starting points and limits for tiling
03085 
03086   /* An Overview Of The Following Logic
03087 
03088           A........ . . . . . . . . . . . . . .
03089           :   +---:-------.-------.-------.----  /|\
03090           :   |   :       .       .       .       |  nh 
03091           :.......: . . . x . . . . . . . . . .  \|/   
03092           .   |   .       .       .       .        
03093           .   |   .       .  ###########  .        
03094           . . . . . . . . . .#. . . . .#. . . .     
03095           .   |   .       .  ###########  .      /|\
03096           .   |   .       .       .       .       |  h
03097           . . | . . . . . . . . . . . . . z . .  \|/
03098           .   |   .       .       .       .    
03099           |<-----nw------>|       |<--w-->|
03100 
03101        ---- = the background clip area edge. The painting is done within
03102               to this area.  If the background is positioned relative to the 
03103               viewport ('fixed') then this is the viewport edge.
03104 
03105        .... = the primary tile.
03106 
03107        . .  = the other tiles.
03108 
03109        #### = the dirtyRect. This is the minimum region we want to cover.
03110 
03111           A = The anchor point. This is the point at which the tile should
03112               start. Always negative or zero.
03113 
03114           x = x0 and y0 in the code. The point at which tiling must start
03115               so that the fewest tiles are laid out while completly
03116               covering the dirtyRect area.
03117 
03118           z = x1 and y1 in the code. The point at which tiling must end so
03119               that the fewest tiles are laid out while completly covering
03120               the dirtyRect area.
03121 
03122           w = the width of the tile (tileWidth).
03123 
03124           h = the height of the tile (tileHeight).
03125 
03126           n = the number of whole tiles that fit between 'A' and 'x'.
03127               (the vertical n and the horizontal n are different)
03128 
03129 
03130        Therefore, 
03131 
03132           x0 = bgClipArea.x + anchor.x + n * tileWidth;
03133 
03134        ...where n is an integer greater or equal to 0 fitting:
03135 
03136           n * tileWidth <= 
03137                       dirtyRect.x - (bgClipArea.x + anchor.x) <=
03138                                                              (n+1) * tileWidth
03139 
03140        ...i.e.,
03141 
03142           n <= (dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth < n + 1
03143 
03144        ...which, treating the division as an integer divide rounding down, gives:
03145 
03146           n = (dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth
03147 
03148        Substituting into the original expression for x0:
03149 
03150           x0 = bgClipArea.x + anchor.x +
03151                ((dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth) *
03152                tileWidth;
03153 
03154        From this x1 is determined,
03155 
03156           x1 = x0 + m * tileWidth;
03157 
03158        ...where m is an integer greater than 0 fitting:
03159 
03160           (m - 1) * tileWidth <
03161                             dirtyRect.x + dirtyRect.width - x0 <=
03162                                                                m * tileWidth
03163 
03164        ...i.e.,
03165 
03166           m - 1 < (dirtyRect.x + dirtyRect.width - x0) / tileWidth <= m
03167 
03168        ...which, treating the division as an integer divide, and making it
03169           round up, gives:
03170 
03171           m = (dirtyRect.x + dirtyRect.width - x0 + tileWidth - 1) / tileWidth
03172 
03173        Substituting into the original expression for x1:
03174 
03175           x1 = x0 + ((dirtyRect.x + dirtyRect.width - x0 + tileWidth - 1) /
03176                      tileWidth) * tileWidth
03177 
03178        The vertical case is analogous. If the background is fixed, then 
03179        bgClipArea.x and bgClipArea.y are set to zero when finding the parent
03180        viewport, above.
03181 
03182   */
03183 
03184   // first do the horizontal case
03185   nscoord x0, x1;
03186   // For scrolling attachment, the anchor is within the 'background-clip'
03187   // For fixed attachment, the anchor is within the bounds of the nearest
03188   // scrolling ancestor (or the viewport)
03189   x0 = (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) ?
03190        bgClipArea.x : 0;
03191   if (repeat & NS_STYLE_BG_REPEAT_X) {
03192     // When tiling in the x direction, adjust the starting position of the
03193     // tile to account for dirtyRect.x. When tiling in x, the anchor.x value
03194     // will be a negative value used to adjust the starting coordinate.
03195     x0 += anchor.x + 
03196           ((dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth) * tileWidth;
03197     x1 = x0 + ((dirtyRect.x + dirtyRect.width - x0 + tileWidth - 1) / tileWidth) * tileWidth;
03198   }
03199   else {
03200     x0 += anchor.x;
03201     x1 = x0 + tileWidth;
03202   }
03203 
03204   // now do all that again with the vertical case
03205   nscoord y0, y1;
03206   // For scrolling attachment, the anchor is within the 'background-clip'
03207   // For fixed attachment, the anchor is within the bounds of the nearest
03208   // scrolling ancestor (or the viewport)
03209   y0 = (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) ?
03210        bgClipArea.y : 0;
03211   if (repeat & NS_STYLE_BG_REPEAT_Y) {
03212     // When tiling in the y direction, adjust the starting position of the
03213     // tile to account for dirtyRect.y. When tiling in y, the anchor.y value
03214     // will be a negative value used to adjust the starting coordinate.
03215     y0 += anchor.y + 
03216           ((dirtyRect.y - (bgClipArea.y + anchor.y)) / tileHeight) * tileHeight;
03217     y1 = y0 + ((dirtyRect.y + dirtyRect.height - y0 + tileHeight - 1) / tileHeight) * tileHeight;
03218   }
03219   else {
03220     y0 += anchor.y;
03221     y1 = y0 + tileHeight;
03222   }
03223 
03224   // Take the intersection again to paint only the required area
03225   nsRect tileRect(x0, y0, (x1 - x0), (y1 - y0));
03226   nsRect drawRect;
03227 
03228   if (drawRect.IntersectRect(tileRect, dirtyRect))
03229     aRenderingContext.DrawTile(image, x0, y0, &drawRect);
03230 
03231 #if (!defined(XP_UNIX) && !defined(XP_BEOS)) || defined(XP_MACOSX)
03232   // Restore clipping
03233   aRenderingContext.PopState();
03234 #endif
03235 
03236 }
03237 
03238 void
03239 nsCSSRendering::PaintBackgroundColor(nsPresContext* aPresContext,
03240                                      nsIRenderingContext& aRenderingContext,
03241                                      nsIFrame* aForFrame,
03242                                      const nsRect& aBgClipArea,
03243                                      const nsStyleBackground& aColor,
03244                                      const nsStyleBorder& aBorder,
03245                                      const nsStylePadding& aPadding,
03246                                      PRBool aCanPaintNonWhite)
03247 {
03248   if (aColor.mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) {
03249     // nothing to paint
03250     return;
03251   }
03252 
03253   nsStyleCoord bordStyleRadius[4];
03254   PRInt16 borderRadii[4];
03255   nsRect bgClipArea(aBgClipArea);
03256 
03257   // get the radius for our border
03258   aBorder.mBorderRadius.GetTop(bordStyleRadius[NS_SIDE_TOP]);       // topleft
03259   aBorder.mBorderRadius.GetRight(bordStyleRadius[NS_SIDE_RIGHT]);   // topright
03260   aBorder.mBorderRadius.GetBottom(bordStyleRadius[NS_SIDE_BOTTOM]); // bottomright
03261   aBorder.mBorderRadius.GetLeft(bordStyleRadius[NS_SIDE_LEFT]);     // bottomleft
03262 
03263   PRUint8 side = 0;
03264   for (; side < 4; ++side) {
03265     borderRadii[side] = 0;
03266     switch (bordStyleRadius[side].GetUnit()) {
03267       case eStyleUnit_Percent:
03268         borderRadii[side] = nscoord(bordStyleRadius[side].GetPercentValue() * aBgClipArea.width);
03269         break;
03270       case eStyleUnit_Coord:
03271         borderRadii[side] = bordStyleRadius[side].GetCoordValue();
03272         break;
03273       default:
03274         break;
03275     }
03276   }
03277 
03278   // Rounded version of the border
03279   // XXXdwh Composite borders (with multiple colors per side) use their own border radius
03280   // algorithm now, since the current one doesn't work right for small radii.
03281   if (!aBorder.mBorderColors) {
03282     for (side = 0; side < 4; ++side) {
03283       if (borderRadii[side] > 0) {
03284         PaintRoundedBackground(aPresContext, aRenderingContext, aForFrame,
03285                                bgClipArea, aColor, aBorder, borderRadii,
03286                                aCanPaintNonWhite);
03287         return;
03288       }
03289     }
03290   }
03291   else if (aColor.mBackgroundClip == NS_STYLE_BG_CLIP_BORDER) {
03292     // XXX users of -moz-border-*-colors expect a transparent border-color
03293     // to show the parent's background-color instead of its background-color.
03294     // This seems wrong, but we handle that here by explictly clipping the
03295     // background to the padding area.
03296     bgClipArea.Deflate(aBorder.GetBorder());
03297   }
03298 
03299   nscolor color = aColor.mBackgroundColor;
03300   if (!aCanPaintNonWhite) {
03301     color = NS_RGB(255, 255, 255);
03302   }
03303   aRenderingContext.SetColor(color);
03304   aRenderingContext.FillRect(bgClipArea);
03305 }
03306 
03311 void
03312 nsCSSRendering::PaintRoundedBackground(nsPresContext* aPresContext,
03313                                        nsIRenderingContext& aRenderingContext,
03314                                        nsIFrame* aForFrame,
03315                                        const nsRect& aBgClipArea,
03316                                        const nsStyleBackground& aColor,
03317                                        const nsStyleBorder& aBorder,
03318                                        PRInt16 aTheRadius[4],
03319                                        PRBool aCanPaintNonWhite)
03320 {
03321   RoundedRect   outerPath;
03322   QBCurve       cr1,cr2,cr3,cr4;
03323   QBCurve       UL,UR,LL,LR;
03324   PRInt32       curIndex,c1Index;
03325   nsFloatPoint  thePath[MAXPATHSIZE];
03326   static nsPoint       polyPath[MAXPOLYPATHSIZE];
03327   PRInt16       np;
03328   nscoord       twipsPerPixel;
03329   float         p2t;
03330 
03331   // needed for our border thickness
03332   p2t = aPresContext->PixelsToTwips();
03333   twipsPerPixel = NSToCoordRound(p2t);
03334 
03335   nscolor color = aColor.mBackgroundColor;
03336   if (!aCanPaintNonWhite) {
03337     color = NS_RGB(255, 255, 255);
03338   }
03339   aRenderingContext.SetColor(color);
03340 
03341   // Adjust for background-clip, if necessary
03342   if (aColor.mBackgroundClip != NS_STYLE_BG_CLIP_BORDER) {
03343     NS_ASSERTION(aColor.mBackgroundClip == NS_STYLE_BG_CLIP_PADDING, "unknown background-clip value");
03344 
03345     // Get the radius to the outer edge of the padding.
03346     // -moz-border-radius is the radius to the outer edge of the border.
03347     NS_FOR_CSS_SIDES(side) {
03348       aTheRadius[side] -= aBorder.GetBorderWidth(side);
03349       aTheRadius[side] = PR_MAX(aTheRadius[side], 0);
03350     }
03351   }
03352 
03353   // set the rounded rect up, and let'er rip
03354   outerPath.Set(aBgClipArea.x,aBgClipArea.y,aBgClipArea.width,aBgClipArea.height,aTheRadius,twipsPerPixel);
03355   outerPath.GetRoundedBorders(UL,UR,LL,LR);
03356 
03357   // BUILD THE ENTIRE OUTSIDE PATH
03358   // TOP LINE ----------------------------------------------------------------
03359   UL.MidPointDivide(&cr1,&cr2);
03360   UR.MidPointDivide(&cr3,&cr4);
03361   np=0;
03362   thePath[np++].MoveTo(cr2.mAnc1.x,cr2.mAnc1.y);
03363   thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
03364   thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
03365   thePath[np++].MoveTo(cr3.mAnc1.x, cr3.mAnc1.y);
03366   thePath[np++].MoveTo(cr3.mCon.x, cr3.mCon.y);
03367   thePath[np++].MoveTo(cr3.mAnc2.x, cr3.mAnc2.y);
03368 
03369   polyPath[0].x = NSToCoordRound(thePath[0].x);
03370   polyPath[0].y = NSToCoordRound(thePath[0].y);
03371   curIndex = 1;
03372   GetPath(thePath,polyPath,&curIndex,eOutside,c1Index);
03373 
03374   // RIGHT LINE ----------------------------------------------------------------
03375   LR.MidPointDivide(&cr2,&cr3);
03376   np=0;
03377   thePath[np++].MoveTo(cr4.mAnc1.x,cr4.mAnc1.y);
03378   thePath[np++].MoveTo(cr4.mCon.x, cr4.mCon.y);
03379   thePath[np++].MoveTo(cr4.mAnc2.x, cr4.mAnc2.y);
03380   thePath[np++].MoveTo(cr2.mAnc1.x, cr2.mAnc1.y);
03381   thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
03382   thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
03383   GetPath(thePath,polyPath,&curIndex,eOutside,c1Index);
03384 
03385   // BOTTOM LINE ----------------------------------------------------------------
03386   LL.MidPointDivide(&cr2,&cr4);
03387   np=0;
03388   thePath[np++].MoveTo(cr3.mAnc1.x,cr3.mAnc1.y);
03389   thePath[np++].MoveTo(cr3.mCon.x, cr3.mCon.y);
03390   thePath[np++].MoveTo(cr3.mAnc2.x, cr3.mAnc2.y);
03391   thePath[np++].MoveTo(cr2.mAnc1.x, cr2.mAnc1.y);
03392   thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
03393   thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
03394   GetPath(thePath,polyPath,&curIndex,eOutside,c1Index);
03395 
03396   // LEFT LINE ----------------------------------------------------------------
03397   np=0;
03398   thePath[np++].MoveTo(cr4.mAnc1.x,cr4.mAnc1.y);
03399   thePath[np++].MoveTo(cr4.mCon.x, cr4.mCon.y);
03400   thePath[np++].MoveTo(cr4.mAnc2.x, cr4.mAnc2.y);
03401   thePath[np++].MoveTo(cr1.mAnc1.x, cr1.mAnc1.y);
03402   thePath[np++].MoveTo(cr1.mCon.x, cr1.mCon.y);
03403   thePath[np++].MoveTo(cr1.mAnc2.x, cr1.mAnc2.y);
03404   GetPath(thePath,polyPath,&curIndex,eOutside,c1Index);
03405 
03406   aRenderingContext.FillPolygon(polyPath,curIndex); 
03407 }
03408 
03409 
03414 void 
03415 nsCSSRendering::PaintRoundedBorder(nsPresContext* aPresContext,
03416                                  nsIRenderingContext& aRenderingContext,
03417                                  nsIFrame* aForFrame,
03418                                  const nsRect& aDirtyRect,
03419                                  const nsRect& aBorderArea,
03420                                  const nsStyleBorder* aBorderStyle,
03421                                  const nsStyleOutline* aOutlineStyle,
03422                                  nsStyleContext* aStyleContext,
03423                                  PRIntn aSkipSides,
03424                                  PRInt16 aBorderRadius[4],
03425                                  nsRect* aGap,
03426                                  PRBool aIsOutline)
03427 {
03428   RoundedRect   outerPath;
03429   QBCurve       UL,LL,UR,LR;
03430   QBCurve       IUL,ILL,IUR,ILR;
03431   QBCurve       cr1,cr2,cr3,cr4;
03432   QBCurve       Icr1,Icr2,Icr3,Icr4;
03433   nsFloatPoint  thePath[MAXPATHSIZE];
03434   PRInt16       np;
03435   nsMargin      border;
03436   nscoord       twipsPerPixel,qtwips;
03437   float         p2t;
03438 
03439   NS_ASSERTION((aIsOutline && aOutlineStyle) || (!aIsOutline && aBorderStyle), "null params not allowed");
03440   if (!aIsOutline) {
03441     aBorderStyle->CalcBorderFor(aForFrame, border);
03442     if ((0 == border.left) && (0 == border.right) &&
03443         (0 == border.top) && (0 == border.bottom)) {
03444       return;
03445     }
03446   } else {
03447     nscoord width;
03448     if (!aOutlineStyle->GetOutlineWidth(width)) {
03449       return;
03450     }
03451     border.left   = width;
03452     border.right  = width;
03453     border.top    = width;
03454     border.bottom = width;
03455   }
03456 
03457   // needed for our border thickness
03458   p2t = aPresContext->PixelsToTwips();
03459   twipsPerPixel = NSToCoordRound(p2t);
03460 
03461   // Base our thickness check on the segment being less than a pixel and 1/2
03462   qtwips = twipsPerPixel >> 2;
03463   //qtwips = twipsPerPixel;
03464 
03465   outerPath.Set(aBorderArea.x,aBorderArea.y,aBorderArea.width,aBorderArea.height,aBorderRadius,twipsPerPixel);
03466   outerPath.GetRoundedBorders(UL,UR,LL,LR);
03467   outerPath.CalcInsetCurves(IUL,IUR,ILL,ILR,border);
03468 
03469   // TOP LINE -- construct and divide the curves first, then put together our top and bottom paths
03470   UL.MidPointDivide(&cr1,&cr2);
03471   UR.MidPointDivide(&cr3,&cr4);
03472   IUL.MidPointDivide(&Icr1,&Icr2);
03473   IUR.MidPointDivide(&Icr3,&Icr4);
03474   if(0!=border.top){
03475     np=0;
03476     thePath[np++].MoveTo(cr2.mAnc1.x,cr2.mAnc1.y);
03477     thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
03478     thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
03479     thePath[np++].MoveTo(cr3.mAnc1.x, cr3.mAnc1.y);
03480     thePath[np++].MoveTo(cr3.mCon.x, cr3.mCon.y);
03481     thePath[np++].MoveTo(cr3.mAnc2.x, cr3.mAnc2.y);
03482  
03483     thePath[np++].MoveTo(Icr3.mAnc2.x,Icr3.mAnc2.y);
03484     thePath[np++].MoveTo(Icr3.mCon.x, Icr3.mCon.y);
03485     thePath[np++].MoveTo(Icr3.mAnc1.x, Icr3.mAnc1.y);
03486     thePath[np++].MoveTo(Icr2.mAnc2.x, Icr2.mAnc2.y);
03487     thePath[np++].MoveTo(Icr2.mCon.x, Icr2.mCon.y);
03488     thePath[np++].MoveTo(Icr2.mAnc1.x, Icr2.mAnc1.y);
03489     RenderSide(thePath,aRenderingContext,aBorderStyle,aOutlineStyle,aStyleContext,NS_SIDE_TOP,border,qtwips, aIsOutline);
03490   }
03491   // RIGHT  LINE ----------------------------------------------------------------
03492   LR.MidPointDivide(&cr2,&cr3);
03493   ILR.MidPointDivide(&Icr2,&Icr3);
03494   if(0!=border.right){
03495     np=0;
03496     thePath[np++].MoveTo(cr4.mAnc1.x,cr4.mAnc1.y);
03497     thePath[np++].MoveTo(cr4.mCon.x, cr4.mCon.y);
03498     thePath[np++].MoveTo(cr4.mAnc2.x,cr4.mAnc2.y);
03499     thePath[np++].MoveTo(cr2.mAnc1.x,cr2.mAnc1.y);
03500     thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
03501     thePath[np++].MoveTo(cr2.mAnc2.x,cr2.mAnc2.y);
03502 
03503     thePath[np++].MoveTo(Icr2.mAnc2.x,Icr2.mAnc2.y);
03504     thePath[np++].MoveTo(Icr2.mCon.x, Icr2.mCon.y);
03505     thePath[np++].MoveTo(Icr2.mAnc1.x,Icr2.mAnc1.y);
03506     thePath[np++].MoveTo(Icr4.mAnc2.x,Icr4.mAnc2.y);
03507     thePath[np++].MoveTo(Icr4.mCon.x, Icr4.mCon.y);
03508     thePath[np++].MoveTo(Icr4.mAnc1.x,Icr4.mAnc1.y);
03509     RenderSide(thePath,aRenderingContext,aBorderStyle,aOutlineStyle,aStyleContext,NS_SIDE_RIGHT,border,qtwips, aIsOutline);
03510   }
03511 
03512   // bottom line ----------------------------------------------------------------
03513   LL.MidPointDivide(&cr2,&cr4);
03514   ILL.MidPointDivide(&Icr2,&Icr4);
03515   if(0!=border.bottom){
03516     np=0;
03517     thePath[np++].MoveTo(cr3.mAnc1.x,cr3.mAnc1.y);
03518     thePath[np++].MoveTo(cr3.mCon.x, cr3.mCon.y);
03519     thePath[np++].MoveTo(cr3.mAnc2.x, cr3.mAnc2.y);
03520     thePath[np++].MoveTo(cr2.mAnc1.x, cr2.mAnc1.y);
03521     thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
03522     thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
03523 
03524     thePath[np++].MoveTo(Icr2.mAnc2.x,Icr2.mAnc2.y);
03525     thePath[np++].MoveTo(Icr2.mCon.x, Icr2.mCon.y);
03526     thePath[np++].MoveTo(Icr2.mAnc1.x, Icr2.mAnc1.y);
03527     thePath[np++].MoveTo(Icr3.mAnc2.x, Icr3.mAnc2.y);
03528     thePath[np++].MoveTo(Icr3.mCon.x, Icr3.mCon.y);
03529     thePath[np++].MoveTo(Icr3.mAnc1.x, Icr3.mAnc1.y);
03530     RenderSide(thePath,aRenderingContext,aBorderStyle,aOutlineStyle,aStyleContext,NS_SIDE_BOTTOM,border,qtwips, aIsOutline);
03531   }
03532   // left line ----------------------------------------------------------------
03533   if(0==border.left)
03534     return;
03535   np=0;
03536   thePath[np++].MoveTo(cr4.mAnc1.x,cr4.mAnc1.y);
03537   thePath[np++].MoveTo(cr4.mCon.x, cr4.mCon.y);
03538   thePath[np++].MoveTo(cr4.mAnc2.x, cr4.mAnc2.y);
03539   thePath[np++].MoveTo(cr1.mAnc1.x, cr1.mAnc1.y);
03540   thePath[np++].MoveTo(cr1.mCon.x, cr1.mCon.y);
03541   thePath[np++].MoveTo(cr1.mAnc2.x, cr1.mAnc2.y);
03542 
03543 
03544   thePath[np++].MoveTo(Icr1.mAnc2.x,Icr1.mAnc2.y);
03545   thePath[np++].MoveTo(Icr1.mCon.x, Icr1.mCon.y);
03546   thePath[np++].MoveTo(Icr1.mAnc1.x, Icr1.mAnc1.y);
03547   thePath[np++].MoveTo(Icr4.mAnc2.x, Icr4.mAnc2.y);
03548   thePath[np++].MoveTo(Icr4.mCon.x, Icr4.mCon.y);
03549   thePath[np++].MoveTo(Icr4.mAnc1.x, Icr4.mAnc1.y);
03550 
03551   RenderSide(thePath,aRenderingContext,aBorderStyle,aOutlineStyle,aStyleContext,NS_SIDE_LEFT,border,qtwips, aIsOutline);
03552 }
03553 
03554 
03559 void 
03560 nsCSSRendering::RenderSide(nsFloatPoint aPoints[],nsIRenderingContext& aRenderingContext,
03561                         const nsStyleBorder* aBorderStyle,const nsStyleOutline* aOutlineStyle,nsStyleContext* aStyleContext,
03562                         PRUint8 aSide,nsMargin  &aBorThick,nscoord aTwipsPerPixel,
03563                         PRBool aIsOutline)
03564 {
03565   QBCurve   thecurve;
03566   nscolor   sideColor = NS_RGB(0,0,0);
03567   static nsPoint   polypath[MAXPOLYPATHSIZE];
03568   PRInt32   curIndex,c1Index,c2Index,junk;
03569   PRInt8    border_Style;
03570   PRInt16   thickness;
03571 
03572   // Get our style context's color struct.
03573   const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
03574 
03575   NS_ASSERTION((aIsOutline && aOutlineStyle) || (!aIsOutline && aBorderStyle), "null params not allowed");
03576   // set the style information
03577   if (!aIsOutline) {
03578     if (!GetBorderColor(ourColor, *aBorderStyle, aSide, sideColor)) {
03579       return;
03580     }
03581   } else {
03582     aOutlineStyle->GetOutlineColor(sideColor);
03583   }
03584   aRenderingContext.SetColor ( sideColor );
03585 
03586   thickness = 0;
03587   switch(aSide){
03588     case  NS_SIDE_LEFT:
03589       thickness = aBorThick.left;
03590       break;
03591     case  NS_SIDE_TOP:
03592       thickness = aBorThick.top;
03593       break;
03594     case  NS_SIDE_RIGHT:
03595       thickness = aBorThick.right;
03596       break;
03597     case  NS_SIDE_BOTTOM:
03598       thickness = aBorThick.bottom;
03599       break;
03600   }
03601 
03602   // if the border is thin, just draw it 
03603   if (thickness<=aTwipsPerPixel) {
03604     // NOTHING FANCY JUST DRAW OUR OUTSIDE BORDER
03605     thecurve.SetPoints(aPoints[0].x,aPoints[0].y,aPoints[1].x,aPoints[1].y,aPoints[2].x,aPoints[2].y);
03606     thecurve.SubDivide((nsIRenderingContext*)&aRenderingContext,nsnull,nsnull);
03607     aRenderingContext.DrawLine((nscoord)aPoints[2].x,(nscoord)aPoints[2].y,(nscoord)aPoints[3].x,(nscoord)aPoints[3].y);
03608     thecurve.SetPoints(aPoints[3].x,aPoints[3].y,aPoints[4].x,aPoints[4].y,aPoints[5].x,aPoints[5].y);
03609     thecurve.SubDivide((nsIRenderingContext*)&aRenderingContext,nsnull,nsnull);
03610   } else {
03611     
03612     if (!aIsOutline) {
03613       border_Style = aBorderStyle->GetBorderStyle(aSide);
03614     } else {
03615       border_Style = aOutlineStyle->GetOutlineStyle();
03616     }
03617     switch (border_Style){
03618       case NS_STYLE_BORDER_STYLE_OUTSET:
03619       case NS_STYLE_BORDER_STYLE_INSET:
03620       case NS_STYLE_BORDER_STYLE_BG_OUTSET:
03621       case NS_STYLE_BORDER_STYLE_BG_INSET:
03622       case NS_STYLE_BORDER_STYLE_BG_SOLID:
03623         {
03624           const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
03625           if (border_Style == NS_STYLE_BORDER_STYLE_BG_SOLID) {
03626             nscolor colors[2]; 
03627             NS_Get3DColors(colors, bgColor->mBackgroundColor); 
03628             aRenderingContext.SetColor(colors[0]);
03629           } else {
03630             aRenderingContext.SetColor(MakeBevelColor(aSide, border_Style, bgColor->mBackgroundColor, sideColor, 
03631                                        !MOZ_BG_BORDER(border_Style)));
03632           }
03633         }
03634       case NS_STYLE_BORDER_STYLE_DOTTED:
03635       case NS_STYLE_BORDER_STYLE_DASHED:
03636         // break; XXX This is here until dotted and dashed are supported.  It is ok to have
03637         // dotted and dashed render in solid until this style is supported.  This code should
03638         // be moved when it is supported so that the above outset and inset will fall into the 
03639         // solid code below....
03640       case NS_STYLE_BORDER_STYLE_AUTO:
03641       case NS_STYLE_BORDER_STYLE_SOLID:
03642         polypath[0].x = NSToCoordRound(aPoints[0].x);
03643         polypath[0].y = NSToCoordRound(aPoints[0].y);
03644         curIndex = 1;
03645         GetPath(aPoints,polypath,&curIndex,eOutside,c1Index);
03646         c2Index = curIndex;
03647         if (curIndex >= MAXPOLYPATHSIZE)
03648           return;
03649         polypath[curIndex].x = NSToCoordRound(aPoints[6].x);
03650         polypath[curIndex].y = NSToCoordRound(aPoints[6].y);
03651         curIndex++;
03652         GetPath(aPoints,polypath,&curIndex,eInside,junk);
03653         if (curIndex >= MAXPOLYPATHSIZE)
03654           return;
03655         polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
03656         polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
03657         curIndex++;
03658         aRenderingContext.FillPolygon(polypath,curIndex);
03659 
03660        break;
03661       case NS_STYLE_BORDER_STYLE_DOUBLE:
03662         polypath[0].x = NSToCoordRound(aPoints[0].x);
03663         polypath[0].y = NSToCoordRound(aPoints[0].y);
03664         curIndex = 1;
03665         GetPath(aPoints,polypath,&curIndex,eOutside,c1Index);
03666         aRenderingContext.DrawPolyline(polypath,curIndex);
03667         polypath[0].x = NSToCoordRound(aPoints[6].x);
03668         polypath[0].y = NSToCoordRound(aPoints[6].y);
03669         curIndex = 1;
03670         GetPath(aPoints,polypath,&curIndex,eInside,c1Index);
03671         aRenderingContext.DrawPolyline(polypath,curIndex);
03672         break;
03673       case NS_STYLE_BORDER_STYLE_NONE:
03674       case NS_STYLE_BORDER_STYLE_HIDDEN:
03675         break;
03676       case NS_STYLE_BORDER_STYLE_RIDGE:
03677       case NS_STYLE_BORDER_STYLE_GROOVE:
03678         {
03679         const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
03680         aRenderingContext.SetColor ( MakeBevelColor (aSide, border_Style, bgColor->mBackgroundColor,sideColor, PR_TRUE));
03681 
03682         polypath[0].x = NSToCoordRound(aPoints[0].x);
03683         polypath[0].y = NSToCoordRound(aPoints[0].y);
03684         curIndex = 1;
03685         GetPath(aPoints,polypath,&curIndex,eOutside,c1Index);
03686         if (curIndex >= MAXPOLYPATHSIZE)
03687           return;
03688         polypath[curIndex].x = NSToCoordRound((aPoints[5].x + aPoints[6].x)/2.0f);
03689         polypath[curIndex].y = NSToCoordRound((aPoints[5].y + aPoints[6].y)/2.0f);
03690         curIndex++;
03691         GetPath(aPoints,polypath,&curIndex,eCalcRev,c1Index,.5);
03692         if (curIndex >= MAXPOLYPATHSIZE)
03693           return;
03694         polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
03695         polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
03696         curIndex++;
03697         aRenderingContext.FillPolygon(polypath,curIndex);
03698 
03699         aRenderingContext.SetColor ( MakeBevelColor (aSide, 
03700                                                 ((border_Style == NS_STYLE_BORDER_STYLE_RIDGE) ?
03701                                                 NS_STYLE_BORDER_STYLE_GROOVE :
03702                                                 NS_STYLE_BORDER_STYLE_RIDGE), 
03703                                                 bgColor->mBackgroundColor,sideColor, PR_TRUE));
03704        
03705         polypath[0].x = NSToCoordRound((aPoints[0].x + aPoints[11].x)/2.0f);
03706         polypath[0].y = NSToCoordRound((aPoints[0].y + aPoints[11].y)/2.0f);
03707         curIndex = 1;
03708         GetPath(aPoints,polypath,&curIndex,eCalc,c1Index,.5);
03709         if (curIndex >= MAXPOLYPATHSIZE)
03710           return;
03711         polypath[curIndex].x = NSToCoordRound(aPoints[6].x) ;
03712         polypath[curIndex].y = NSToCoordRound(aPoints[6].y);
03713         curIndex++;
03714         GetPath(aPoints,polypath,&curIndex,eInside,c1Index);
03715         if (curIndex >= MAXPOLYPATHSIZE)
03716           return;
03717         polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
03718         polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
03719         curIndex++;
03720         aRenderingContext.FillPolygon(polypath,curIndex);
03721         }
03722         break;
03723       default:
03724         break;
03725     }
03726   }
03727 }
03728 
03733 void 
03734 RoundedRect::CalcInsetCurves(QBCurve &aULCurve,QBCurve &aURCurve,QBCurve &aLLCurve,QBCurve &aLRCurve,nsMargin &aBorder)
03735 {
03736 PRInt32   nLeft,nTop,nRight,nBottom;
03737 PRInt32   tLeft,bLeft,tRight,bRight,lTop,rTop,lBottom,rBottom;
03738 PRInt16   adjust=0;
03739 
03740   if(mDoRound)
03741     adjust = mRoundness[0]>>3;
03742 
03743   nLeft = mLeft + aBorder.left;
03744   tLeft = mLeft + mRoundness[0];
03745   bLeft = mLeft + mRoundness[3];
03746 
03747   if(tLeft < nLeft){
03748     tLeft = nLeft;
03749   }
03750 
03751   if(bLeft < nLeft){
03752     bLeft = nLeft;
03753   }
03754 
03755   nRight = mRight - aBorder.right;
03756   tRight = mRight - mRoundness[1];
03757   bRight = mRight - mRoundness[2];
03758 
03759   if(tRight > nRight){
03760     tRight = nRight;
03761   }
03762 
03763   if(bRight > nRight){
03764     bRight = nRight;
03765   }
03766 
03767   nTop = mTop + aBorder.top;
03768   lTop = mTop + mRoundness[0];
03769   rTop = mTop + mRoundness[1];
03770 
03771   if(lTop < nTop){
03772     lTop = nTop;
03773   }
03774 
03775   if(rTop < nTop){
03776     rTop = nTop;
03777   }
03778 
03779   nBottom = mBottom - aBorder.bottom;
03780   lBottom = mBottom - mRoundness[3];
03781   rBottom = mBottom - mRoundness[2];
03782 
03783   if(lBottom > nBottom){
03784     lBottom = nBottom;
03785   }
03786 
03787   if(rBottom > nBottom){
03788     rBottom = nBottom;
03789   }
03790 
03791 
03792   // set the passed in curves to the rounded borders of the rectangle
03793   aULCurve.SetPoints( (float)nLeft,(float)lTop,
03794                       (float)nLeft+adjust,(float)nTop+adjust,
03795                       (float)tLeft,(float)nTop);
03796   aURCurve.SetPoints( (float)tRight,(float)nTop,
03797                       (float)nRight-adjust,(float)nTop+adjust,
03798                       (float)nRight,(float)rTop);
03799   aLRCurve.SetPoints( (float)nRight,(float)rBottom,
03800                       (float)nRight-adjust,(float)nBottom-adjust,
03801                       (float)bRight,(float)nBottom);
03802   aLLCurve.SetPoints( (float)bLeft,(float)nBottom,
03803                       (float)nLeft+adjust,(float)nBottom-adjust,
03804                       (float)nLeft,(float)lBottom);
03805 
03806 }
03807 
03812 void 
03813 RoundedRect::Set(nscoord aLeft,nscoord aTop,PRInt32  aWidth,PRInt32 aHeight,PRInt16 aRadius[4],PRInt16 aNumTwipPerPix)
03814 {
03815   nscoord x,y,width,height;
03816   int     i;
03817 
03818   // convert this rect to pixel boundaries
03819   x = (aLeft/aNumTwipPerPix)*aNumTwipPerPix;
03820   y = (aTop/aNumTwipPerPix)*aNumTwipPerPix;
03821   width = (aWidth/aNumTwipPerPix)*aNumTwipPerPix;
03822   height = (aHeight/aNumTwipPerPix)*aNumTwipPerPix;
03823 
03824 
03825   for(i=0;i<4;i++) {
03826     if( (aRadius[i]) > (aWidth>>1) ){
03827       mRoundness[i] = (aWidth>>1); 
03828     } else {
03829       mRoundness[i] = aRadius[i];
03830     }
03831 
03832     if( mRoundness[i] > (aHeight>>1) )
03833       mRoundness[i] = aHeight>>1;
03834   }
03835 
03836 
03837   // if we are drawing a circle
03838   mDoRound = PR_FALSE;
03839   if(aHeight==aWidth){
03840     PRBool doRound = PR_TRUE;
03841     for(i=0;i<4;i++){
03842       if(mRoundness[i]<(aWidth>>1)){
03843         doRound = PR_FALSE;
03844         break;
03845       }
03846     }
03847 
03848     if(doRound){
03849       mDoRound = PR_TRUE;
03850       for(i=0;i<4;i++){
03851         mRoundness[i] = aWidth>>1;
03852       }
03853     }
03854   }
03855 
03856 
03857 
03858   // important coordinates that the path hits
03859   mLeft = x;
03860   mTop = y;
03861   mRight = x+width;
03862   mBottom = y+height;
03863 
03864 }
03865 
03870 void 
03871 RoundedRect::GetRoundedBorders(QBCurve &aULCurve,QBCurve &aURCurve,QBCurve &aLLCurve,QBCurve &aLRCurve)
03872 {
03873 
03874   PRInt16 adjust=0;
03875 
03876   if(mDoRound)
03877     adjust = mRoundness[0]>>3;
03878 
03879   // set the passed in curves to the rounded borders of the rectangle
03880   aULCurve.SetPoints( (float)mLeft,(float)mTop + mRoundness[0],
03881                       (float)mLeft+adjust,(float)mTop+adjust,
03882                       (float)mLeft+mRoundness[0],(float)mTop);
03883   aURCurve.SetPoints( (float)mRight - mRoundness[1],(float)mTop,
03884                       (float)mRight-adjust,(float)mTop+adjust,
03885                       (float)mRight,(float)mTop + mRoundness[1]);
03886   aLRCurve.SetPoints( (float)mRight,(float)mBottom - mRoundness[2],
03887                       (float)mRight-adjust,(float)mBottom-adjust,
03888                       (float)mRight - mRoundness[2],(float)mBottom);
03889   aLLCurve.SetPoints( (float)mLeft + mRoundness[3],(float)mBottom,
03890                       (float)mLeft+adjust,(float)mBottom-adjust,
03891                       (float)mLeft,(float)mBottom - mRoundness[3]);
03892 }
03893 
03903 static void 
03904 GetPath(nsFloatPoint aPoints[],nsPoint aPolyPath[],PRInt32 *aCurIndex,ePathTypes  aPathType,PRInt32 &aC1Index,float aFrac)
03905 {
03906   QBCurve thecurve;
03907   
03908   if (*aCurIndex >= MAXPOLYPATHSIZE)
03909     return;
03910 
03911   switch (aPathType) {
03912     case eOutside:
03913       thecurve.SetPoints(aPoints[0].x,aPoints[0].y,aPoints[1].x,aPoints[1].y,aPoints[2].x,aPoints[2].y);
03914       thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
03915       aC1Index = *aCurIndex;
03916       if (*aCurIndex >= MAXPOLYPATHSIZE)
03917         return;
03918       aPolyPath[*aCurIndex].x = (nscoord)aPoints[3].x;
03919       aPolyPath[*aCurIndex].y = (nscoord)aPoints[3].y;
03920       (*aCurIndex)++;
03921       if (*aCurIndex >= MAXPOLYPATHSIZE)
03922         return;
03923       thecurve.SetPoints(aPoints[3].x,aPoints[3].y,aPoints[4].x,aPoints[4].y,aPoints[5].x,aPoints[5].y);
03924       thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
03925       break;
03926     case eInside:
03927       thecurve.SetPoints(aPoints[6].x,aPoints[6].y,aPoints[7].x,aPoints[7].y,aPoints[8].x,aPoints[8].y);
03928       thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
03929       if (*aCurIndex >= MAXPOLYPATHSIZE)
03930         return;
03931       aPolyPath[*aCurIndex].x = (nscoord)aPoints[9].x;
03932       aPolyPath[*aCurIndex].y = (nscoord)aPoints[9].y;
03933       (*aCurIndex)++;
03934       if (*aCurIndex >= MAXPOLYPATHSIZE)
03935         return;
03936       thecurve.SetPoints(aPoints[9].x,aPoints[9].y,aPoints[10].x,aPoints[10].y,aPoints[11].x,aPoints[11].y);
03937       thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
03938      break;
03939     case eCalc:
03940       thecurve.SetPoints( (aPoints[0].x+aPoints[11].x)/2.0f,(aPoints[0].y+aPoints[11].y)/2.0f,
03941                           (aPoints[1].x+aPoints[10].x)/2.0f,(aPoints[1].y+aPoints[10].y)/2.0f,
03942                           (aPoints[2].x+aPoints[9].x)/2.0f,(aPoints[2].y+aPoints[9].y)/2.0f);
03943       thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
03944       if (*aCurIndex >= MAXPOLYPATHSIZE)
03945         return;
03946       aPolyPath[*aCurIndex].x = (nscoord)((aPoints[3].x+aPoints[8].x)/2.0f);
03947       aPolyPath[*aCurIndex].y = (nscoord)((aPoints[3].y+aPoints[8].y)/2.0f);
03948       (*aCurIndex)++;
03949       if (*aCurIndex >= MAXPOLYPATHSIZE)
03950         return;
03951       thecurve.SetPoints( (aPoints[3].x+aPoints[8].x)/2.0f,(aPoints[3].y+aPoints[8].y)/2.0f,
03952                           (aPoints[4].x+aPoints[7].x)/2.0f,(aPoints[4].y+aPoints[7].y)/2.0f,
03953                           (aPoints[5].x+aPoints[6].x)/2.0f,(aPoints[5].y+aPoints[6].y)/2.0f);
03954       thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
03955       break;
03956     case eCalcRev:
03957       thecurve.SetPoints( (aPoints[5].x+aPoints[6].x)/2.0f,(aPoints[5].y+aPoints[6].y)/2.0f,
03958                           (aPoints[4].x+aPoints[7].x)/2.0f,(aPoints[4].y+aPoints[7].y)/2.0f,
03959                           (aPoints[3].x+aPoints[8].x)/2.0f,(aPoints[3].y+aPoints[8].y)/2.0f);
03960       thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
03961       aPolyPath[*aCurIndex].x = (nscoord)((aPoints[2].x+aPoints[9].x)/2.0f);
03962       aPolyPath[*aCurIndex].y = (nscoord)((aPoints[2].y+aPoints[9].y)/2.0f);
03963       (*aCurIndex)++;
03964       if (*aCurIndex >= MAXPOLYPATHSIZE)
03965         return;
03966       thecurve.SetPoints( (aPoints[2].x+aPoints[9].x)/2.0f,(aPoints[2].y+aPoints[9].y)/2.0f,
03967                           (aPoints[1].x+aPoints[10].x)/2.0f,(aPoints[1].y+aPoints[10].y)/2.0f,
03968                           (aPoints[0].x+aPoints[11].x)/2.0f,(aPoints[0].y+aPoints[11].y)/2.0f);
03969       thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
03970       break;
03971   } 
03972 }
03973 
03978 void 
03979 QBCurve::SubDivide(nsIRenderingContext *aRenderingContext,nsPoint aPointArray[],PRInt32 *aCurIndex)
03980 {
03981   QBCurve   curve1,curve2;
03982   float     fx,fy,smag, oldfx, oldfy, oldsmag;
03983   
03984   if (aCurIndex && (*aCurIndex >= MAXPOLYPATHSIZE))
03985     return;
03986   
03987   oldfx = (this->mAnc1.x + this->mAnc2.x)/2.0f - this->mCon.x;
03988   oldfy = (this->mAnc1.y + this->mAnc2.y)/2.0f - this->mCon.y;
03989   oldsmag = oldfx * oldfx + oldfy * oldfy;
03990   // divide the curve into 2 pieces
03991   MidPointDivide(&curve1,&curve2);
03992 
03993   fx = (float)fabs(curve1.mAnc2.x - this->mCon.x);
03994   fy = (float)fabs(curve1.mAnc2.y - this->mCon.y);
03995 
03996   //smag = fx+fy-(PR_MIN(fx,fy)>>1);
03997   smag = fx*fx + fy*fy;
03998  
03999   if (smag>1){
04000     if (smag + 0.2 > oldsmag)
04001       return; // we did not get closer
04002     // split the curve again
04003     curve1.SubDivide(aRenderingContext,aPointArray,aCurIndex);
04004     curve2.SubDivide(aRenderingContext,aPointArray,aCurIndex);
04005   }else{
04006     if(aPointArray ) {
04007       // save the points for further processing
04008       aPointArray[*aCurIndex].x = (nscoord)curve1.mAnc2.x;
04009       aPointArray[*aCurIndex].y = (nscoord)curve1.mAnc2.y;
04010       (*aCurIndex)++;
04011       if (*aCurIndex >= MAXPOLYPATHSIZE)
04012         return;
04013       aPointArray[*aCurIndex].x = (nscoord)curve2.mAnc2.x;
04014       aPointArray[*aCurIndex].y = (nscoord)curve2.mAnc2.y;
04015       (*aCurIndex)++;
04016     }else{
04017       // draw the curve 
04018       nsTransform2D *aTransform;
04019       aRenderingContext->GetCurrentTransform(aTransform);
04020 
04021       
04022       aRenderingContext->DrawLine((nscoord)curve1.mAnc1.x,(nscoord)curve1.mAnc1.y,(nscoord)curve1.mAnc2.x,(nscoord)curve1.mAnc2.y);
04023       aRenderingContext->DrawLine((nscoord)curve1.mAnc2.x,(nscoord)curve1.mAnc2.y,(nscoord)curve2.mAnc2.x,(nscoord)curve2.mAnc2.y);
04024     }
04025   }
04026 }
04027 
04032 void 
04033 QBCurve::MidPointDivide(QBCurve *A,QBCurve *B)
04034 {
04035   float c1x,c1y,c2x,c2y;
04036   nsFloatPoint a1;
04037 
04038   c1x = (mAnc1.x+mCon.x)/2.0f;
04039   c1y = (mAnc1.y+mCon.y)/2.0f;
04040   c2x = (mAnc2.x+mCon.x)/2.0f;
04041   c2y = (mAnc2.y+mCon.y)/2.0f;
04042 
04043   a1.x = (c1x + c2x)/2.0f;
04044   a1.y = (c1y + c2y)/2.0f;
04045 
04046   // put the math into our 2 new curves
04047   A->mAnc1 = this->mAnc1;
04048   A->mCon.x = c1x;
04049   A->mCon.y = c1y;
04050   A->mAnc2 = a1;
04051   B->mAnc1 = a1;
04052   B->mCon.x = c2x;
04053   B->mCon.y = c2y;
04054   B->mAnc2 = this->mAnc2;
04055 }
04056 
04057 void FillOrInvertRect(nsIRenderingContext& aRC, nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aInvert)
04058 {
04059   if (aInvert) {
04060     aRC.InvertRect(aX, aY, aWidth, aHeight);
04061   } else {
04062     aRC.FillRect(aX, aY, aWidth, aHeight);
04063   }
04064 }
04065 
04066 void FillOrInvertRect(nsIRenderingContext& aRC, const nsRect& aRect, PRBool aInvert)
04067 {
04068   if (aInvert) {
04069     aRC.InvertRect(aRect);
04070   } else {
04071     aRC.FillRect(aRect);
04072   }
04073 }
04074 
04075 // Begin table border-collapsing section
04076 // These functions were written to not disrupt the normal ones and yet satisfy some additional requirements
04077 // At some point, all functions should be unified to include the additional functionality that these provide
04078 
04079 static nscoord
04080 RoundIntToPixel(nscoord aValue, 
04081                 nscoord aTwipsPerPixel,
04082                 PRBool  aRoundDown = PR_FALSE)
04083 {
04084   if (aTwipsPerPixel <= 0) 
04085     // We must be rendering to a device that has a resolution greater than Twips! 
04086     // In that case, aValue is as accurate as it's going to get.
04087     return aValue; 
04088 
04089   nscoord halfPixel = NSToCoordRound(aTwipsPerPixel / 2.0f);
04090   nscoord extra = aValue % aTwipsPerPixel;
04091   nscoord finalValue = (!aRoundDown && (extra >= halfPixel)) ? aValue + (aTwipsPerPixel - extra) : aValue - extra;
04092   return finalValue;
04093 }
04094 
04095 static nscoord
04096 RoundFloatToPixel(float   aValue, 
04097                   nscoord aTwipsPerPixel,
04098                   PRBool  aRoundDown = PR_FALSE)
04099 {
04100   return RoundIntToPixel(NSToCoordRound(aValue), aTwipsPerPixel, aRoundDown);
04101 }
04102 
04103 static void
04104 SetPoly(const nsRect& aRect,
04105         nsPoint*      poly)
04106 {
04107   poly[0].x = aRect.x;
04108   poly[0].y = aRect.y;
04109   poly[1].x = aRect.x + aRect.width;
04110   poly[1].y = aRect.y;
04111   poly[2].x = aRect.x + aRect.width;
04112   poly[2].y = aRect.y + aRect.height;
04113   poly[3].x = aRect.x;
04114   poly[3].y = aRect.y + aRect.height;
04115   poly[4].x = aRect.x;
04116   poly[4].y = aRect.y;
04117 }
04118           
04119 static void 
04120 DrawSolidBorderSegment(nsIRenderingContext& aContext,
04121                        nsRect               aRect,
04122                        nscoord              aTwipsPerPixel,
04123                        PRUint8              aStartBevelSide = 0,
04124                        nscoord              aStartBevelOffset = 0,
04125                        PRUint8              aEndBevelSide = 0,
04126                        nscoord              aEndBevelOffset = 0)
04127 {
04128 
04129   if ((aRect.width == aTwipsPerPixel) || (aRect.height == aTwipsPerPixel) ||
04130       ((0 == aStartBevelOffset) && (0 == aEndBevelOffset))) {
04131     // simple line or rectangle
04132     if ((NS_SIDE_TOP == aStartBevelSide) || (NS_SIDE_BOTTOM == aStartBevelSide)) {
04133       if (1 == aRect.height) 
04134         aContext.DrawLine(aRect.x, aRect.y, aRect.x, aRect.y + aRect.height); 
04135       else 
04136         aContext.FillRect(aRect);
04137     }
04138     else {
04139       if (1 == aRect.width) 
04140         aContext.DrawLine(aRect.x, aRect.y, aRect.x + aRect.width, aRect.y); 
04141       else 
04142         aContext.FillRect(aRect);
04143     }
04144   }
04145   else {
04146     // polygon with beveling
04147     nsPoint poly[5];
04148     SetPoly(aRect, poly);
04149     switch(aStartBevelSide) {
04150     case NS_SIDE_TOP:
04151       poly[0].x += aStartBevelOffset;
04152       poly[4].x = poly[0].x;
04153       break;
04154     case NS_SIDE_BOTTOM:
04155       poly[3].x += aStartBevelOffset;
04156       break;
04157     case NS_SIDE_RIGHT:
04158       poly[1].y += aStartBevelOffset;
04159       break;
04160     case NS_SIDE_LEFT:
04161       poly[0].y += aStartBevelOffset;
04162       poly[4].y = poly[0].y;
04163     }
04164 
04165     switch(aEndBevelSide) {
04166     case NS_SIDE_TOP:
04167       poly[1].x -= aEndBevelOffset;
04168       break;
04169     case NS_SIDE_BOTTOM:
04170       poly[2].x -= aEndBevelOffset;
04171       break;
04172     case NS_SIDE_RIGHT:
04173       poly[2].y -= aEndBevelOffset;
04174       break;
04175     case NS_SIDE_LEFT:
04176       poly[3].y -= aEndBevelOffset;
04177     }
04178 
04179     aContext.FillPolygon(poly, 5);
04180   }
04181 
04182 
04183 }
04184 
04185 static void
04186 GetDashInfo(nscoord  aBorderLength,
04187             nscoord  aDashLength,
04188             nscoord  aTwipsPerPixel,
04189             PRInt32& aNumDashSpaces,
04190             nscoord& aStartDashLength,
04191             nscoord& aEndDashLength)
04192 {
04193   aNumDashSpaces = 0;
04194   if (aStartDashLength + aDashLength + aEndDashLength >= aBorderLength) {
04195     aStartDashLength = aBorderLength;
04196     aEndDashLength = 0;
04197   }
04198   else {
04199     aNumDashSpaces = aBorderLength / (2 * aDashLength); // round down
04200     nscoord extra = aBorderLength - aStartDashLength - aEndDashLength - (((2 * aNumDashSpaces) - 1) * aDashLength);
04201     if (extra > 0) {
04202       nscoord half = RoundIntToPixel(extra / 2, aTwipsPerPixel);
04203       aStartDashLength += half;
04204       aEndDashLength += (extra - half);
04205     }
04206   }
04207 }
04208 
04209 void 
04210 nsCSSRendering::DrawTableBorderSegment(nsIRenderingContext&     aContext,
04211                                        PRUint8                  aBorderStyle,  
04212                                        nscolor                  aBorderColor,
04213                                        const nsStyleBackground* aBGColor,
04214                                        const nsRect&            aBorder,
04215                                        float                    aPixelsToTwips,
04216                                        PRUint8                  aStartBevelSide,
04217                                        nscoord                  aStartBevelOffset,
04218                                        PRUint8                  aEndBevelSide,
04219                                        nscoord                  aEndBevelOffset)
04220 {
04221   aContext.SetColor (aBorderColor); 
04222 
04223   PRBool horizontal = ((NS_SIDE_TOP == aStartBevelSide) || (NS_SIDE_BOTTOM == aStartBevelSide));
04224   nscoord twipsPerPixel = NSIntPixelsToTwips(1, aPixelsToTwips);
04225   PRBool ridgeGroove = NS_STYLE_BORDER_STYLE_RIDGE;
04226 
04227   if ((twipsPerPixel >= aBorder.width) || (twipsPerPixel >= aBorder.height) ||
04228       (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) || (NS_STYLE_BORDER_STYLE_DOTTED == aBorderStyle)) {
04229     // no beveling for 1 pixel border, dash or dot
04230     aStartBevelOffset = 0;
04231     aEndBevelOffset = 0;
04232   }
04233 
04234   switch (aBorderStyle) {
04235   case NS_STYLE_BORDER_STYLE_NONE:
04236   case NS_STYLE_BORDER_STYLE_HIDDEN:
04237     //NS_ASSERTION(PR_FALSE, "style of none or hidden");
04238     break;
04239   case NS_STYLE_BORDER_STYLE_DOTTED:
04240   case NS_STYLE_BORDER_STYLE_DASHED: 
04241     {
04242       nscoord dashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) ? DASH_LENGTH : DOT_LENGTH;
04243       // make the dash length proportional to the border thickness
04244       dashLength *= (horizontal) ? aBorder.height : aBorder.width;
04245       // make the min dash length for the ends 1/2 the dash length
04246       nscoord minDashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) 
04247                               ? RoundFloatToPixel(((float)dashLength) / 2.0f, twipsPerPixel) : dashLength;
04248       minDashLength = PR_MAX(minDashLength, twipsPerPixel);
04249       nscoord numDashSpaces = 0;
04250       nscoord startDashLength = minDashLength;
04251       nscoord endDashLength   = minDashLength;
04252       if (horizontal) {
04253         GetDashInfo(aBorder.width, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength);
04254         nsRect rect(aBorder.x, aBorder.y, startDashLength, aBorder.height);
04255         DrawSolidBorderSegment(aContext, rect, PR_TRUE);
04256         for (PRInt32 spaceX = 0; spaceX < numDashSpaces; spaceX++) {
04257           rect.x += rect.width + dashLength;
04258           rect.width = (spaceX == (numDashSpaces - 1)) ? endDashLength : dashLength;
04259           DrawSolidBorderSegment(aContext, rect, PR_TRUE);
04260         }
04261       }
04262       else {
04263         GetDashInfo(aBorder.height, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength);
04264         nsRect rect(aBorder.x, aBorder.y, aBorder.width, startDashLength);
04265         DrawSolidBorderSegment(aContext, rect, PR_FALSE);
04266         for (PRInt32 spaceY = 0; spaceY < numDashSpaces; spaceY++) {
04267           rect.y += rect.height + dashLength;
04268           rect.height = (spaceY == (numDashSpaces - 1)) ? endDashLength : dashLength;
04269           DrawSolidBorderSegment(aContext, rect, PR_FALSE);
04270         }
04271       }
04272     }
04273     break;                                  
04274   case NS_STYLE_BORDER_STYLE_GROOVE:
04275     ridgeGroove = NS_STYLE_BORDER_STYLE_GROOVE; // and fall through to ridge
04276   case NS_STYLE_BORDER_STYLE_RIDGE:
04277     if ((horizontal && (twipsPerPixel >= aBorder.height)) ||
04278         (!horizontal && (twipsPerPixel >= aBorder.width))) {
04279       // a one pixel border
04280       DrawSolidBorderSegment(aContext, aBorder, twipsPerPixel, aStartBevelSide, aStartBevelOffset,
04281                              aEndBevelSide, aEndBevelOffset);
04282     }
04283     else {
04284       nscoord startBevel = (aStartBevelOffset > 0) 
04285                             ? RoundFloatToPixel(0.5f * (float)aStartBevelOffset, twipsPerPixel, PR_TRUE) : 0;
04286       nscoord endBevel =   (aEndBevelOffset > 0) 
04287                             ? RoundFloatToPixel(0.5f * (float)aEndBevelOffset, twipsPerPixel, PR_TRUE) : 0;
04288       PRUint8 ridgeGrooveSide = (horizontal) ? NS_SIDE_TOP : NS_SIDE_LEFT;
04289       aContext.SetColor ( 
04290         MakeBevelColor (ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor, PR_TRUE));
04291       nsRect rect(aBorder);
04292       nscoord half;
04293       if (horizontal) { // top, bottom
04294         half = RoundFloatToPixel(0.5f * (float)aBorder.height, twipsPerPixel);
04295         rect.height = half;
04296         if (NS_SIDE_TOP == aStartBevelSide) {
04297           rect.x += startBevel;
04298           rect.width -= startBevel;
04299         }
04300         if (NS_SIDE_TOP == aEndBevelSide) {
04301           rect.width -= endBevel;
04302         }
04303         DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide, 
04304                                startBevel, aEndBevelSide, endBevel);
04305       }
04306       else { // left, right
04307         half = RoundFloatToPixel(0.5f * (float)aBorder.width, twipsPerPixel);
04308         rect.width = half;
04309         if (NS_SIDE_LEFT == aStartBevelSide) {
04310           rect.y += startBevel;
04311           rect.height -= startBevel;
04312         }
04313         if (NS_SIDE_LEFT == aEndBevelSide) {
04314           rect.height -= endBevel;
04315         }
04316         DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide, 
04317                                startBevel, aEndBevelSide, endBevel);
04318       }
04319 
04320       rect = aBorder;
04321       ridgeGrooveSide = (NS_SIDE_TOP == ridgeGrooveSide) ? NS_SIDE_BOTTOM : NS_SIDE_RIGHT;
04322       aContext.SetColor ( 
04323         MakeBevelColor (ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor, PR_TRUE));
04324       if (horizontal) {
04325         rect.y = rect.y + half;
04326         rect.height = aBorder.height - half;
04327         if (NS_SIDE_BOTTOM == aStartBevelSide) {
04328           rect.x += startBevel;
04329           rect.width -= startBevel;
04330         }
04331         if (NS_SIDE_BOTTOM == aEndBevelSide) {
04332           rect.width -= endBevel;
04333         }
04334         DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide, 
04335                                startBevel, aEndBevelSide, endBevel);
04336       }
04337       else {
04338         rect.x = rect.x + half;
04339         rect.width = aBorder.width - half;
04340         if (NS_SIDE_RIGHT == aStartBevelSide) {
04341           rect.y += aStartBevelOffset - startBevel;
04342           rect.height -= startBevel;
04343         }
04344         if (NS_SIDE_RIGHT == aEndBevelSide) {
04345           rect.height -= endBevel;
04346         }
04347         DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide, 
04348                                startBevel, aEndBevelSide, endBevel);
04349       }
04350     }
04351     break;
04352   case NS_STYLE_BORDER_STYLE_DOUBLE:
04353     if ((aBorder.width > 2) && (aBorder.height > 2)) {
04354       nscoord startBevel = (aStartBevelOffset > 0) 
04355                             ? RoundFloatToPixel(0.333333f * (float)aStartBevelOffset, twipsPerPixel) : 0;
04356       nscoord endBevel =   (aEndBevelOffset > 0) 
04357                             ? RoundFloatToPixel(0.333333f * (float)aEndBevelOffset, twipsPerPixel) : 0;
04358       if (horizontal) { // top, bottom
04359         nscoord thirdHeight = RoundFloatToPixel(0.333333f * (float)aBorder.height, twipsPerPixel);
04360 
04361         // draw the top line or rect
04362         nsRect topRect(aBorder.x, aBorder.y, aBorder.width, thirdHeight);
04363         if (NS_SIDE_TOP == aStartBevelSide) {
04364           topRect.x += aStartBevelOffset - startBevel;
04365           topRect.width -= aStartBevelOffset - startBevel;
04366         }
04367         if (NS_SIDE_TOP == aEndBevelSide) {
04368           topRect.width -= aEndBevelOffset - endBevel;
04369         }
04370         DrawSolidBorderSegment(aContext, topRect, twipsPerPixel, aStartBevelSide, 
04371                                startBevel, aEndBevelSide, endBevel);
04372 
04373         // draw the botom line or rect
04374         nscoord heightOffset = aBorder.height - thirdHeight; 
04375         nsRect bottomRect(aBorder.x, aBorder.y + heightOffset, aBorder.width, aBorder.height - heightOffset);
04376         if (NS_SIDE_BOTTOM == aStartBevelSide) {
04377           bottomRect.x += aStartBevelOffset - startBevel;
04378           bottomRect.width -= aStartBevelOffset - startBevel;
04379         }
04380         if (NS_SIDE_BOTTOM == aEndBevelSide) {
04381           bottomRect.width -= aEndBevelOffset - endBevel;
04382         }
04383         DrawSolidBorderSegment(aContext, bottomRect, twipsPerPixel, aStartBevelSide, 
04384                                startBevel, aEndBevelSide, endBevel);
04385       }
04386       else { // left, right
04387         nscoord thirdWidth = RoundFloatToPixel(0.333333f * (float)aBorder.width, twipsPerPixel);
04388 
04389         nsRect leftRect(aBorder.x, aBorder.y, thirdWidth, aBorder.height); 
04390         if (NS_SIDE_LEFT == aStartBevelSide) {
04391           leftRect.y += aStartBevelOffset - startBevel;
04392           leftRect.height -= aStartBevelOffset - startBevel;
04393         }
04394         if (NS_SIDE_LEFT == aEndBevelSide) {
04395           leftRect.height -= aEndBevelOffset - endBevel;
04396         }
04397         DrawSolidBorderSegment(aContext, leftRect, twipsPerPixel, aStartBevelSide,
04398                                startBevel, aEndBevelSide, endBevel);
04399 
04400         nscoord widthOffset = aBorder.width - thirdWidth; 
04401         nsRect rightRect(aBorder.x + widthOffset, aBorder.y, aBorder.width - widthOffset, aBorder.height);
04402         if (NS_SIDE_RIGHT == aStartBevelSide) {
04403           rightRect.y += aStartBevelOffset - startBevel;
04404           rightRect.height -= aStartBevelOffset - startBevel;
04405         }
04406         if (NS_SIDE_RIGHT == aEndBevelSide) {
04407           rightRect.height -= aEndBevelOffset - endBevel;
04408         }
04409         DrawSolidBorderSegment(aContext, rightRect, twipsPerPixel, aStartBevelSide,
04410                                startBevel, aEndBevelSide, endBevel);
04411       }
04412       break;
04413     }
04414     // else fall through to solid
04415   case NS_STYLE_BORDER_STYLE_BG_SOLID:
04416   case NS_STYLE_BORDER_STYLE_SOLID:
04417     DrawSolidBorderSegment(aContext, aBorder, twipsPerPixel, aStartBevelSide, 
04418                            aStartBevelOffset, aEndBevelSide, aEndBevelOffset);
04419     break;
04420   case NS_STYLE_BORDER_STYLE_BG_OUTSET:
04421   case NS_STYLE_BORDER_STYLE_BG_INSET:
04422   case NS_STYLE_BORDER_STYLE_OUTSET:
04423   case NS_STYLE_BORDER_STYLE_INSET:
04424     NS_ASSERTION(PR_FALSE, "inset, outset should have been converted to groove, ridge");
04425     break;
04426   case NS_STYLE_BORDER_STYLE_AUTO:
04427     NS_ASSERTION(PR_FALSE, "Unexpected 'auto' table border");
04428     break;
04429   }
04430 }
04431 
04432 // End table border-collapsing section
04433