~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/layout/html/style/src/nsCSSRendering.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
// vim:cindent:ts=2:et:sw=2:
 
3
/* ***** BEGIN LICENSE BLOCK *****
 
4
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 
5
 *
 
6
 * The contents of this file are subject to the Netscape Public License
 
7
 * Version 1.1 (the "License"); you may not use this file except in
 
8
 * compliance with the License. You may obtain a copy of the License at
 
9
 * http://www.mozilla.org/NPL/
 
10
 *
 
11
 * Software distributed under the License is distributed on an "AS IS" basis,
 
12
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
13
 * for the specific language governing rights and limitations under the
 
14
 * License.
 
15
 *
 
16
 * The Original Code is mozilla.org code.
 
17
 *
 
18
 * The Initial Developer of the Original Code is 
 
19
 * Netscape Communications Corporation.
 
20
 * Portions created by the Initial Developer are Copyright (C) 1998
 
21
 * the Initial Developer. All Rights Reserved.
 
22
 *
 
23
 * Contributor(s):
 
24
 *
 
25
 * Alternatively, the contents of this file may be used under the terms of
 
26
 * either the GNU General Public License Version 2 or later (the "GPL"), or 
 
27
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
29
 * of those above. If you wish to allow use of your version of this file only
 
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
31
 * use your version of this file under the terms of the NPL, indicate your
 
32
 * decision by deleting the provisions above and replace them with the notice
 
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
34
 * the provisions above, a recipient may use your version of this file under
 
35
 * the terms of any one of the NPL, the GPL or the LGPL.
 
36
 *
 
37
 * ***** END LICENSE BLOCK ***** */
 
38
#include "nsStyleConsts.h"
 
39
#include "nsIPresContext.h"
 
40
#include "nsIImage.h"
 
41
#include "nsIFrame.h"
 
42
#include "nsPoint.h"
 
43
#include "nsRect.h"
 
44
#include "nsIViewManager.h"
 
45
#include "nsIPresShell.h"
 
46
#include "nsStyleContext.h"
 
47
#include "nsIScrollableView.h"
 
48
#include "nsLayoutAtoms.h"
 
49
#include "nsIDrawingSurface.h"
 
50
#include "nsTransform2D.h"
 
51
#include "nsIDeviceContext.h"
 
52
#include "nsIContent.h"
 
53
#include "nsHTMLAtoms.h"
 
54
#include "nsIDocument.h"
 
55
#include "nsIScrollableFrame.h"
 
56
#include "imgIRequest.h"
 
57
#include "imgIContainer.h"
 
58
#include "gfxIImageFrame.h"
 
59
#include "nsCSSRendering.h"
 
60
#include "nsCSSColorUtils.h"
 
61
#include "nsIPrintContext.h"
 
62
#include "nsITheme.h"
 
63
#include "nsThemeConstants.h"
 
64
#include "nsIServiceManager.h"
 
65
#include "nsIDOMHTMLBodyElement.h"
 
66
#include "nsIDOMHTMLDocument.h"
 
67
#include "nsLayoutUtils.h"
 
68
#include "nsINameSpaceManager.h"
 
69
 
 
70
#define BORDER_FULL    0        //entire side
 
71
#define BORDER_INSIDE  1        //inside half
 
72
#define BORDER_OUTSIDE 2        //outside half
 
73
 
 
74
//thickness of dashed line relative to dotted line
 
75
#define DOT_LENGTH  1           //square
 
76
#define DASH_LENGTH 3           //3 times longer than dot
 
77
 
 
78
 
 
79
/** The following classes are used by CSSRendering for the rounded rect implementation */
 
80
#define MAXPATHSIZE 12
 
81
#define MAXPOLYPATHSIZE 1000
 
82
 
 
83
enum ePathTypes{
 
84
  eOutside =0,
 
85
  eInside,
 
86
  eCalc,
 
87
  eCalcRev
 
88
};
 
89
 
 
90
// To avoid storing this data on nsInlineFrame (bloat) and to avoid
 
91
// recalculating this for each frame in a continuation (perf), hold
 
92
// a cache of various coordinate information that we need in order
 
93
// to paint inline backgrounds.
 
94
struct InlineBackgroundData
 
95
{
 
96
  InlineBackgroundData()
 
97
      : mFrame(nsnull)
 
98
  {
 
99
  }
 
100
 
 
101
  ~InlineBackgroundData()
 
102
  {
 
103
  }
 
104
 
 
105
  void Reset()
 
106
  {
 
107
    mBoundingBox.SetRect(0,0,0,0);
 
108
    mContinuationPoint = mUnbrokenWidth = 0;
 
109
    mFrame = nsnull;    
 
110
  }
 
111
 
 
112
  nsRect GetContinuousRect(nsIFrame* aFrame)
 
113
  {
 
114
    SetFrame(aFrame);
 
115
 
 
116
    // Assume background-origin: border and return a rect with offsets
 
117
    // relative to (0,0).  If we have a different background-origin,
 
118
    // then our rect should be deflated appropriately by our caller.
 
119
    return nsRect(-mContinuationPoint, 0, mUnbrokenWidth, mFrame->GetSize().height);
 
120
  }
 
121
 
 
122
  nsRect GetBoundingRect(nsIFrame* aFrame)
 
123
  {
 
124
    SetFrame(aFrame);
 
125
 
 
126
    // Move the offsets relative to (0,0) which puts the bounding box into
 
127
    // our coordinate system rather than our parent's.  We do this by
 
128
    // moving it the back distance from us to the bounding box.
 
129
    // This also assumes background-origin: border, so our caller will
 
130
    // need to deflate us if needed.
 
131
    nsRect boundingBox(mBoundingBox);
 
132
    nsPoint point = mFrame->GetPosition();
 
133
    boundingBox.MoveBy(-point.x, -point.y);
 
134
 
 
135
    return boundingBox;
 
136
  }
 
137
 
 
138
protected:
 
139
  nsIFrame*     mFrame;
 
140
  nscoord       mContinuationPoint;
 
141
  nscoord       mUnbrokenWidth;
 
142
  nsRect        mBoundingBox;
 
143
 
 
144
  void SetFrame(nsIFrame* aFrame)
 
145
  {
 
146
    NS_PRECONDITION(aFrame, "Need a frame");
 
147
 
 
148
    nsIFrame *prevInFlow = nsnull;
 
149
    aFrame->GetPrevInFlow(&prevInFlow);
 
150
 
 
151
    if (!prevInFlow || mFrame != prevInFlow) {
 
152
      // Ok, we've got the wrong frame.  We have to start from scratch.
 
153
      Reset();
 
154
      Init(aFrame);
 
155
      return;
 
156
    }
 
157
 
 
158
    // Get our last frame's size and add its width to our continuation
 
159
    // point before we cache the new frame.
 
160
    mContinuationPoint += mFrame->GetSize().width;
 
161
 
 
162
    mFrame = aFrame;
 
163
  }
 
164
 
 
165
  void Init(nsIFrame* aFrame)
 
166
  {
 
167
    nsIFrame* inlineFrame;
 
168
    // Start with the previous flow frame as our continuation point
 
169
    // is the total of the widths of the previous frames.
 
170
    aFrame->GetPrevInFlow(&inlineFrame);
 
171
 
 
172
    while (inlineFrame) {
 
173
      nsRect rect = inlineFrame->GetRect();
 
174
      mContinuationPoint += rect.width;
 
175
      mUnbrokenWidth += rect.width;
 
176
      mBoundingBox.UnionRect(mBoundingBox, rect);
 
177
      inlineFrame->GetPrevInFlow(&inlineFrame);
 
178
    }
 
179
 
 
180
    // Next add this frame and subsequent frames to the bounding box and
 
181
    // unbroken width.
 
182
    inlineFrame = aFrame;
 
183
    while (inlineFrame) {
 
184
      nsRect rect = inlineFrame->GetRect();
 
185
      mUnbrokenWidth += rect.width;
 
186
      mBoundingBox.UnionRect(mBoundingBox, rect);
 
187
      inlineFrame->GetNextInFlow(&inlineFrame);
 
188
    }
 
189
 
 
190
    mFrame = aFrame;
 
191
  }
 
192
};
 
193
 
 
194
static InlineBackgroundData gInlineBGData;
 
195
 
 
196
static void GetPath(nsFloatPoint aPoints[],nsPoint aPolyPath[],PRInt32 *aCurIndex,ePathTypes  aPathType,PRInt32 &aC1Index,float aFrac=0);
 
197
 
 
198
// FillRect or InvertRect depending on the renderingaInvert parameter
 
199
static void FillOrInvertRect(nsIRenderingContext& aRC,nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aInvert);
 
200
static void FillOrInvertRect(nsIRenderingContext& aRC,const nsRect& aRect, PRBool aInvert);
 
201
 
 
202
// Draw a line, skipping that portion which crosses aGap. aGap defines a rectangle gap
 
203
// This services fieldset legends and only works for coords defining horizontal lines.
 
204
void nsCSSRendering::DrawLine (nsIRenderingContext& aContext, 
 
205
                               nscoord aX1, nscoord aY1, nscoord aX2, nscoord aY2,
 
206
                               nsRect* aGap)
 
207
{
 
208
  if (nsnull == aGap) {
 
209
    aContext.DrawLine(aX1, aY1, aX2, aY2);
 
210
  } else {
 
211
    nscoord x1 = (aX1 < aX2) ? aX1 : aX2;
 
212
    nscoord x2 = (aX1 < aX2) ? aX2 : aX1;
 
213
    nsPoint gapUpperRight(aGap->x + aGap->width, aGap->y);
 
214
    nsPoint gapLowerRight(aGap->x + aGap->width, aGap->y + aGap->height);
 
215
    if ((aGap->y <= aY1) && (gapLowerRight.y >= aY2)) {
 
216
      if ((aGap->x > x1) && (aGap->x < x2)) {
 
217
        aContext.DrawLine(x1, aY1, aGap->x, aY1);
 
218
      } 
 
219
      if ((gapLowerRight.x > x1) && (gapLowerRight.x < x2)) {
 
220
        aContext.DrawLine(gapUpperRight.x, aY2, x2, aY2);
 
221
      } 
 
222
    } else {
 
223
      aContext.DrawLine(aX1, aY1, aX2, aY2);
 
224
    }
 
225
  }
 
226
}
 
227
 
 
228
// Fill a polygon, skipping that portion which crosses aGap. aGap defines a rectangle gap
 
229
// This services fieldset legends and only works for points defining a horizontal rectangle 
 
230
void nsCSSRendering::FillPolygon (nsIRenderingContext& aContext, 
 
231
                                  const nsPoint aPoints[],
 
232
                                  PRInt32 aNumPoints,
 
233
                                  nsRect* aGap)
 
234
{
 
235
#ifdef DEBUG
 
236
  nsPenMode penMode;
 
237
  if (NS_SUCCEEDED(aContext.GetPenMode(penMode)) &&
 
238
      penMode == nsPenMode_kInvert) {
 
239
    NS_WARNING( "Invert mode ignored in FillPolygon" );
 
240
  }
 
241
#endif
 
242
 
 
243
  if (nsnull == aGap) {
 
244
    aContext.FillPolygon(aPoints, aNumPoints);
 
245
  } else if (4 == aNumPoints) {
 
246
    nsPoint gapUpperRight(aGap->x + aGap->width, aGap->y);
 
247
    nsPoint gapLowerRight(aGap->x + aGap->width, aGap->y + aGap->height);
 
248
 
 
249
    // sort the 4 points by x
 
250
    nsPoint points[4];
 
251
    for (PRInt32 pX = 0; pX < 4; pX++) {
 
252
      points[pX] = aPoints[pX];
 
253
    }
 
254
    for (PRInt32 i = 0; i < 3; i++) {
 
255
      for (PRInt32 j = i+1; j < 4; j++) { 
 
256
        if (points[j].x < points[i].x) {
 
257
          nsPoint swap = points[i];
 
258
          points[i] = points[j];
 
259
          points[j] = swap;
 
260
        }
 
261
      }
 
262
    }
 
263
 
 
264
    nsPoint upperLeft  = (points[0].y <= points[1].y) ? points[0] : points[1];
 
265
    nsPoint lowerLeft  = (points[0].y <= points[1].y) ? points[1] : points[0];
 
266
    nsPoint upperRight = (points[2].y <= points[3].y) ? points[2] : points[3];
 
267
    nsPoint lowerRight = (points[2].y <= points[3].y) ? points[3] : points[2];
 
268
 
 
269
 
 
270
    if ((aGap->y <= upperLeft.y) && (gapLowerRight.y >= lowerRight.y)) {
 
271
      if ((aGap->x > upperLeft.x) && (aGap->x < upperRight.x)) {
 
272
        nsPoint leftRect[4];
 
273
        leftRect[0] = upperLeft;
 
274
        leftRect[1] = nsPoint(aGap->x, upperLeft.y);
 
275
        leftRect[2] = nsPoint(aGap->x, lowerLeft.y);
 
276
        leftRect[3] = lowerLeft;
 
277
        aContext.FillPolygon(leftRect, 4);
 
278
      } 
 
279
      if ((gapUpperRight.x > upperLeft.x) && (gapUpperRight.x < upperRight.x)) {
 
280
        nsPoint rightRect[4];
 
281
        rightRect[0] = nsPoint(gapUpperRight.x, upperRight.y);
 
282
        rightRect[1] = upperRight;
 
283
        rightRect[2] = lowerRight;
 
284
        rightRect[3] = nsPoint(gapLowerRight.x, lowerRight.y);
 
285
        aContext.FillPolygon(rightRect, 4);
 
286
      } 
 
287
    } else {
 
288
      aContext.FillPolygon(aPoints, aNumPoints);
 
289
    }      
 
290
  }
 
291
}
 
292
 
 
293
/**
 
294
 * Make a bevel color
 
295
 */
 
296
nscolor nsCSSRendering::MakeBevelColor(PRIntn whichSide, PRUint8 style,
 
297
                                       nscolor aBackgroundColor,
 
298
                                       nscolor aBorderColor,
 
299
                                       PRBool aSpecialCase)
 
300
{
 
301
 
 
302
  nscolor colors[2];
 
303
  nscolor theColor;
 
304
 
 
305
  // Given a background color and a border color
 
306
  // calculate the color used for the shading
 
307
  if(aSpecialCase)
 
308
    NS_GetSpecial3DColors(colors, aBackgroundColor, aBorderColor);
 
309
  else
 
310
    NS_Get3DColors(colors, aBackgroundColor);
 
311
 
 
312
  if ((style == NS_STYLE_BORDER_STYLE_BG_OUTSET) ||
 
313
      (style == NS_STYLE_BORDER_STYLE_OUTSET) ||
 
314
      (style == NS_STYLE_BORDER_STYLE_RIDGE)) {
 
315
    // Flip colors for these three border styles
 
316
    switch (whichSide) {
 
317
    case NS_SIDE_BOTTOM: whichSide = NS_SIDE_TOP;    break;
 
318
    case NS_SIDE_RIGHT:  whichSide = NS_SIDE_LEFT;   break;
 
319
    case NS_SIDE_TOP:    whichSide = NS_SIDE_BOTTOM; break;
 
320
    case NS_SIDE_LEFT:   whichSide = NS_SIDE_RIGHT;  break;
 
321
    }
 
322
  }
 
323
 
 
324
  switch (whichSide) {
 
325
  case NS_SIDE_BOTTOM:
 
326
    theColor = colors[1];
 
327
    break;
 
328
  case NS_SIDE_RIGHT:
 
329
    theColor = colors[1];
 
330
    break;
 
331
  case NS_SIDE_TOP:
 
332
    theColor = colors[0];
 
333
    break;
 
334
  case NS_SIDE_LEFT:
 
335
  default:
 
336
    theColor = colors[0];
 
337
    break;
 
338
  }
 
339
  return theColor;
 
340
}
 
341
 
 
342
// Maximum poly points in any of the polygons we generate below
 
343
#define MAX_POLY_POINTS 4
 
344
 
 
345
// a nifty helper function to create a polygon representing a
 
346
// particular side of a border. This helps localize code for figuring
 
347
// mitered edges. It is mainly used by the solid, inset, and outset
 
348
// styles.
 
349
//
 
350
// If the side can be represented as a line segment (because the thickness
 
351
// is one pixel), then a line with two endpoints is returned
 
352
PRIntn nsCSSRendering::MakeSide(nsPoint aPoints[],
 
353
                                nsIRenderingContext& aContext,
 
354
                                PRIntn whichSide,
 
355
                                const nsRect& outside, const nsRect& inside,
 
356
                                PRIntn aSkipSides,
 
357
                                PRIntn borderPart, float borderFrac,
 
358
                                nscoord twipsPerPixel)
 
359
{
 
360
  float borderRest = 1.0f - borderFrac;
 
361
 
 
362
  PRIntn np = 0;
 
363
  nscoord thickness, outsideEdge, insideEdge, outsideTL, insideTL, outsideBR,
 
364
    insideBR;
 
365
 
 
366
  // Initialize the following six nscoord's:
 
367
  // outsideEdge, insideEdge, outsideTL, insideTL, outsideBR, insideBR
 
368
  // so that outsideEdge is the x or y of the outside edge, etc., and
 
369
  // outsideTR is the y or x at the top or right end, etc., e.g.:
 
370
  //
 
371
  // outsideEdge ---  ----------------------------------------
 
372
  //                  \                                      /
 
373
  //                   \                                    /
 
374
  //                    \                                  /
 
375
  // insideEdge -------  ----------------------------------
 
376
  //                 |   |                                |   |
 
377
  //         outsideTL   insideTL                  insideBR   outsideBR       
 
378
  //
 
379
  // if we don't want the bevel, we'll get rid of it later by setting
 
380
  // outsideXX to insideXX
 
381
 
 
382
  switch (whichSide) {
 
383
  case NS_SIDE_TOP:
 
384
    // the TL points are the left end; the BR points are the right end
 
385
    outsideEdge = outside.y;
 
386
    insideEdge = inside.y;
 
387
    outsideTL = outside.x;
 
388
    insideTL = inside.x;
 
389
    insideBR = inside.XMost();
 
390
    outsideBR = outside.XMost();
 
391
    break;
 
392
 
 
393
  case NS_SIDE_BOTTOM:
 
394
    // the TL points are the left end; the BR points are the right end
 
395
    outsideEdge = outside.YMost();
 
396
    insideEdge = inside.YMost();
 
397
    outsideTL = outside.x;
 
398
    insideTL = inside.x;
 
399
    insideBR = inside.XMost();
 
400
    outsideBR = outside.XMost();
 
401
    break;
 
402
 
 
403
  case NS_SIDE_LEFT:
 
404
    // the TL points are the top end; the BR points are the bottom end
 
405
    outsideEdge = outside.x;
 
406
    insideEdge = inside.x;
 
407
    outsideTL = outside.y;
 
408
    insideTL = inside.y;
 
409
    insideBR = inside.YMost();
 
410
    outsideBR = outside.YMost();
 
411
    break;
 
412
 
 
413
  case NS_SIDE_RIGHT:
 
414
    // the TL points are the top end; the BR points are the bottom end
 
415
    outsideEdge = outside.XMost();
 
416
    insideEdge = inside.XMost();
 
417
    outsideTL = outside.y;
 
418
    insideTL = inside.y;
 
419
    insideBR = inside.YMost();
 
420
    outsideBR = outside.YMost();
 
421
    break;
 
422
  }
 
423
 
 
424
  // Don't draw the bevels if an adjacent side is skipped
 
425
 
 
426
  if ( (whichSide == NS_SIDE_TOP) || (whichSide == NS_SIDE_BOTTOM) ) {
 
427
    // a top or bottom side
 
428
    if ((1<<NS_SIDE_LEFT) & aSkipSides) {
 
429
      insideTL = outsideTL;
 
430
    }
 
431
    if ((1<<NS_SIDE_RIGHT) & aSkipSides) {
 
432
      insideBR = outsideBR;
 
433
    }
 
434
  } else {
 
435
    // a right or left side
 
436
    if ((1<<NS_SIDE_TOP) & aSkipSides) {
 
437
      insideTL = outsideTL;
 
438
    }
 
439
    if ((1<<NS_SIDE_BOTTOM) & aSkipSides) {
 
440
      insideBR = outsideBR;
 
441
    }
 
442
  }
 
443
 
 
444
  // move things around when only drawing part of the border
 
445
 
 
446
  if (borderPart == BORDER_INSIDE) {
 
447
    outsideEdge = nscoord(outsideEdge * borderFrac + insideEdge * borderRest);
 
448
    outsideTL = nscoord(outsideTL * borderFrac + insideTL * borderRest);
 
449
    outsideBR = nscoord(outsideBR * borderFrac + insideBR * borderRest);
 
450
  } else if (borderPart == BORDER_OUTSIDE ) {
 
451
    insideEdge = nscoord(insideEdge * borderFrac + outsideEdge * borderRest);
 
452
    insideTL = nscoord(insideTL * borderFrac + outsideTL * borderRest);
 
453
    insideBR = nscoord(insideBR * borderFrac + outsideBR * borderRest);
 
454
  }
 
455
 
 
456
  // Base our thickness check on the segment being less than a pixel and 1/2
 
457
  twipsPerPixel += twipsPerPixel >> 2;
 
458
 
 
459
  // find the thickness of the piece being drawn
 
460
  if ((whichSide == NS_SIDE_TOP) || (whichSide == NS_SIDE_LEFT)) {
 
461
    thickness = insideEdge - outsideEdge;
 
462
  } else {
 
463
    thickness = outsideEdge - insideEdge;
 
464
  }
 
465
 
 
466
  // if returning a line, do it along inside edge for bottom or right borders
 
467
  // so that it's in the same place as it would be with polygons (why?)
 
468
  // XXX The previous version of the code shortened the right border too.
 
469
  if ( !((thickness >= twipsPerPixel) || (borderPart != BORDER_FULL)) &&
 
470
       ((whichSide == NS_SIDE_BOTTOM) || (whichSide == NS_SIDE_RIGHT))) {
 
471
    outsideEdge = insideEdge;
 
472
    }
 
473
 
 
474
  // return the appropriate line or trapezoid
 
475
  if ((whichSide == NS_SIDE_TOP) || (whichSide == NS_SIDE_BOTTOM)) {
 
476
    // top and bottom borders
 
477
    aPoints[np++].MoveTo(outsideTL,outsideEdge);
 
478
    aPoints[np++].MoveTo(outsideBR,outsideEdge);
 
479
    // XXX Making this condition only (thickness >= twipsPerPixel) will
 
480
    // improve double borders and some cases of groove/ridge,
 
481
    //  but will cause problems with table borders.  See last and third
 
482
    // from last tests in test4.htm
 
483
    // Doing it this way emulates the old behavior.  It might be worth
 
484
    // fixing.
 
485
    if ((thickness >= twipsPerPixel) || (borderPart != BORDER_FULL) ) {
 
486
      aPoints[np++].MoveTo(insideBR,insideEdge);
 
487
      aPoints[np++].MoveTo(insideTL,insideEdge);
 
488
    }
 
489
  } else {
 
490
    // right and left borders
 
491
    // XXX Ditto above
 
492
    if ((thickness >= twipsPerPixel) || (borderPart != BORDER_FULL) )  {
 
493
      aPoints[np++].MoveTo(insideEdge,insideBR);
 
494
      aPoints[np++].MoveTo(insideEdge,insideTL);
 
495
    }
 
496
    aPoints[np++].MoveTo(outsideEdge,outsideTL);
 
497
    aPoints[np++].MoveTo(outsideEdge,outsideBR);
 
498
  }
 
499
  return np;
 
500
}
 
501
 
 
502
void nsCSSRendering::DrawSide(nsIRenderingContext& aContext,
 
503
                              PRIntn whichSide,
 
504
                              const PRUint8 borderStyle,  
 
505
                              const nscolor borderColor,
 
506
                              const nscolor aBackgroundColor,
 
507
                              const nsRect& borderOutside,
 
508
                              const nsRect& borderInside,
 
509
                              PRIntn aSkipSides,
 
510
                              nscoord twipsPerPixel,
 
511
                              nsRect* aGap)
 
512
{
 
513
  nsPoint theSide[MAX_POLY_POINTS];
 
514
  nscolor theColor = borderColor; 
 
515
  PRUint8 theStyle = borderStyle; 
 
516
  PRInt32 np;
 
517
  switch (theStyle) {
 
518
  case NS_STYLE_BORDER_STYLE_NONE:
 
519
  case NS_STYLE_BORDER_STYLE_HIDDEN:
 
520
    return;
 
521
 
 
522
  case NS_STYLE_BORDER_STYLE_DOTTED:    //handled a special case elsewhere
 
523
  case NS_STYLE_BORDER_STYLE_DASHED:    //handled a special case elsewhere
 
524
    break; // That was easy...
 
525
 
 
526
  case NS_STYLE_BORDER_STYLE_GROOVE:
 
527
  case NS_STYLE_BORDER_STYLE_RIDGE:
 
528
    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, aSkipSides,
 
529
                   BORDER_INSIDE, 0.5f, twipsPerPixel);
 
530
    aContext.SetColor ( MakeBevelColor (whichSide, 
 
531
                                        ((theStyle == NS_STYLE_BORDER_STYLE_RIDGE) ?
 
532
                                         NS_STYLE_BORDER_STYLE_GROOVE :
 
533
                                         NS_STYLE_BORDER_STYLE_RIDGE), 
 
534
                                         aBackgroundColor, theColor, 
 
535
                                         PR_TRUE));
 
536
    if (2 == np) {
 
537
      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
 
538
      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
 
539
    } else {
 
540
      //aContext.FillPolygon (theSide, np);
 
541
      FillPolygon (aContext, theSide, np, aGap);
 
542
    }
 
543
    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
 
544
                   BORDER_OUTSIDE, 0.5f, twipsPerPixel);
 
545
    aContext.SetColor ( MakeBevelColor (whichSide, theStyle, aBackgroundColor, 
 
546
                                        theColor, PR_TRUE));
 
547
    if (2 == np) {
 
548
      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
 
549
      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
 
550
    } else {
 
551
      //aContext.FillPolygon (theSide, np);
 
552
      FillPolygon (aContext, theSide, np, aGap);
 
553
    }
 
554
    break;
 
555
 
 
556
  case NS_STYLE_BORDER_STYLE_SOLID:
 
557
    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
 
558
                   BORDER_FULL, 1.0f, twipsPerPixel);
 
559
    aContext.SetColor (borderColor);  
 
560
    if (2 == np) {
 
561
      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
 
562
      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
 
563
    } else {
 
564
      //aContext.FillPolygon (theSide, np);
 
565
      FillPolygon (aContext, theSide, np, aGap);
 
566
    }
 
567
    break;
 
568
 
 
569
  case NS_STYLE_BORDER_STYLE_BG_SOLID:
 
570
    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, aSkipSides,
 
571
                   BORDER_FULL, 1.0f, twipsPerPixel);
 
572
    nscolor colors[2]; 
 
573
    NS_Get3DColors(colors, aBackgroundColor); 
 
574
    aContext.SetColor (colors[0]);
 
575
    if (2 == np) {
 
576
      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
 
577
    } else {
 
578
      FillPolygon (aContext, theSide, np, aGap);
 
579
    }
 
580
    break;
 
581
 
 
582
  case NS_STYLE_BORDER_STYLE_DOUBLE:
 
583
    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
 
584
                   BORDER_INSIDE, 0.333333f, twipsPerPixel);
 
585
    aContext.SetColor (borderColor);
 
586
    if (2 == np) {
 
587
      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
 
588
      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
 
589
    } else {
 
590
      //aContext.FillPolygon (theSide, np);
 
591
      FillPolygon (aContext, theSide, np, aGap);
 
592
   }
 
593
    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
 
594
                   BORDER_OUTSIDE, 0.333333f, twipsPerPixel);
 
595
    if (2 == np) {
 
596
      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
 
597
      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
 
598
    } else {
 
599
      //aContext.FillPolygon (theSide, np);
 
600
      FillPolygon (aContext, theSide, np, aGap);
 
601
    }
 
602
    break;
 
603
 
 
604
  case NS_STYLE_BORDER_STYLE_BG_OUTSET:
 
605
  case NS_STYLE_BORDER_STYLE_BG_INSET:
 
606
    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
 
607
                   BORDER_FULL, 1.0f, twipsPerPixel);
 
608
    aContext.SetColor ( MakeBevelColor (whichSide, theStyle, aBackgroundColor,
 
609
                                        theColor, PR_FALSE));
 
610
    if (2 == np) {
 
611
      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
 
612
      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
 
613
    } else {
 
614
      //aContext.FillPolygon (theSide, np);
 
615
      FillPolygon (aContext, theSide, np, aGap);
 
616
    }
 
617
    break;
 
618
  case NS_STYLE_BORDER_STYLE_OUTSET:
 
619
  case NS_STYLE_BORDER_STYLE_INSET:
 
620
    np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
 
621
                   BORDER_FULL, 1.0f, twipsPerPixel);
 
622
    aContext.SetColor ( MakeBevelColor (whichSide, theStyle, aBackgroundColor, 
 
623
                                        theColor, PR_TRUE));
 
624
    if (2 == np) {
 
625
      //aContext.DrawLine (theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y);
 
626
      DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
 
627
    } else {
 
628
      //aContext.FillPolygon (theSide, np);
 
629
      FillPolygon (aContext, theSide, np, aGap);
 
630
    }
 
631
    break;
 
632
  }
 
633
}
 
634
 
 
635
 
 
636
/**
 
637
 * Draw a dotted/dashed sides of a box
 
638
 */
 
639
//XXX dashes which span more than two edges are not handled properly MMP
 
640
void nsCSSRendering::DrawDashedSides(PRIntn startSide,
 
641
                                     nsIRenderingContext& aContext,
 
642
                   /* XXX unused */  const nsRect& aDirtyRect,
 
643
                                     const PRUint8 borderStyles[],  
 
644
                                     const nscolor borderColors[],  
 
645
                                     const nsRect& borderOutside,
 
646
                                     const nsRect& borderInside,
 
647
                                     PRIntn aSkipSides,
 
648
                   /* XXX unused */  nsRect* aGap)
 
649
{
 
650
PRIntn  dashLength;
 
651
nsRect  dashRect, firstRect, currRect;
 
652
PRBool  bSolid = PR_TRUE;
 
653
float   over = 0.0f;
 
654
PRUint8 style = borderStyles[startSide];  
 
655
PRBool  skippedSide = PR_FALSE;
 
656
 
 
657
  for (PRIntn whichSide = startSide; whichSide < 4; whichSide++) {
 
658
    PRUint8 prevStyle = style;
 
659
    style = borderStyles[whichSide];  
 
660
    if ((1<<whichSide) & aSkipSides) {
 
661
      // Skipped side
 
662
      skippedSide = PR_TRUE;
 
663
      continue;
 
664
    }
 
665
    if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
 
666
        (style == NS_STYLE_BORDER_STYLE_DOTTED))
 
667
    {
 
668
      if ((style != prevStyle) || skippedSide) {
 
669
        //style discontinuity
 
670
        over = 0.0f;
 
671
        bSolid = PR_TRUE;
 
672
      }
 
673
 
 
674
      // XXX units for dash & dot?
 
675
      if (style == NS_STYLE_BORDER_STYLE_DASHED) {
 
676
        dashLength = DASH_LENGTH;
 
677
      } else {
 
678
        dashLength = DOT_LENGTH;
 
679
      }
 
680
 
 
681
      aContext.SetColor(borderColors[whichSide]);  
 
682
      switch (whichSide) {
 
683
      case NS_SIDE_LEFT:
 
684
        //XXX need to properly handle wrap around from last edge to first edge
 
685
        //(this is the first edge) MMP
 
686
        dashRect.width = borderInside.x - borderOutside.x;
 
687
        dashRect.height = nscoord(dashRect.width * dashLength);
 
688
        dashRect.x = borderOutside.x;
 
689
        dashRect.y = borderInside.YMost() - dashRect.height;
 
690
 
 
691
        if (over > 0.0f) {
 
692
          firstRect.x = dashRect.x;
 
693
          firstRect.width = dashRect.width;
 
694
          firstRect.height = nscoord(dashRect.height * over);
 
695
          firstRect.y = dashRect.y + (dashRect.height - firstRect.height);
 
696
          over = 0.0f;
 
697
          currRect = firstRect;
 
698
        } else {
 
699
          currRect = dashRect;
 
700
        }
 
701
 
 
702
        while (currRect.YMost() > borderInside.y) {
 
703
          //clip if necessary
 
704
          if (currRect.y < borderInside.y) {
 
705
            over = float(borderInside.y - dashRect.y) /
 
706
              float(dashRect.height);
 
707
            currRect.height = currRect.height - (borderInside.y - currRect.y);
 
708
            currRect.y = borderInside.y;
 
709
          }
 
710
 
 
711
          //draw if necessary
 
712
          if (bSolid) {
 
713
            aContext.FillRect(currRect);
 
714
          }
 
715
 
 
716
          //setup for next iteration
 
717
          if (over == 0.0f) {
 
718
            bSolid = PRBool(!bSolid);
 
719
          }
 
720
          dashRect.y = dashRect.y - currRect.height;
 
721
          currRect = dashRect;
 
722
        }
 
723
        break;
 
724
 
 
725
      case NS_SIDE_TOP:
 
726
        //if we are continuing a solid rect, fill in the corner first
 
727
        if (bSolid) {
 
728
          aContext.FillRect(borderOutside.x, borderOutside.y,
 
729
                            borderInside.x - borderOutside.x,
 
730
                            borderInside.y - borderOutside.y);
 
731
        }
 
732
 
 
733
        dashRect.height = borderInside.y - borderOutside.y;
 
734
        dashRect.width = dashRect.height * dashLength;
 
735
        dashRect.x = borderInside.x;
 
736
        dashRect.y = borderOutside.y;
 
737
 
 
738
        if (over > 0.0f) {
 
739
          firstRect.x = dashRect.x;
 
740
          firstRect.y = dashRect.y;
 
741
          firstRect.width = nscoord(dashRect.width * over);
 
742
          firstRect.height = dashRect.height;
 
743
          over = 0.0f;
 
744
          currRect = firstRect;
 
745
        } else {
 
746
          currRect = dashRect;
 
747
        }
 
748
 
 
749
        while (currRect.x < borderInside.XMost()) {
 
750
          //clip if necessary
 
751
          if (currRect.XMost() > borderInside.XMost()) {
 
752
            over = float(dashRect.XMost() - borderInside.XMost()) /
 
753
              float(dashRect.width);
 
754
            currRect.width = currRect.width -
 
755
              (currRect.XMost() - borderInside.XMost());
 
756
          }
 
757
 
 
758
          //draw if necessary
 
759
          if (bSolid) {
 
760
            aContext.FillRect(currRect);
 
761
          }
 
762
 
 
763
          //setup for next iteration
 
764
          if (over == 0.0f) {
 
765
            bSolid = PRBool(!bSolid);
 
766
          }
 
767
          dashRect.x = dashRect.x + currRect.width;
 
768
          currRect = dashRect;
 
769
        }
 
770
        break;
 
771
 
 
772
      case NS_SIDE_RIGHT:
 
773
        //if we are continuing a solid rect, fill in the corner first
 
774
        if (bSolid) {
 
775
          aContext.FillRect(borderInside.XMost(), borderOutside.y,
 
776
                            borderOutside.XMost() - borderInside.XMost(),
 
777
                            borderInside.y - borderOutside.y);
 
778
        }
 
779
 
 
780
        dashRect.width = borderOutside.XMost() - borderInside.XMost();
 
781
        dashRect.height = nscoord(dashRect.width * dashLength);
 
782
        dashRect.x = borderInside.XMost();
 
783
        dashRect.y = borderInside.y;
 
784
 
 
785
        if (over > 0.0f) {
 
786
          firstRect.x = dashRect.x;
 
787
          firstRect.y = dashRect.y;
 
788
          firstRect.width = dashRect.width;
 
789
          firstRect.height = nscoord(dashRect.height * over);
 
790
          over = 0.0f;
 
791
          currRect = firstRect;
 
792
        } else {
 
793
          currRect = dashRect;
 
794
        }
 
795
 
 
796
        while (currRect.y < borderInside.YMost()) {
 
797
          //clip if necessary
 
798
          if (currRect.YMost() > borderInside.YMost()) {
 
799
            over = float(dashRect.YMost() - borderInside.YMost()) /
 
800
              float(dashRect.height);
 
801
            currRect.height = currRect.height -
 
802
              (currRect.YMost() - borderInside.YMost());
 
803
          }
 
804
 
 
805
          //draw if necessary
 
806
          if (bSolid) {
 
807
            aContext.FillRect(currRect);
 
808
          }
 
809
 
 
810
          //setup for next iteration
 
811
          if (over == 0.0f) {
 
812
            bSolid = PRBool(!bSolid);
 
813
          }
 
814
          dashRect.y = dashRect.y + currRect.height;
 
815
          currRect = dashRect;
 
816
        }
 
817
        break;
 
818
 
 
819
      case NS_SIDE_BOTTOM:
 
820
        //if we are continuing a solid rect, fill in the corner first
 
821
        if (bSolid) {
 
822
          aContext.FillRect(borderInside.XMost(), borderInside.YMost(),
 
823
                            borderOutside.XMost() - borderInside.XMost(),
 
824
                            borderOutside.YMost() - borderInside.YMost());
 
825
        }
 
826
 
 
827
        dashRect.height = borderOutside.YMost() - borderInside.YMost();
 
828
        dashRect.width = nscoord(dashRect.height * dashLength);
 
829
        dashRect.x = borderInside.XMost() - dashRect.width;
 
830
        dashRect.y = borderInside.YMost();
 
831
 
 
832
        if (over > 0.0f) {
 
833
          firstRect.y = dashRect.y;
 
834
          firstRect.width = nscoord(dashRect.width * over);
 
835
          firstRect.height = dashRect.height;
 
836
          firstRect.x = dashRect.x + (dashRect.width - firstRect.width);
 
837
          over = 0.0f;
 
838
          currRect = firstRect;
 
839
        } else {
 
840
          currRect = dashRect;
 
841
        }
 
842
 
 
843
        while (currRect.XMost() > borderInside.x) {
 
844
          //clip if necessary
 
845
          if (currRect.x < borderInside.x) {
 
846
            over = float(borderInside.x - dashRect.x) / float(dashRect.width);
 
847
            currRect.width = currRect.width - (borderInside.x - currRect.x);
 
848
            currRect.x = borderInside.x;
 
849
          }
 
850
 
 
851
          //draw if necessary
 
852
          if (bSolid) {
 
853
            aContext.FillRect(currRect);
 
854
          }
 
855
 
 
856
          //setup for next iteration
 
857
          if (over == 0.0f) {
 
858
            bSolid = PRBool(!bSolid);
 
859
          }
 
860
          dashRect.x = dashRect.x - currRect.width;
 
861
          currRect = dashRect;
 
862
        }
 
863
        break;
 
864
      }
 
865
    }
 
866
    skippedSide = PR_FALSE;
 
867
  }
 
868
}
 
869
 
 
870
/** ---------------------------------------------------
 
871
 *  See documentation in nsCSSRendering.h
 
872
 *  @update 10/22/99 dwc
 
873
 */
 
874
void nsCSSRendering::DrawDashedSides(PRIntn startSide,
 
875
                                     nsIRenderingContext& aContext,
 
876
                                     const nsRect& aDirtyRect,
 
877
                                     const nsStyleColor* aColorStyle,
 
878
                                     const nsStyleBorder* aBorderStyle,  
 
879
                                     const nsStyleOutline* aOutlineStyle,  
 
880
                                     PRBool aDoOutline,
 
881
                                     const nsRect& borderOutside,
 
882
                                     const nsRect& borderInside,
 
883
                                     PRIntn aSkipSides,
 
884
                   /* XXX unused */  nsRect* aGap)
 
885
{
 
886
 
 
887
PRIntn  dashLength;
 
888
nsRect  dashRect, currRect;
 
889
nscoord temp, temp1, adjust;
 
890
PRBool  bSolid = PR_TRUE;
 
891
float   over = 0.0f;
 
892
PRBool  skippedSide = PR_FALSE;
 
893
const nscolor kBlackColor = NS_RGB(0,0,0);
 
894
 
 
895
  NS_ASSERTION((aDoOutline && aOutlineStyle) || (!aDoOutline && aBorderStyle), "null params not allowed");
 
896
  PRUint8 style = aDoOutline
 
897
                  ? aOutlineStyle->GetOutlineStyle()
 
898
                  : aBorderStyle->GetBorderStyle(startSide);  
 
899
 
 
900
  // find the x and y width
 
901
  nscoord xwidth = aDirtyRect.XMost();
 
902
  nscoord ywidth = aDirtyRect.YMost();
 
903
 
 
904
  for (PRIntn whichSide = startSide; whichSide < 4; whichSide++) {
 
905
    PRUint8 prevStyle = style;
 
906
    style = aDoOutline
 
907
              ? aOutlineStyle->GetOutlineStyle()
 
908
              : aBorderStyle->GetBorderStyle(whichSide);  
 
909
    if ((1<<whichSide) & aSkipSides) {
 
910
      // Skipped side
 
911
      skippedSide = PR_TRUE;
 
912
      continue;
 
913
    }
 
914
    if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
 
915
        (style == NS_STYLE_BORDER_STYLE_DOTTED))
 
916
    {
 
917
      if ((style != prevStyle) || skippedSide) {
 
918
        //style discontinuity
 
919
        over = 0.0f;
 
920
        bSolid = PR_TRUE;
 
921
      }
 
922
 
 
923
      if (style == NS_STYLE_BORDER_STYLE_DASHED) {
 
924
        dashLength = DASH_LENGTH;
 
925
      } else {
 
926
        dashLength = DOT_LENGTH;
 
927
      }
 
928
 
 
929
      nscolor sideColor(kBlackColor); // default to black in case color cannot be resolved
 
930
                                      // (because invert is not supported on cur platform)
 
931
      PRBool  isInvert=PR_FALSE;
 
932
      if (aDoOutline) {
 
933
        // see if the outline color is 'invert'
 
934
        if (aOutlineStyle->GetOutlineInvert()) { 
 
935
          isInvert = PR_TRUE;
 
936
        } else {
 
937
          aOutlineStyle->GetOutlineColor(sideColor);
 
938
        }
 
939
      } else {
 
940
        PRBool transparent; 
 
941
        PRBool foreground;
 
942
        aBorderStyle->GetBorderColor(whichSide, sideColor, transparent, foreground);
 
943
        if (foreground)
 
944
          sideColor = aColorStyle->mColor;
 
945
        if (transparent)
 
946
          continue; // side is transparent
 
947
      }
 
948
      aContext.SetColor(sideColor);  
 
949
 
 
950
      switch (whichSide) {
 
951
      case NS_SIDE_RIGHT:
 
952
      case NS_SIDE_LEFT:
 
953
        bSolid = PR_FALSE;
 
954
        
 
955
        // This is our dot or dash..
 
956
        if(whichSide==NS_SIDE_LEFT){ 
 
957
          dashRect.width = borderInside.x - borderOutside.x;
 
958
        } else {
 
959
          dashRect.width = borderOutside.XMost() - borderInside.XMost();
 
960
        }
 
961
        if( dashRect.width >0 ) {
 
962
          dashRect.height = dashRect.width * dashLength;
 
963
          dashRect.y = borderOutside.y;
 
964
 
 
965
          if(whichSide == NS_SIDE_RIGHT){
 
966
            dashRect.x = borderInside.XMost();
 
967
          } else {
 
968
            dashRect.x = borderOutside.x;
 
969
          }
 
970
 
 
971
          temp = borderOutside.YMost();
 
972
          temp1 = temp/dashRect.height;
 
973
 
 
974
          currRect = dashRect;
 
975
 
 
976
          if((temp1%2)==0){
 
977
            adjust = (dashRect.height-(temp%dashRect.height))/2; // adjust back
 
978
            // draw in the left and right
 
979
            FillOrInvertRect(aContext,  dashRect.x, borderOutside.y,dashRect.width, dashRect.height-adjust,isInvert);
 
980
            FillOrInvertRect(aContext,dashRect.x,(borderOutside.YMost()-(dashRect.height-adjust)),dashRect.width, dashRect.height-adjust,isInvert);
 
981
            currRect.y += (dashRect.height-adjust);
 
982
            temp = temp-= (dashRect.height-adjust);
 
983
          } else {
 
984
            adjust = (temp%dashRect.width)/2;                   // adjust a tad longer
 
985
            // draw in the left and right
 
986
            FillOrInvertRect(aContext, dashRect.x, borderOutside.y,dashRect.width, dashRect.height+adjust,isInvert);
 
987
            FillOrInvertRect(aContext, dashRect.x,(borderOutside.YMost()-(dashRect.height+adjust)),dashRect.width, dashRect.height+adjust,isInvert);
 
988
            currRect.y += (dashRect.height+adjust);
 
989
            temp = temp-= (dashRect.height+adjust);
 
990
          }
 
991
        
 
992
          if( temp > ywidth)
 
993
            temp = ywidth;
 
994
 
 
995
          // get the currRect's x into the view before we start
 
996
          if( currRect.y < aDirtyRect.y){
 
997
            temp1 = NSToCoordFloor((float)((aDirtyRect.y-currRect.y)/dashRect.height));
 
998
            currRect.y += temp1*dashRect.height;
 
999
            if((temp1%2)==1){
 
1000
              bSolid = PR_TRUE;
 
1001
            }
 
1002
         }
 
1003
 
 
1004
          while(currRect.y<temp) {
 
1005
            //draw if necessary
 
1006
            if (bSolid) {
 
1007
              FillOrInvertRect(aContext, currRect,isInvert);
 
1008
            }
 
1009
 
 
1010
            bSolid = PRBool(!bSolid);
 
1011
            currRect.y += dashRect.height;
 
1012
          }
 
1013
        }
 
1014
        break;
 
1015
 
 
1016
      case NS_SIDE_BOTTOM:
 
1017
      case NS_SIDE_TOP:
 
1018
        bSolid = PR_FALSE;
 
1019
        
 
1020
        // This is our dot or dash..
 
1021
 
 
1022
        if(whichSide==NS_SIDE_TOP){ 
 
1023
          dashRect.height = borderInside.y - borderOutside.y;
 
1024
        } else {
 
1025
          dashRect.height = borderOutside.YMost() - borderInside.YMost();
 
1026
        }
 
1027
        if( dashRect.height >0 ) {
 
1028
          dashRect.width = dashRect.height * dashLength;
 
1029
          dashRect.x = borderOutside.x;
 
1030
 
 
1031
          if(whichSide == NS_SIDE_BOTTOM){
 
1032
            dashRect.y = borderInside.YMost();
 
1033
          } else {
 
1034
            dashRect.y = borderOutside.y;
 
1035
          }
 
1036
 
 
1037
          temp = borderOutside.XMost();
 
1038
          temp1 = temp/dashRect.width;
 
1039
 
 
1040
          currRect = dashRect;
 
1041
 
 
1042
          if((temp1%2)==0){
 
1043
            adjust = (dashRect.width-(temp%dashRect.width))/2;     // even, adjust back
 
1044
            // draw in the left and right
 
1045
            FillOrInvertRect(aContext, borderOutside.x,dashRect.y,dashRect.width-adjust,dashRect.height,isInvert);
 
1046
            FillOrInvertRect(aContext, (borderOutside.XMost()-(dashRect.width-adjust)),dashRect.y,dashRect.width-adjust,dashRect.height,isInvert);
 
1047
            currRect.x += (dashRect.width-adjust);
 
1048
            temp = temp-= (dashRect.width-adjust);
 
1049
          } else {
 
1050
            adjust = (temp%dashRect.width)/2;
 
1051
            // draw in the left and right
 
1052
            FillOrInvertRect(aContext, borderOutside.x,dashRect.y,dashRect.width+adjust,dashRect.height,isInvert);
 
1053
            FillOrInvertRect(aContext, (borderOutside.XMost()-(dashRect.width+adjust)),dashRect.y,dashRect.width+adjust,dashRect.height,isInvert);
 
1054
            currRect.x += (dashRect.width+adjust);
 
1055
            temp = temp-= (dashRect.width+adjust);
 
1056
          }
 
1057
       
 
1058
 
 
1059
          if( temp > xwidth)
 
1060
            temp = xwidth;
 
1061
 
 
1062
          // get the currRect's x into the view before we start
 
1063
          if( currRect.x < aDirtyRect.x){
 
1064
            temp1 = NSToCoordFloor((float)((aDirtyRect.x-currRect.x)/dashRect.width));
 
1065
            currRect.x += temp1*dashRect.width;
 
1066
            if((temp1%2)==1){
 
1067
              bSolid = PR_TRUE;
 
1068
            }
 
1069
          }
 
1070
 
 
1071
          while(currRect.x<temp) {
 
1072
            //draw if necessary
 
1073
            if (bSolid) {
 
1074
              FillOrInvertRect(aContext, currRect,isInvert);
 
1075
            }
 
1076
 
 
1077
            bSolid = PRBool(!bSolid);
 
1078
            currRect.x += dashRect.width;
 
1079
          }
 
1080
        }
 
1081
      break;
 
1082
      }
 
1083
    }
 
1084
    skippedSide = PR_FALSE;
 
1085
  }
 
1086
}
 
1087
 
 
1088
/* draw the portions of the border described in aBorderEdges that are dashed.
 
1089
 * a border has 4 edges.  Each edge has 1 or more segments. 
 
1090
 * "inside edges" are drawn differently than "outside edges" so the shared edges will match up.
 
1091
 * in the case of table collapsing borders, the table edge is the "outside" edge and
 
1092
 * cell edges are always "inside" edges (so adjacent cells have 2 shared "inside" edges.)
 
1093
 * There is a case for each of the four sides.  Only the left side is well documented.  The others
 
1094
 * are very similar.
 
1095
 */
 
1096
// XXX: doesn't do corners or junctions well at all.  Just uses logic stolen 
 
1097
//      from DrawDashedSides which is insufficient
 
1098
void nsCSSRendering::DrawDashedSegments(nsIRenderingContext& aContext,
 
1099
                                        const nsRect& aBounds,
 
1100
                                        nsBorderEdges * aBorderEdges,
 
1101
                                        PRIntn aSkipSides,
 
1102
                      /* XXX unused */  nsRect* aGap)
 
1103
{
 
1104
PRIntn dashLength;
 
1105
nsRect dashRect, currRect;
 
1106
 
 
1107
PRBool  bSolid = PR_TRUE;
 
1108
float   over = 0.0f;
 
1109
PRBool  skippedSide = PR_FALSE;
 
1110
PRIntn  whichSide=0;
 
1111
 
 
1112
 
 
1113
  // do this just to set up initial condition for loop
 
1114
  // "segment" is the current portion of the edge we are computing
 
1115
  nsBorderEdge * segment =  (nsBorderEdge *)(aBorderEdges->mEdges[whichSide].ElementAt(0));
 
1116
  PRUint8 style = segment->mStyle;  
 
1117
  for ( ; whichSide < 4; whichSide++) 
 
1118
  {
 
1119
    if ((1<<whichSide) & aSkipSides) {
 
1120
      // Skipped side
 
1121
      skippedSide = PR_TRUE;
 
1122
      continue;
 
1123
    }
 
1124
    nscoord x=0;  nscoord y=0;
 
1125
    PRInt32 i;
 
1126
    PRInt32 segmentCount = aBorderEdges->mEdges[whichSide].Count();
 
1127
    nsBorderEdges * neighborBorderEdges=nsnull;
 
1128
    PRIntn neighborEdgeCount=0; // keeps track of which inside neighbor is shared with an outside segment
 
1129
    for (i=0; i<segmentCount; i++)
 
1130
    {
 
1131
      bSolid=PR_TRUE;
 
1132
      over = 0.0f;
 
1133
      segment =  (nsBorderEdge *)(aBorderEdges->mEdges[whichSide].ElementAt(i));
 
1134
      style = segment->mStyle;
 
1135
 
 
1136
      // XXX units for dash & dot?
 
1137
      if (style == NS_STYLE_BORDER_STYLE_DASHED) {
 
1138
        dashLength = DASH_LENGTH;
 
1139
      } else {
 
1140
        dashLength = DOT_LENGTH;
 
1141
      }
 
1142
 
 
1143
      aContext.SetColor(segment->mColor);  
 
1144
      switch (whichSide) {
 
1145
      case NS_SIDE_LEFT:
 
1146
      { // draw left segment i
 
1147
        nsBorderEdge * topEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(0));
 
1148
        if (0==y)
 
1149
        { // y is the offset to the top of this segment.  0 means its the topmost left segment
 
1150
          y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
 
1151
          if (PR_TRUE==aBorderEdges->mOutsideEdge)
 
1152
            y += topEdge->mWidth;
 
1153
        }
 
1154
        // the x offset is the x position offset by the max width of the left edge minus this segment's width
 
1155
        x = aBounds.x + (aBorderEdges->mMaxBorderWidth.left - segment->mWidth);
 
1156
        nscoord height = segment->mLength;
 
1157
        // the space between borderOutside and borderInside inclusive is the segment.
 
1158
        nsRect borderOutside(x, y, aBounds.width, height);
 
1159
        y += segment->mLength;  // keep track of the y offset for the next segment
 
1160
        if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
 
1161
            (style == NS_STYLE_BORDER_STYLE_DOTTED))
 
1162
        {
 
1163
          nsRect borderInside(borderOutside);
 
1164
          nsMargin outsideMargin(segment->mWidth, 0, 0, 0);
 
1165
          borderInside.Deflate(outsideMargin);
 
1166
          nscoord totalLength = segment->mLength; // the computed length of this segment
 
1167
          // outside edges need info from their inside neighbor.  The following code keeps track
 
1168
          // of which segment of the inside neighbor's shared edge we should use for this outside segment
 
1169
          if (PR_TRUE==aBorderEdges->mOutsideEdge)
 
1170
          {
 
1171
            if (segment->mInsideNeighbor == neighborBorderEdges)
 
1172
            {
 
1173
              neighborEdgeCount++;
 
1174
            }
 
1175
            else 
 
1176
            {
 
1177
              neighborBorderEdges = segment->mInsideNeighbor;
 
1178
              neighborEdgeCount=0;
 
1179
            }
 
1180
            nsBorderEdge * neighborLeft = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_LEFT].ElementAt(neighborEdgeCount));
 
1181
            totalLength = neighborLeft->mLength;
 
1182
          }
 
1183
          dashRect.width = borderInside.x - borderOutside.x;
 
1184
          dashRect.height = nscoord(dashRect.width * dashLength);
 
1185
          dashRect.x = borderOutside.x;
 
1186
          dashRect.y = borderOutside.y + (totalLength/2) - dashRect.height;
 
1187
          if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
 
1188
            dashRect.y -= topEdge->mWidth;  // account for the topmost left edge corner with the leftmost top edge
 
1189
          if (0)
 
1190
          {
 
1191
            printf("  L: totalLength = %d, borderOutside.y = %d, midpoint %d, dashRect.y = %d\n", 
 
1192
            totalLength, borderOutside.y, borderOutside.y +(totalLength/2), dashRect.y); 
 
1193
          }
 
1194
          currRect = dashRect;
 
1195
 
 
1196
          // we draw the segment in 2 halves to get the inside and outside edges to line up on the
 
1197
          // centerline of the shared edge.
 
1198
 
 
1199
          // draw the top half
 
1200
          while (currRect.YMost() > borderInside.y) {
 
1201
            //clip if necessary
 
1202
            if (currRect.y < borderInside.y) {
 
1203
              over = float(borderInside.y - dashRect.y) /
 
1204
                float(dashRect.height);
 
1205
              currRect.height = currRect.height - (borderInside.y - currRect.y);
 
1206
              currRect.y = borderInside.y;
 
1207
            }
 
1208
 
 
1209
            //draw if necessary
 
1210
            if (0)
 
1211
            {
 
1212
              printf("DASHED LEFT: xywh in loop currRect = %d %d %d %d %s\n", 
 
1213
                   currRect.x, currRect.y, currRect.width, currRect.height, bSolid?"TRUE":"FALSE");
 
1214
            }
 
1215
            if (bSolid) {
 
1216
              aContext.FillRect(currRect);
 
1217
            }
 
1218
 
 
1219
            //setup for next iteration
 
1220
            if (over == 0.0f) {
 
1221
              bSolid = PRBool(!bSolid);
 
1222
            }
 
1223
            dashRect.y = dashRect.y - currRect.height;
 
1224
            currRect = dashRect;
 
1225
          }
 
1226
 
 
1227
          // draw the bottom half
 
1228
          dashRect.y = borderOutside.y + (totalLength/2) + dashRect.height;
 
1229
          if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
 
1230
            dashRect.y -= topEdge->mWidth;
 
1231
          currRect = dashRect;
 
1232
          bSolid=PR_TRUE;
 
1233
          over = 0.0f;
 
1234
          while (currRect.YMost() < borderInside.YMost()) {
 
1235
            //clip if necessary
 
1236
            if (currRect.y < borderInside.y) {
 
1237
              over = float(borderInside.y - dashRect.y) /
 
1238
                float(dashRect.height);
 
1239
              currRect.height = currRect.height - (borderInside.y - currRect.y);
 
1240
              currRect.y = borderInside.y;
 
1241
            }
 
1242
 
 
1243
            //draw if necessary
 
1244
            if (0)
 
1245
            {
 
1246
              printf("DASHED LEFT: xywh in loop currRect = %d %d %d %d %s\n", 
 
1247
                   currRect.x, currRect.y, currRect.width, currRect.height, bSolid?"TRUE":"FALSE");
 
1248
            }
 
1249
            if (bSolid) {
 
1250
              aContext.FillRect(currRect);
 
1251
            }
 
1252
 
 
1253
            //setup for next iteration
 
1254
            if (over == 0.0f) {
 
1255
              bSolid = PRBool(!bSolid);
 
1256
            }
 
1257
            dashRect.y = dashRect.y + currRect.height;
 
1258
            currRect = dashRect;
 
1259
          }
 
1260
        }
 
1261
      }
 
1262
      break;
 
1263
 
 
1264
      case NS_SIDE_TOP:
 
1265
      { // draw top segment i
 
1266
        if (0==x)
 
1267
        {
 
1268
          nsBorderEdge * leftEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
 
1269
          x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
 
1270
        }
 
1271
        y = aBounds.y;
 
1272
        if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are bottom-aligned
 
1273
          y += aBorderEdges->mMaxBorderWidth.top - segment->mWidth;
 
1274
        nsRect borderOutside(x, y, segment->mLength, aBounds.height);
 
1275
        x += segment->mLength;
 
1276
        if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
 
1277
            (style == NS_STYLE_BORDER_STYLE_DOTTED))
 
1278
        {
 
1279
          nsRect borderInside(borderOutside);
 
1280
          nsBorderEdge * neighbor;
 
1281
          // XXX Adding check to make sure segment->mInsideNeighbor is not null
 
1282
          // so it will do the else part, at this point we are assuming this is an
 
1283
          // ok thing to do (Bug 52130)
 
1284
          if (PR_TRUE==aBorderEdges->mOutsideEdge && segment->mInsideNeighbor)
 
1285
            neighbor = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_LEFT].ElementAt(0));
 
1286
          else
 
1287
            neighbor = (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
 
1288
          nsMargin outsideMargin(neighbor->mWidth, segment->mWidth, 0, segment->mWidth);
 
1289
          borderInside.Deflate(outsideMargin);
 
1290
          nscoord firstRectWidth = 0;
 
1291
          if (PR_TRUE==aBorderEdges->mOutsideEdge && 0==i)
 
1292
          {
 
1293
            firstRectWidth = borderInside.x - borderOutside.x;
 
1294
            aContext.FillRect(borderOutside.x, borderOutside.y,
 
1295
                              firstRectWidth,
 
1296
                              borderInside.y - borderOutside.y);
 
1297
          }
 
1298
 
 
1299
          dashRect.height = borderInside.y - borderOutside.y;
 
1300
          dashRect.width = dashRect.height * dashLength;
 
1301
          dashRect.x = borderOutside.x + firstRectWidth;
 
1302
          dashRect.y = borderOutside.y;
 
1303
          currRect = dashRect;
 
1304
 
 
1305
          while (currRect.x < borderInside.XMost()) {
 
1306
            //clip if necessary
 
1307
            if (currRect.XMost() > borderInside.XMost()) {
 
1308
              over = float(dashRect.XMost() - borderInside.XMost()) /
 
1309
                float(dashRect.width);
 
1310
              currRect.width = currRect.width -
 
1311
                (currRect.XMost() - borderInside.XMost());
 
1312
            }
 
1313
 
 
1314
            //draw if necessary
 
1315
            if (bSolid) {
 
1316
              aContext.FillRect(currRect);
 
1317
            }
 
1318
 
 
1319
            //setup for next iteration
 
1320
            if (over == 0.0f) {
 
1321
              bSolid = PRBool(!bSolid);
 
1322
            }
 
1323
            dashRect.x = dashRect.x + currRect.width;
 
1324
            currRect = dashRect;
 
1325
          }
 
1326
        }
 
1327
      }
 
1328
      break;
 
1329
 
 
1330
      case NS_SIDE_RIGHT:
 
1331
      { // draw right segment i
 
1332
        nsBorderEdge * topEdge =  (nsBorderEdge *)
 
1333
            (aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(aBorderEdges->mEdges[NS_SIDE_TOP].Count()-1));
 
1334
        if (0==y)
 
1335
        {
 
1336
          y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
 
1337
          if (PR_TRUE==aBorderEdges->mOutsideEdge)
 
1338
            y += topEdge->mWidth;
 
1339
        }
 
1340
        nscoord width;
 
1341
        if (PR_TRUE==aBorderEdges->mOutsideEdge)
 
1342
        {
 
1343
          width = aBounds.width - aBorderEdges->mMaxBorderWidth.right;
 
1344
          width += segment->mWidth;
 
1345
        }
 
1346
        else
 
1347
        {
 
1348
          width = aBounds.width;
 
1349
        }
 
1350
        nscoord height = segment->mLength;
 
1351
        nsRect borderOutside(aBounds.x, y, width, height);
 
1352
        y += segment->mLength;
 
1353
        if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
 
1354
            (style == NS_STYLE_BORDER_STYLE_DOTTED))
 
1355
        {
 
1356
          nsRect borderInside(borderOutside);
 
1357
          nsMargin outsideMargin(segment->mWidth, 0, (segment->mWidth), 0);
 
1358
          borderInside.Deflate(outsideMargin);
 
1359
          nscoord totalLength = segment->mLength;
 
1360
          if (PR_TRUE==aBorderEdges->mOutsideEdge)
 
1361
          {
 
1362
            if (segment->mInsideNeighbor == neighborBorderEdges)
 
1363
            {
 
1364
              neighborEdgeCount++;
 
1365
            }
 
1366
            else 
 
1367
            {
 
1368
              neighborBorderEdges = segment->mInsideNeighbor;
 
1369
              neighborEdgeCount=0;
 
1370
            }
 
1371
            nsBorderEdge * neighborRight = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_RIGHT].ElementAt(neighborEdgeCount));
 
1372
            totalLength = neighborRight->mLength;
 
1373
          }
 
1374
          dashRect.width = borderOutside.XMost() - borderInside.XMost();
 
1375
          dashRect.height = nscoord(dashRect.width * dashLength);
 
1376
          dashRect.x = borderInside.XMost();
 
1377
          dashRect.y = borderOutside.y + (totalLength/2) - dashRect.height;
 
1378
          if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
 
1379
            dashRect.y -= topEdge->mWidth;
 
1380
          currRect = dashRect;
 
1381
 
 
1382
          // draw the top half
 
1383
          while (currRect.YMost() > borderInside.y) {
 
1384
            //clip if necessary
 
1385
            if (currRect.y < borderInside.y) {
 
1386
              over = float(borderInside.y - dashRect.y) /
 
1387
                float(dashRect.height);
 
1388
              currRect.height = currRect.height - (borderInside.y - currRect.y);
 
1389
              currRect.y = borderInside.y;
 
1390
            }
 
1391
 
 
1392
            //draw if necessary
 
1393
            if (bSolid) {
 
1394
              aContext.FillRect(currRect);
 
1395
            }
 
1396
 
 
1397
            //setup for next iteration
 
1398
            if (over == 0.0f) {
 
1399
              bSolid = PRBool(!bSolid);
 
1400
            }
 
1401
            dashRect.y = dashRect.y - currRect.height;
 
1402
            currRect = dashRect;
 
1403
          }
 
1404
 
 
1405
          // draw the bottom half
 
1406
          dashRect.y = borderOutside.y + (totalLength/2) + dashRect.height;
 
1407
          if ((PR_TRUE==aBorderEdges->mOutsideEdge) && (0!=i))
 
1408
            dashRect.y -= topEdge->mWidth;
 
1409
          currRect = dashRect;
 
1410
          bSolid=PR_TRUE;
 
1411
          over = 0.0f;
 
1412
          while (currRect.YMost() < borderInside.YMost()) {
 
1413
            //clip if necessary
 
1414
            if (currRect.y < borderInside.y) {
 
1415
              over = float(borderInside.y - dashRect.y) /
 
1416
                float(dashRect.height);
 
1417
              currRect.height = currRect.height - (borderInside.y - currRect.y);
 
1418
              currRect.y = borderInside.y;
 
1419
            }
 
1420
 
 
1421
            //draw if necessary
 
1422
            if (bSolid) {
 
1423
              aContext.FillRect(currRect);
 
1424
            }
 
1425
 
 
1426
            //setup for next iteration
 
1427
            if (over == 0.0f) {
 
1428
              bSolid = PRBool(!bSolid);
 
1429
            }
 
1430
            dashRect.y = dashRect.y + currRect.height;
 
1431
            currRect = dashRect;
 
1432
          }
 
1433
 
 
1434
        }
 
1435
      }
 
1436
      break;
 
1437
 
 
1438
      case NS_SIDE_BOTTOM:
 
1439
      {  // draw bottom segment i
 
1440
        if (0==x)
 
1441
        {
 
1442
          nsBorderEdge * leftEdge =  (nsBorderEdge *)
 
1443
            (aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(aBorderEdges->mEdges[NS_SIDE_LEFT].Count()-1));
 
1444
          x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
 
1445
        }
 
1446
        y = aBounds.y;
 
1447
        if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are top-aligned
 
1448
          y -= aBorderEdges->mMaxBorderWidth.bottom - segment->mWidth;
 
1449
        nsRect borderOutside(x, y, segment->mLength, aBounds.height);
 
1450
        x += segment->mLength;
 
1451
        if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
 
1452
            (style == NS_STYLE_BORDER_STYLE_DOTTED))
 
1453
        {
 
1454
          nsRect borderInside(borderOutside);
 
1455
          nsBorderEdge * neighbor;
 
1456
          if (PR_TRUE==aBorderEdges->mOutsideEdge)
 
1457
            neighbor = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_LEFT].ElementAt(0));
 
1458
          else
 
1459
            neighbor = (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
 
1460
          nsMargin outsideMargin(neighbor->mWidth, segment->mWidth, 0, segment->mWidth);
 
1461
          borderInside.Deflate(outsideMargin);
 
1462
          nscoord firstRectWidth = 0;
 
1463
          if (PR_TRUE==aBorderEdges->mOutsideEdge  &&  0==i)
 
1464
          {
 
1465
            firstRectWidth = borderInside.x - borderOutside.x;
 
1466
            aContext.FillRect(borderOutside.x, borderInside.YMost(),
 
1467
                              firstRectWidth,
 
1468
                              borderOutside.YMost() - borderInside.YMost());
 
1469
          }
 
1470
 
 
1471
          dashRect.height = borderOutside.YMost() - borderInside.YMost();
 
1472
          dashRect.width = nscoord(dashRect.height * dashLength);
 
1473
          dashRect.x = borderOutside.x + firstRectWidth;
 
1474
          dashRect.y = borderInside.YMost();
 
1475
          currRect = dashRect;
 
1476
 
 
1477
          while (currRect.x < borderInside.XMost()) {
 
1478
            //clip if necessary
 
1479
            if (currRect.XMost() > borderInside.XMost()) {
 
1480
              over = float(dashRect.XMost() - borderInside.XMost()) / 
 
1481
                float(dashRect.width);
 
1482
              currRect.width = currRect.width -
 
1483
                (currRect.XMost() - borderInside.XMost());
 
1484
            }
 
1485
 
 
1486
            //draw if necessary
 
1487
            if (bSolid) {
 
1488
              aContext.FillRect(currRect);
 
1489
            }
 
1490
 
 
1491
            //setup for next iteration
 
1492
            if (over == 0.0f) {
 
1493
              bSolid = PRBool(!bSolid);
 
1494
            }
 
1495
            dashRect.x = dashRect.x + currRect.width;
 
1496
            currRect = dashRect;
 
1497
          }
 
1498
        }
 
1499
      }
 
1500
      break;
 
1501
      }
 
1502
    }
 
1503
    skippedSide = PR_FALSE;
 
1504
  }
 
1505
}
 
1506
 
 
1507
nscolor
 
1508
nsCSSRendering::TransformColor(nscolor  aMapColor,PRBool aNoBackGround)
 
1509
{
 
1510
PRUint16  hue,sat,value;
 
1511
nscolor   newcolor;
 
1512
 
 
1513
  newcolor = aMapColor;
 
1514
  if (PR_TRUE == aNoBackGround){
 
1515
    // convert the RBG to HSV so we can get the lightness (which is the v)
 
1516
    NS_RGB2HSV(newcolor,hue,sat,value);
 
1517
    // The goal here is to send white to black while letting colored
 
1518
    // stuff stay colored... So we adopt the following approach.
 
1519
    // Something with sat = 0 should end up with value = 0.  Something
 
1520
    // with a high sat can end up with a high value and it's ok.... At
 
1521
    // the same time, we don't want to make things lighter.  Do
 
1522
    // something simple, since it seems to work.
 
1523
    if (value > sat) {
 
1524
      value = sat;
 
1525
      // convert this color back into the RGB color space.
 
1526
      NS_HSV2RGB(newcolor,hue,sat,value);
 
1527
    }
 
1528
  }
 
1529
  return newcolor;
 
1530
}
 
1531
 
 
1532
// method GetBGColorForHTMLElement
 
1533
//
 
1534
// Now here's a *fun* hack: Nav4 uses the BODY element's background color for the 
 
1535
//                          background color on tables so we need to find that element's
 
1536
//                          color and use it... Actually, we can use the HTML element as well.
 
1537
//
 
1538
// Traverse from PresContext to PresShell to Document to RootContent. The RootContent is
 
1539
// then checked to ensure that it is the HTML or BODY element, and if it is, we get
 
1540
// it's primary frame and from that the style context and from that the color to use.
 
1541
//
 
1542
PRBool GetBGColorForHTMLElement( nsIPresContext *aPresContext,
 
1543
                                   const nsStyleBackground *&aBGColor )
 
1544
{
 
1545
  NS_ASSERTION(aPresContext, "null params not allowed");
 
1546
  PRBool result = PR_FALSE; // assume we did not find the HTML element
 
1547
 
 
1548
  nsIPresShell* shell = aPresContext->GetPresShell();
 
1549
  if (shell) {
 
1550
    nsIDocument *doc = nsnull;
 
1551
    if (NS_SUCCEEDED(shell->GetDocument(&doc)) && doc) {
 
1552
      nsIContent *pContent;
 
1553
      if ((pContent = doc->GetRootContent())) {
 
1554
        // make sure that this is the HTML element
 
1555
        nsIAtom *tag = pContent->Tag();
 
1556
        NS_ASSERTION(tag, "Tag could not be retrieved from root content element");
 
1557
        if (tag == nsHTMLAtoms::html ||
 
1558
            tag == nsHTMLAtoms::body) {
 
1559
          // use this guy's color
 
1560
          nsIFrame *pFrame = nsnull;
 
1561
          if (NS_SUCCEEDED(shell->GetPrimaryFrameFor(pContent, &pFrame)) &&
 
1562
              pFrame) {
 
1563
            nsStyleContext *pContext = pFrame->GetStyleContext();
 
1564
            if (pContext) {
 
1565
              const nsStyleBackground* color = pContext->GetStyleBackground();
 
1566
              if (0 == (color->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT)) {
 
1567
                aBGColor = color;
 
1568
                // set the reslt to TRUE to indicate we mapped the color
 
1569
                result = PR_TRUE;
 
1570
              }
 
1571
            }// if context
 
1572
          }// if frame
 
1573
        }// if tag == html or body
 
1574
#ifdef DEBUG
 
1575
        else {
 
1576
          printf( "Root Content is not HTML or BODY: cannot get bgColor of HTML or BODY\n");
 
1577
        }
 
1578
#endif
 
1579
      }// if content
 
1580
      NS_RELEASE(doc);
 
1581
    }// if doc
 
1582
  } // if shell
 
1583
 
 
1584
  return result;
 
1585
}
 
1586
 
 
1587
// helper macro to determine if the borderstyle 'a' is a MOZ-BG-XXX style
 
1588
#define MOZ_BG_BORDER(a)\
 
1589
((a==NS_STYLE_BORDER_STYLE_BG_INSET) || (a==NS_STYLE_BORDER_STYLE_BG_OUTSET)\
 
1590
                                     || (a==NS_STYLE_BORDER_STYLE_BG_SOLID))
 
1591
 
 
1592
static
 
1593
PRBool GetBorderColor(const nsStyleColor* aColor, const nsStyleBorder& aBorder, PRUint8 aSide, nscolor& aColorVal,
 
1594
                      nsBorderColors** aCompositeColors = nsnull)
 
1595
{
 
1596
  PRBool transparent;
 
1597
  PRBool foreground;
 
1598
 
 
1599
  if (aCompositeColors) {
 
1600
    aBorder.GetCompositeColors(aSide, aCompositeColors);
 
1601
    if (*aCompositeColors)
 
1602
      return PR_TRUE;
 
1603
  }
 
1604
 
 
1605
  aBorder.GetBorderColor(aSide, aColorVal, transparent, foreground);
 
1606
  if (foreground)
 
1607
    aColorVal = aColor->mColor;
 
1608
 
 
1609
  return !transparent;
 
1610
}
 
1611
 
 
1612
// XXX improve this to constrain rendering to the damaged area
 
1613
void nsCSSRendering::PaintBorder(nsIPresContext* aPresContext,
 
1614
                                 nsIRenderingContext& aRenderingContext,
 
1615
                                 nsIFrame* aForFrame,
 
1616
                                 const nsRect& aDirtyRect,
 
1617
                                 const nsRect& aBorderArea,
 
1618
                                 const nsStyleBorder& aBorderStyle,
 
1619
                                 nsStyleContext* aStyleContext,
 
1620
                                 PRIntn aSkipSides,
 
1621
                                 nsRect* aGap,
 
1622
                                 nscoord aHardBorderSize,
 
1623
                                 PRBool  aShouldIgnoreRounded)
 
1624
{
 
1625
  PRIntn              cnt;
 
1626
  nsMargin            border;
 
1627
  nsStyleCoord        bordStyleRadius[4];
 
1628
  PRInt16             borderRadii[4],i;
 
1629
  float               percent;
 
1630
  nsCompatibility     compatMode = aPresContext->CompatibilityMode();
 
1631
 
 
1632
  // Check to see if we have an appearance defined.  If so, we let the theme
 
1633
  // renderer draw the border.  DO not get the data from aForFrame, since the passed in style context
 
1634
  // may be different!  Always use |aStyleContext|!
 
1635
  const nsStyleDisplay* displayData = aStyleContext->GetStyleDisplay();
 
1636
  if (displayData->mAppearance) {
 
1637
    nsCOMPtr<nsITheme> theme;
 
1638
    aPresContext->GetTheme(getter_AddRefs(theme));
 
1639
    if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame, displayData->mAppearance))
 
1640
      return; // Let the theme handle it.
 
1641
  }
 
1642
  // Get our style context's color struct.
 
1643
  const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
 
1644
 
 
1645
  // in NavQuirks mode we want to use the parent's context as a starting point 
 
1646
  // for determining the background color
 
1647
  const nsStyleBackground* bgColor = 
 
1648
    nsCSSRendering::FindNonTransparentBackground(aStyleContext, 
 
1649
                                            compatMode == eCompatibility_NavQuirks ? PR_TRUE : PR_FALSE); 
 
1650
 
 
1651
  // mozBGColor is used instead of bgColor when the display type is BG_INSET or BG_OUTSET
 
1652
  // or BG_SOLID, and, in quirk mode, it is set to the BODY element's background color
 
1653
  // instead of the nearest ancestor's background color.
 
1654
  const nsStyleBackground* mozBGColor = bgColor;
 
1655
 
 
1656
  // now check if we are in Quirks mode and have a border style of BG_INSET or OUTSET
 
1657
  // or BG_SOLID - if so we use the bgColor from the HTML element instead of the
 
1658
  // nearest ancestor
 
1659
  if (compatMode == eCompatibility_NavQuirks) {
 
1660
    PRBool bNeedBodyBGColor = PR_FALSE;
 
1661
    if (aStyleContext) {
 
1662
      for (cnt=0; cnt<4;cnt++) {
 
1663
        bNeedBodyBGColor = MOZ_BG_BORDER(aBorderStyle.GetBorderStyle(cnt));
 
1664
        if (bNeedBodyBGColor) {
 
1665
          break;
 
1666
        }
 
1667
      }
 
1668
    }
 
1669
    if (bNeedBodyBGColor) {
 
1670
      GetBGColorForHTMLElement(aPresContext, mozBGColor);
 
1671
    } 
 
1672
  }
 
1673
 
 
1674
  if (aHardBorderSize > 0) {
 
1675
    border.SizeTo(aHardBorderSize, aHardBorderSize, aHardBorderSize, aHardBorderSize);
 
1676
  } else {
 
1677
    aBorderStyle.CalcBorderFor(aForFrame, border);
 
1678
  }
 
1679
  if ((0 == border.left) && (0 == border.right) &&
 
1680
      (0 == border.top) && (0 == border.bottom)) {
 
1681
    // Empty border area
 
1682
    return;
 
1683
  }
 
1684
 
 
1685
 
 
1686
  // get the radius for our border
 
1687
  aBorderStyle.mBorderRadius.GetTop(bordStyleRadius[0]);      //topleft
 
1688
  aBorderStyle.mBorderRadius.GetRight(bordStyleRadius[1]);    //topright
 
1689
  aBorderStyle.mBorderRadius.GetBottom(bordStyleRadius[2]);   //bottomright
 
1690
  aBorderStyle.mBorderRadius.GetLeft(bordStyleRadius[3]);     //bottomleft
 
1691
 
 
1692
  for(i=0;i<4;i++) {
 
1693
    borderRadii[i] = 0;
 
1694
    switch ( bordStyleRadius[i].GetUnit()) {
 
1695
    case eStyleUnit_Percent:
 
1696
      percent = bordStyleRadius[i].GetPercentValue();
 
1697
      borderRadii[i] = (nscoord)(percent * aBorderArea.width);
 
1698
      break;
 
1699
    case eStyleUnit_Coord:
 
1700
      borderRadii[i] = bordStyleRadius[i].GetCoordValue();
 
1701
      break;
 
1702
    default:
 
1703
      break;
 
1704
    }
 
1705
  }
 
1706
 
 
1707
  // rounded version of the outline
 
1708
  // check for any corner that is rounded
 
1709
  for(i=0;i<4;i++){
 
1710
    if(borderRadii[i] > 0 && !aBorderStyle.mBorderColors){
 
1711
      PaintRoundedBorder(aPresContext,aRenderingContext,aForFrame,aDirtyRect,aBorderArea,&aBorderStyle,nsnull,aStyleContext,aSkipSides,borderRadii,aGap,PR_FALSE);
 
1712
      return;
 
1713
    }
 
1714
  }
 
1715
 
 
1716
  // Turn off rendering for all of the zero sized sides
 
1717
  if (0 == border.top) aSkipSides |= (1 << NS_SIDE_TOP);
 
1718
  if (0 == border.right) aSkipSides |= (1 << NS_SIDE_RIGHT);
 
1719
  if (0 == border.bottom) aSkipSides |= (1 << NS_SIDE_BOTTOM);
 
1720
  if (0 == border.left) aSkipSides |= (1 << NS_SIDE_LEFT);
 
1721
 
 
1722
  // get the inside and outside parts of the border
 
1723
  nsRect outerRect(aBorderArea);
 
1724
  nsRect innerRect(outerRect);
 
1725
  innerRect.Deflate(border);
 
1726
 
 
1727
  if (border.left + border.right > aBorderArea.width) {
 
1728
    innerRect.x = outerRect.x;
 
1729
    innerRect.width = outerRect.width;
 
1730
  }
 
1731
  if (border.top + border.bottom > aBorderArea.height) {
 
1732
    innerRect.y = outerRect.y;
 
1733
    innerRect.height = outerRect.height;
 
1734
  }
 
1735
 
 
1736
 
 
1737
 
 
1738
  // If the dirty rect is completely inside the border area (e.g., only the
 
1739
  // content is being painted), then we can skip out now
 
1740
  if (innerRect.Contains(aDirtyRect)) {
 
1741
    return;
 
1742
  }
 
1743
 
 
1744
  //see if any sides are dotted or dashed
 
1745
  for (cnt = 0; cnt < 4; cnt++) {
 
1746
    if ((aBorderStyle.GetBorderStyle(cnt) == NS_STYLE_BORDER_STYLE_DOTTED) || 
 
1747
        (aBorderStyle.GetBorderStyle(cnt) == NS_STYLE_BORDER_STYLE_DASHED))  {
 
1748
      break;
 
1749
    }
 
1750
  }
 
1751
  if (cnt < 4) {
 
1752
    DrawDashedSides(cnt, aRenderingContext,aDirtyRect, ourColor, &aBorderStyle,nsnull, PR_FALSE,
 
1753
                    outerRect, innerRect, aSkipSides, aGap);
 
1754
  }
 
1755
 
 
1756
  // dont clip the borders for composite borders, they use the inner and 
 
1757
  // outer rect to compute the diagonale to cross the border radius
 
1758
  nsRect compositeInnerRect(innerRect);
 
1759
  nsRect compositeOuterRect(outerRect);
 
1760
 
 
1761
  // Draw all the other sides
 
1762
  if (!aDirtyRect.Contains(outerRect)) {
 
1763
    // Border leaks out of the dirty rectangle - lets clip it but with care
 
1764
    if (innerRect.y < aDirtyRect.y) {
 
1765
      aSkipSides |= (1 << NS_SIDE_TOP);
 
1766
      PRUint32 shortenBy =
 
1767
        PR_MIN(innerRect.height, aDirtyRect.y - innerRect.y);
 
1768
      innerRect.y += shortenBy;
 
1769
      innerRect.height -= shortenBy;
 
1770
      outerRect.y += shortenBy;
 
1771
      outerRect.height -= shortenBy;
 
1772
    }
 
1773
    if (aDirtyRect.YMost() < innerRect.YMost()) {
 
1774
      aSkipSides |= (1 << NS_SIDE_BOTTOM);
 
1775
      PRUint32 shortenBy =
 
1776
        PR_MIN(innerRect.height, innerRect.YMost() - aDirtyRect.YMost());
 
1777
      innerRect.height -= shortenBy;
 
1778
      outerRect.height -= shortenBy;
 
1779
    }
 
1780
    if (innerRect.x < aDirtyRect.x) {
 
1781
      aSkipSides |= (1 << NS_SIDE_LEFT);
 
1782
      PRUint32 shortenBy =
 
1783
        PR_MIN(innerRect.width, aDirtyRect.x - innerRect.x);
 
1784
      innerRect.x += shortenBy;
 
1785
      innerRect.width -= shortenBy;
 
1786
      outerRect.x += shortenBy;
 
1787
      outerRect.width -= shortenBy;
 
1788
    }
 
1789
    if (aDirtyRect.XMost() < innerRect.XMost()) {
 
1790
      aSkipSides |= (1 << NS_SIDE_RIGHT);
 
1791
      PRUint32 shortenBy =
 
1792
        PR_MIN(innerRect.width, innerRect.XMost() - aDirtyRect.XMost());
 
1793
      innerRect.width -= shortenBy;
 
1794
      outerRect.width -= shortenBy;
 
1795
    }
 
1796
  }
 
1797
  /* Get our conversion values */
 
1798
  nscoord twipsPerPixel;
 
1799
  float p2t;
 
1800
  aPresContext->GetScaledPixelsToTwips(&p2t);
 
1801
  twipsPerPixel = NSIntPixelsToTwips(1,p2t);
 
1802
 
 
1803
  static PRUint8 sideOrder[] = { NS_SIDE_BOTTOM, NS_SIDE_LEFT, NS_SIDE_TOP, NS_SIDE_RIGHT };
 
1804
  nscolor sideColor;
 
1805
  nsBorderColors* compositeColors = nsnull;
 
1806
  for (cnt = 0; cnt < 4; cnt++) {
 
1807
    PRUint8 side = sideOrder[cnt];
 
1808
    if (0 == (aSkipSides & (1<<side))) {
 
1809
      if (GetBorderColor(ourColor, aBorderStyle, side, sideColor, &compositeColors)) {
 
1810
        if (compositeColors)
 
1811
          DrawCompositeSide(aRenderingContext, side, compositeColors, compositeOuterRect, 
 
1812
                            compositeInnerRect, borderRadii, twipsPerPixel, aGap);
 
1813
        else
 
1814
          DrawSide(aRenderingContext, side,
 
1815
                   aBorderStyle.GetBorderStyle(side),
 
1816
                   sideColor,
 
1817
                   MOZ_BG_BORDER(aBorderStyle.GetBorderStyle(side)) ? 
 
1818
                    mozBGColor->mBackgroundColor :
 
1819
                    bgColor->mBackgroundColor,
 
1820
                   outerRect,innerRect, aSkipSides,
 
1821
                   twipsPerPixel, aGap);
 
1822
      }
 
1823
    }
 
1824
  }
 
1825
}
 
1826
 
 
1827
void nsCSSRendering::DrawCompositeSide(nsIRenderingContext& aRenderingContext,
 
1828
                                       PRIntn aWhichSide,
 
1829
                                       nsBorderColors* aCompositeColors,
 
1830
                                       const nsRect& aOuterRect,
 
1831
                                       const nsRect& aInnerRect,
 
1832
                                       PRInt16* aBorderRadii,
 
1833
                                       nscoord twipsPerPixel,
 
1834
                                       nsRect* aGap)
 
1835
 
 
1836
{
 
1837
  // Loop over each color and at each iteration shrink the length of the
 
1838
  // lines that we draw.
 
1839
  nsRect currOuterRect(aOuterRect);
 
1840
 
 
1841
  // XXXdwh This border radius code is rather hacky and will only work for
 
1842
  // small radii, but it will be sufficient to get a major performance
 
1843
  // improvement in themes with small curvature (like Modern).
 
1844
  // Still, this code should be rewritten if/when someone chooses to pick
 
1845
  // up the -moz-border-radius gauntlet.
 
1846
  // Alternatively we could add support for a -moz-border-diagonal property, which is
 
1847
  // what this code actually draws (instead of a curve).
 
1848
 
 
1849
  // determine the the number of pixels we need to draw for this side
 
1850
  // and the start and end radii
 
1851
  nscoord shrinkage, startRadius, endRadius;
 
1852
  if (aWhichSide == NS_SIDE_TOP) {
 
1853
    shrinkage = aInnerRect.y - aOuterRect.y;
 
1854
    startRadius = aBorderRadii[0];
 
1855
    endRadius = aBorderRadii[1];
 
1856
  } else if (aWhichSide == NS_SIDE_BOTTOM) {
 
1857
    shrinkage = (aOuterRect.height+aOuterRect.y) - (aInnerRect.height+aInnerRect.y);
 
1858
    startRadius = aBorderRadii[3];
 
1859
    endRadius = aBorderRadii[2];
 
1860
  } else if (aWhichSide == NS_SIDE_RIGHT) {
 
1861
    shrinkage = (aOuterRect.width+aOuterRect.x) - (aInnerRect.width+aInnerRect.x);
 
1862
    startRadius = aBorderRadii[1];
 
1863
    endRadius = aBorderRadii[2];
 
1864
  } else if (aWhichSide == NS_SIDE_LEFT) {
 
1865
    shrinkage = aInnerRect.x - aOuterRect.x;
 
1866
    startRadius = aBorderRadii[0];
 
1867
    endRadius = aBorderRadii[3];
 
1868
  }
 
1869
 
 
1870
  while (shrinkage > 0) {
 
1871
    nscoord xshrink = 0;
 
1872
    nscoord yshrink = 0;
 
1873
    nscoord widthshrink = 0;
 
1874
    nscoord heightshrink = 0;
 
1875
 
 
1876
    if (startRadius || endRadius) {
 
1877
      if (aWhichSide == NS_SIDE_TOP || aWhichSide == NS_SIDE_BOTTOM) {
 
1878
        xshrink = startRadius;
 
1879
        widthshrink = startRadius + endRadius;
 
1880
      }
 
1881
      else if (aWhichSide == NS_SIDE_LEFT || aWhichSide == NS_SIDE_RIGHT) {
 
1882
        yshrink = startRadius-1;
 
1883
        heightshrink = yshrink + endRadius;
 
1884
      }
 
1885
    }
 
1886
 
 
1887
    // subtract any rounded pixels from the outer rect
 
1888
    nsRect newOuterRect(currOuterRect);
 
1889
    newOuterRect.x += xshrink;
 
1890
    newOuterRect.y += yshrink;
 
1891
    newOuterRect.width -= widthshrink;
 
1892
    newOuterRect.height -= heightshrink;
 
1893
 
 
1894
    nsRect borderInside(currOuterRect);
 
1895
    
 
1896
    // try to subtract one pixel from each side of the outer rect, but only if 
 
1897
    // that side has any extra space left to shrink
 
1898
    if (aInnerRect.x > borderInside.x) { // shrink left
 
1899
      borderInside.x += twipsPerPixel;
 
1900
      borderInside.width -= twipsPerPixel;
 
1901
    }
 
1902
    if (borderInside.x+borderInside.width > aInnerRect.x+aInnerRect.width) // shrink right
 
1903
      borderInside.width -= twipsPerPixel;
 
1904
    
 
1905
    if (aInnerRect.y > borderInside.y) { // shrink top
 
1906
      borderInside.y += twipsPerPixel;
 
1907
      borderInside.height -= twipsPerPixel;
 
1908
    }
 
1909
    if (borderInside.y+borderInside.height > aInnerRect.y+aInnerRect.height) // shrink bottom
 
1910
      borderInside.height -= twipsPerPixel;
 
1911
 
 
1912
    if (!aCompositeColors->mTransparent) {
 
1913
      nsPoint theSide[MAX_POLY_POINTS];
 
1914
      PRInt32 np = MakeSide(theSide, aRenderingContext, aWhichSide, newOuterRect, borderInside, 0,
 
1915
                            BORDER_FULL, 1.0f, twipsPerPixel);
 
1916
      NS_ASSERTION(np == 2, "Composite border should always be single pixel!");
 
1917
      aRenderingContext.SetColor(aCompositeColors->mColor);
 
1918
      DrawLine(aRenderingContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
 
1919
    
 
1920
      if (aWhichSide == NS_SIDE_TOP) {
 
1921
        if (startRadius) {
 
1922
          // Connecting line between top/left
 
1923
          nscoord distance = (startRadius+twipsPerPixel)/2;
 
1924
          nscoord remainder = distance%twipsPerPixel;
 
1925
          if (remainder) 
 
1926
            distance += twipsPerPixel - remainder;
 
1927
          DrawLine(aRenderingContext,
 
1928
                   currOuterRect.x+startRadius,
 
1929
                   currOuterRect.y, 
 
1930
                   currOuterRect.x+startRadius-distance,
 
1931
                   currOuterRect.y+distance,
 
1932
                   aGap);
 
1933
        }
 
1934
        if (endRadius) {
 
1935
          // Connecting line between top/right
 
1936
          nscoord distance = (endRadius+twipsPerPixel)/2;
 
1937
          nscoord remainder = distance%twipsPerPixel;
 
1938
          if (remainder) 
 
1939
            distance += twipsPerPixel - remainder;
 
1940
          DrawLine(aRenderingContext,
 
1941
                   currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel,
 
1942
                   currOuterRect.y, 
 
1943
                   currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel+distance,
 
1944
                   currOuterRect.y+distance,
 
1945
                   aGap);
 
1946
        }
 
1947
      }
 
1948
      else if (aWhichSide == NS_SIDE_BOTTOM) {
 
1949
        if (startRadius) {
 
1950
          // Connecting line between bottom/left
 
1951
          nscoord distance = (startRadius+twipsPerPixel)/2;
 
1952
          nscoord remainder = distance%twipsPerPixel;
 
1953
          if (remainder) 
 
1954
            distance += twipsPerPixel - remainder;
 
1955
          DrawLine(aRenderingContext,
 
1956
                   currOuterRect.x+startRadius, 
 
1957
                   currOuterRect.y+currOuterRect.height-twipsPerPixel,
 
1958
                   currOuterRect.x+startRadius-distance, 
 
1959
                   currOuterRect.y+currOuterRect.height-twipsPerPixel-distance,
 
1960
                   aGap);
 
1961
        }
 
1962
        if (endRadius) {
 
1963
          // Connecting line between bottom/right
 
1964
          nscoord distance = (endRadius+twipsPerPixel)/2;
 
1965
          nscoord remainder = distance%twipsPerPixel;
 
1966
          if (remainder) 
 
1967
            distance += twipsPerPixel - remainder;
 
1968
          DrawLine(aRenderingContext,
 
1969
                   currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel, 
 
1970
                   currOuterRect.y+currOuterRect.height-twipsPerPixel, 
 
1971
                   currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel+distance, 
 
1972
                   currOuterRect.y+currOuterRect.height-twipsPerPixel-distance,
 
1973
                   aGap);
 
1974
        }
 
1975
      }
 
1976
      else if (aWhichSide == NS_SIDE_LEFT) {
 
1977
        if (startRadius) {
 
1978
          // Connecting line between left/top
 
1979
          nscoord distance = (startRadius-twipsPerPixel)/2;
 
1980
          nscoord remainder = distance%twipsPerPixel;
 
1981
          if (remainder)
 
1982
            distance -= remainder;
 
1983
          DrawLine(aRenderingContext,
 
1984
                   currOuterRect.x+distance,
 
1985
                   currOuterRect.y+startRadius-distance, 
 
1986
                   currOuterRect.x,
 
1987
                   currOuterRect.y+startRadius,
 
1988
                   aGap);
 
1989
        }
 
1990
        if (endRadius) {
 
1991
          // Connecting line between left/bottom
 
1992
          nscoord distance = (endRadius-twipsPerPixel)/2;
 
1993
          nscoord remainder = distance%twipsPerPixel;
 
1994
          if (remainder)
 
1995
            distance -= remainder;
 
1996
          DrawLine(aRenderingContext,
 
1997
                   currOuterRect.x+distance,
 
1998
                   currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius+distance,
 
1999
                   currOuterRect.x,
 
2000
                   currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius,
 
2001
                   aGap);
 
2002
        }
 
2003
      }
 
2004
      else if (aWhichSide == NS_SIDE_RIGHT) {
 
2005
       if (startRadius) {
 
2006
          // Connecting line between right/top
 
2007
          nscoord distance = (startRadius-twipsPerPixel)/2;
 
2008
          nscoord remainder = distance%twipsPerPixel;
 
2009
          if (remainder)
 
2010
            distance -= remainder;
 
2011
          DrawLine(aRenderingContext,
 
2012
                   currOuterRect.x+currOuterRect.width-twipsPerPixel-distance,
 
2013
                   currOuterRect.y+startRadius-distance, 
 
2014
                   currOuterRect.x+currOuterRect.width-twipsPerPixel,
 
2015
                   currOuterRect.y+startRadius,
 
2016
                   aGap);
 
2017
        }
 
2018
        if (endRadius) {
 
2019
          // Connecting line between right/bottom
 
2020
          nscoord distance = (endRadius-twipsPerPixel)/2;
 
2021
          nscoord remainder = distance%twipsPerPixel;
 
2022
          if (remainder)
 
2023
            distance -= remainder;
 
2024
          DrawLine(aRenderingContext,
 
2025
                   currOuterRect.x+currOuterRect.width-twipsPerPixel-distance, 
 
2026
                   currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius+distance,
 
2027
                   currOuterRect.x+currOuterRect.width-twipsPerPixel, 
 
2028
                   currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius,
 
2029
                   aGap);
 
2030
        }
 
2031
      }
 
2032
    }
 
2033
    
 
2034
    if (aCompositeColors->mNext)
 
2035
      aCompositeColors = aCompositeColors->mNext;
 
2036
 
 
2037
    currOuterRect = borderInside;
 
2038
    shrinkage -= twipsPerPixel;
 
2039
    
 
2040
    startRadius -= twipsPerPixel;
 
2041
    if (startRadius < 0) startRadius = 0;
 
2042
    endRadius -= twipsPerPixel;
 
2043
    if (endRadius < 0) endRadius = 0;
 
2044
  }
 
2045
}
 
2046
 
 
2047
// XXX improve this to constrain rendering to the damaged area
 
2048
void nsCSSRendering::PaintOutline(nsIPresContext* aPresContext,
 
2049
                                 nsIRenderingContext& aRenderingContext,
 
2050
                                 nsIFrame* aForFrame,
 
2051
                                 const nsRect& aDirtyRect,
 
2052
                                 const nsRect& aBorderArea,
 
2053
                                 const nsStyleBorder& aBorderStyle,
 
2054
                                 const nsStyleOutline& aOutlineStyle,
 
2055
                                 nsStyleContext* aStyleContext,
 
2056
                                 PRIntn aSkipSides,
 
2057
                                 nsRect* aGap)
 
2058
{
 
2059
nsStyleCoord        bordStyleRadius[4];
 
2060
PRInt16             borderRadii[4],i;
 
2061
float               percent;
 
2062
const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
 
2063
nscoord width;
 
2064
 
 
2065
  // Get our style context's color struct.
 
2066
  const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
 
2067
 
 
2068
  aOutlineStyle.GetOutlineWidth(width);
 
2069
 
 
2070
  if (0 == width) {
 
2071
    // Empty outline
 
2072
    return;
 
2073
  }
 
2074
 
 
2075
  // get the radius for our border
 
2076
  aOutlineStyle.mOutlineRadius.GetTop(bordStyleRadius[0]);      //topleft
 
2077
  aOutlineStyle.mOutlineRadius.GetRight(bordStyleRadius[1]);    //topright
 
2078
  aOutlineStyle.mOutlineRadius.GetBottom(bordStyleRadius[2]);   //bottomright
 
2079
  aOutlineStyle.mOutlineRadius.GetLeft(bordStyleRadius[3]);     //bottomleft
 
2080
 
 
2081
  for(i=0;i<4;i++) {
 
2082
    borderRadii[i] = 0;
 
2083
    switch ( bordStyleRadius[i].GetUnit()) {
 
2084
    case eStyleUnit_Percent:
 
2085
      percent = bordStyleRadius[i].GetPercentValue();
 
2086
      borderRadii[i] = (nscoord)(percent * aBorderArea.width);
 
2087
      break;
 
2088
    case eStyleUnit_Coord:
 
2089
      borderRadii[i] = bordStyleRadius[i].GetCoordValue();
 
2090
      break;
 
2091
    default:
 
2092
      break;
 
2093
    }
 
2094
  }
 
2095
 
 
2096
 
 
2097
  // This if control whether the outline paints on the inside 
 
2098
  // or outside of the frame
 
2099
  // XXX This is temporary fix for nsbeta3+ Bug 48973
 
2100
  // so we can use "mozoutline
 
2101
#if 0 // outside
 
2102
  nsRect inside(aBorderArea);
 
2103
  nsRect outside(inside);
 
2104
  inside.Inflate(width, width);
 
2105
 
 
2106
  nsRect clipRect(aBorderArea);
 
2107
  clipRect.Inflate(width, width); // make clip extra big for now
 
2108
 
 
2109
#else // inside
 
2110
  nsMargin borderWidth;
 
2111
  aBorderStyle.GetBorder(borderWidth);
 
2112
 
 
2113
  nsRect outside(aBorderArea);
 
2114
  outside.Deflate(borderWidth);
 
2115
  nsRect inside(outside);
 
2116
  inside.Deflate(width, width);
 
2117
 
 
2118
  nsRect clipRect(outside);
 
2119
#endif
 
2120
 
 
2121
  PRBool clipState = PR_FALSE;
 
2122
  aRenderingContext.PushState();
 
2123
  aRenderingContext.SetClipRect(clipRect, nsClipCombine_kReplace, clipState);
 
2124
 
 
2125
  // rounded version of the border
 
2126
  for(i=0;i<4;i++){
 
2127
    if(borderRadii[i] > 0){
 
2128
      PaintRoundedBorder(aPresContext,aRenderingContext,aForFrame,aDirtyRect,aBorderArea,nsnull,&aOutlineStyle,aStyleContext,aSkipSides,borderRadii,aGap,PR_TRUE);
 
2129
      aRenderingContext.PopState(clipState);
 
2130
      return;
 
2131
    }
 
2132
  }
 
2133
 
 
2134
 
 
2135
  PRUint8 outlineStyle = aOutlineStyle.GetOutlineStyle();
 
2136
  //see if any sides are dotted or dashed
 
2137
  if ((outlineStyle == NS_STYLE_BORDER_STYLE_DOTTED) || 
 
2138
      (outlineStyle == NS_STYLE_BORDER_STYLE_DASHED))  {
 
2139
    DrawDashedSides(0, aRenderingContext, aDirtyRect, ourColor, nsnull, &aOutlineStyle, PR_TRUE,
 
2140
                    outside, inside, aSkipSides, aGap);
 
2141
    aRenderingContext.PopState(clipState);
 
2142
    return;
 
2143
  }
 
2144
 
 
2145
  // Draw all the other sides
 
2146
 
 
2147
  /* XXX something is misnamed here!!!! */
 
2148
  nscoord twipsPerPixel;/* XXX */
 
2149
  float p2t;/* XXX */
 
2150
  p2t = aPresContext->PixelsToTwips();/* XXX */
 
2151
  twipsPerPixel = (nscoord) p2t;/* XXX */
 
2152
 
 
2153
  nscolor outlineColor(NS_RGB(0,0,0)); // default to black in case it is invert color and the platform does not support that
 
2154
  PRBool  canDraw = PR_FALSE;
 
2155
  PRBool  modeChanged=PR_FALSE;
 
2156
 
 
2157
  // see if the outline color is 'invert' or can invert.
 
2158
  if (aOutlineStyle.GetOutlineInvert()) {
 
2159
    canDraw = PR_TRUE;
 
2160
    if( NS_SUCCEEDED(aRenderingContext.SetPenMode(nsPenMode_kInvert)) ) {
 
2161
      modeChanged=PR_TRUE;
 
2162
     }
 
2163
  } else {
 
2164
    canDraw = aOutlineStyle.GetOutlineColor(outlineColor);
 
2165
  }
 
2166
 
 
2167
  if (PR_TRUE == canDraw) {
 
2168
    DrawSide(aRenderingContext, NS_SIDE_BOTTOM,
 
2169
             outlineStyle,
 
2170
             outlineColor,
 
2171
             bgColor->mBackgroundColor, outside, inside, aSkipSides,
 
2172
             twipsPerPixel, aGap);
 
2173
 
 
2174
    DrawSide(aRenderingContext, NS_SIDE_LEFT,
 
2175
             outlineStyle, 
 
2176
             outlineColor,
 
2177
             bgColor->mBackgroundColor,outside, inside,aSkipSides,
 
2178
             twipsPerPixel, aGap);
 
2179
 
 
2180
    DrawSide(aRenderingContext, NS_SIDE_TOP,
 
2181
             outlineStyle,
 
2182
             outlineColor,
 
2183
             bgColor->mBackgroundColor,outside, inside,aSkipSides,
 
2184
             twipsPerPixel, aGap);
 
2185
 
 
2186
    DrawSide(aRenderingContext, NS_SIDE_RIGHT,
 
2187
             outlineStyle,
 
2188
             outlineColor,
 
2189
             bgColor->mBackgroundColor,outside, inside,aSkipSides,
 
2190
             twipsPerPixel, aGap);
 
2191
             
 
2192
    if(modeChanged ) {
 
2193
      aRenderingContext.SetPenMode(nsPenMode_kNone);
 
2194
    }  
 
2195
  }
 
2196
  // Restore clipping
 
2197
  aRenderingContext.PopState(clipState);
 
2198
}
 
2199
 
 
2200
/* draw the edges of the border described in aBorderEdges one segment at a time.
 
2201
 * a border has 4 edges.  Each edge has 1 or more segments. 
 
2202
 * "inside edges" are drawn differently than "outside edges" so the shared edges will match up.
 
2203
 * in the case of table collapsing borders, the table edge is the "outside" edge and
 
2204
 * cell edges are always "inside" edges (so adjacent cells have 2 shared "inside" edges.)
 
2205
 * dashed segments are drawn by DrawDashedSegments().
 
2206
 */
 
2207
// XXX: doesn't do corners or junctions well at all.  Just uses logic stolen 
 
2208
//      from PaintBorder which is insufficient
 
2209
 
 
2210
void nsCSSRendering::PaintBorderEdges(nsIPresContext* aPresContext,
 
2211
                                      nsIRenderingContext& aRenderingContext,
 
2212
                                      nsIFrame* aForFrame,
 
2213
                                      const nsRect& aDirtyRect,
 
2214
                                      const nsRect& aBorderArea,
 
2215
                                      nsBorderEdges * aBorderEdges,
 
2216
                                      nsStyleContext* aStyleContext,
 
2217
                                      PRIntn aSkipSides,
 
2218
                                      nsRect* aGap)
 
2219
{
 
2220
  const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
 
2221
  
 
2222
  if (nsnull==aBorderEdges) {  // Empty border segments
 
2223
    return;
 
2224
  }
 
2225
 
 
2226
  // Turn off rendering for all of the zero sized sides
 
2227
  if (0 == aBorderEdges->mMaxBorderWidth.top) 
 
2228
    aSkipSides |= (1 << NS_SIDE_TOP);
 
2229
  if (0 == aBorderEdges->mMaxBorderWidth.right) 
 
2230
    aSkipSides |= (1 << NS_SIDE_RIGHT);
 
2231
  if (0 == aBorderEdges->mMaxBorderWidth.bottom) 
 
2232
    aSkipSides |= (1 << NS_SIDE_BOTTOM);
 
2233
  if (0 == aBorderEdges->mMaxBorderWidth.left) 
 
2234
    aSkipSides |= (1 << NS_SIDE_LEFT);
 
2235
 
 
2236
  // Draw any dashed or dotted segments separately
 
2237
  DrawDashedSegments(aRenderingContext, aBorderArea, aBorderEdges, aSkipSides, aGap);
 
2238
 
 
2239
  // Draw all the other sides
 
2240
  nscoord twipsPerPixel;
 
2241
  float p2t;
 
2242
  p2t = aPresContext->PixelsToTwips();
 
2243
  twipsPerPixel = (nscoord) p2t;/* XXX huh!*/
 
2244
 
 
2245
  if (0 == (aSkipSides & (1<<NS_SIDE_TOP))) {
 
2246
    PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_TOP].Count();
 
2247
    PRInt32 i;
 
2248
    nsBorderEdge * leftEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
 
2249
    nscoord x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
 
2250
    for (i=0; i<segmentCount; i++)
 
2251
    {
 
2252
      nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(i));
 
2253
      nscoord y = aBorderArea.y;
 
2254
      if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are bottom-aligned
 
2255
        y += aBorderEdges->mMaxBorderWidth.top - borderEdge->mWidth;
 
2256
      nsRect inside(x, y, borderEdge->mLength, aBorderArea.height);
 
2257
      x += borderEdge->mLength;
 
2258
      nsRect outside(inside);
 
2259
      nsMargin outsideMargin(0, borderEdge->mWidth, 0, 0);
 
2260
      outside.Deflate(outsideMargin);
 
2261
      DrawSide(aRenderingContext, NS_SIDE_TOP,
 
2262
               borderEdge->mStyle,
 
2263
               borderEdge->mColor,
 
2264
               bgColor->mBackgroundColor,
 
2265
               inside, outside,aSkipSides,
 
2266
               twipsPerPixel, aGap);
 
2267
    }
 
2268
  }
 
2269
  if (0 == (aSkipSides & (1<<NS_SIDE_LEFT))) {
 
2270
    PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_LEFT].Count();
 
2271
    PRInt32 i;
 
2272
    nsBorderEdge * topEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(0));
 
2273
    nscoord y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
 
2274
    for (i=0; i<segmentCount; i++)
 
2275
    {
 
2276
      nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(i));
 
2277
      nscoord x = aBorderArea.x + (aBorderEdges->mMaxBorderWidth.left - borderEdge->mWidth);
 
2278
      nsRect inside(x, y, aBorderArea.width, borderEdge->mLength);
 
2279
      y += borderEdge->mLength;
 
2280
      nsRect outside(inside);
 
2281
      nsMargin outsideMargin(borderEdge->mWidth, 0, 0, 0);
 
2282
      outside.Deflate(outsideMargin);
 
2283
      DrawSide(aRenderingContext, NS_SIDE_LEFT,
 
2284
               borderEdge->mStyle,
 
2285
               borderEdge->mColor,
 
2286
               bgColor->mBackgroundColor,
 
2287
               inside, outside, aSkipSides,
 
2288
               twipsPerPixel, aGap);
 
2289
    }
 
2290
  }
 
2291
  if (0 == (aSkipSides & (1<<NS_SIDE_BOTTOM))) {
 
2292
    PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_BOTTOM].Count();
 
2293
    PRInt32 i;
 
2294
    nsBorderEdge * leftEdge =  (nsBorderEdge *)
 
2295
      (aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(aBorderEdges->mEdges[NS_SIDE_LEFT].Count()-1));
 
2296
    nscoord x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
 
2297
    for (i=0; i<segmentCount; i++)
 
2298
    {
 
2299
      nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_BOTTOM].ElementAt(i));
 
2300
      nscoord y = aBorderArea.y;
 
2301
      if (PR_TRUE==aBorderEdges->mOutsideEdge) // segments of the outside edge are top-aligned
 
2302
        y -= (aBorderEdges->mMaxBorderWidth.bottom - borderEdge->mWidth);
 
2303
      nsRect inside(x, y, borderEdge->mLength, aBorderArea.height);
 
2304
      x += borderEdge->mLength;
 
2305
      nsRect outside(inside);
 
2306
      nsMargin outsideMargin(0, 0, 0, borderEdge->mWidth);
 
2307
      outside.Deflate(outsideMargin);
 
2308
      DrawSide(aRenderingContext, NS_SIDE_BOTTOM,
 
2309
               borderEdge->mStyle,
 
2310
               borderEdge->mColor,
 
2311
               bgColor->mBackgroundColor,
 
2312
               inside, outside,aSkipSides,
 
2313
               twipsPerPixel, aGap);
 
2314
    }
 
2315
  }
 
2316
  if (0 == (aSkipSides & (1<<NS_SIDE_RIGHT))) {
 
2317
    PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_RIGHT].Count();
 
2318
    PRInt32 i;
 
2319
    nsBorderEdge * topEdge =  (nsBorderEdge *)
 
2320
      (aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(aBorderEdges->mEdges[NS_SIDE_TOP].Count()-1));
 
2321
    nscoord y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
 
2322
    for (i=0; i<segmentCount; i++)
 
2323
    {
 
2324
      nsBorderEdge * borderEdge =  (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_RIGHT].ElementAt(i));
 
2325
      nscoord width;
 
2326
      if (PR_TRUE==aBorderEdges->mOutsideEdge)
 
2327
      {
 
2328
        width = aBorderArea.width - aBorderEdges->mMaxBorderWidth.right;
 
2329
        width += borderEdge->mWidth;
 
2330
      }
 
2331
      else
 
2332
      {
 
2333
        width = aBorderArea.width;
 
2334
      }
 
2335
      nsRect inside(aBorderArea.x, y, width, borderEdge->mLength);
 
2336
      y += borderEdge->mLength;
 
2337
      nsRect outside(inside);
 
2338
      nsMargin outsideMargin(0, 0, (borderEdge->mWidth), 0);
 
2339
      outside.Deflate(outsideMargin);
 
2340
      DrawSide(aRenderingContext, NS_SIDE_RIGHT,
 
2341
               borderEdge->mStyle,
 
2342
               borderEdge->mColor,
 
2343
               bgColor->mBackgroundColor,
 
2344
               inside, outside,aSkipSides,
 
2345
               twipsPerPixel, aGap);
 
2346
    }
 
2347
  }
 
2348
}
 
2349
 
 
2350
 
 
2351
//----------------------------------------------------------------------
 
2352
 
 
2353
// Returns the anchor point to use for the background image. The
 
2354
// anchor point is the (x, y) location where the first tile should
 
2355
// be placed
 
2356
//
 
2357
// For repeated tiling, the anchor values are normalized wrt to the upper-left
 
2358
// edge of the bounds, and are always in the range:
 
2359
// -(aTileWidth - 1) <= anchor.x <= 0
 
2360
// -(aTileHeight - 1) <= anchor.y <= 0
 
2361
//
 
2362
// i.e., they are either 0 or a negative number whose absolute value is
 
2363
// less than the tile size in that dimension
 
2364
//
 
2365
// aOriginBounds is the box to which the tiling position should be relative
 
2366
// aClipBounds is the box in which the tiling will actually be done
 
2367
// They should correspond to 'background-origin' and 'background-clip',
 
2368
// except when painting on the canvas, in which case the origin bounds
 
2369
// should be the bounds of the root element's frame and the clip bounds
 
2370
// should be the bounds of the canvas frame.
 
2371
static void
 
2372
ComputeBackgroundAnchorPoint(const nsStyleBackground& aColor,
 
2373
                             const nsRect& aOriginBounds,
 
2374
                             const nsRect& aClipBounds,
 
2375
                             nscoord aTileWidth, nscoord aTileHeight,
 
2376
                             nsPoint& aResult)
 
2377
{
 
2378
  nscoord x;
 
2379
  if (NS_STYLE_BG_X_POSITION_LENGTH & aColor.mBackgroundFlags) {
 
2380
    x = aColor.mBackgroundXPosition.mCoord;
 
2381
  }
 
2382
  else if (NS_STYLE_BG_X_POSITION_PERCENT & aColor.mBackgroundFlags) {
 
2383
    PRFloat64 percent = PRFloat64(aColor.mBackgroundXPosition.mFloat);
 
2384
    nscoord tilePos = nscoord(percent * PRFloat64(aTileWidth));
 
2385
    nscoord boxPos = nscoord(percent * PRFloat64(aOriginBounds.width));
 
2386
    x = boxPos - tilePos;
 
2387
  }
 
2388
  else {
 
2389
    x = 0;
 
2390
  }
 
2391
  x += aOriginBounds.x - aClipBounds.x;
 
2392
  if (NS_STYLE_BG_REPEAT_X & aColor.mBackgroundRepeat) {
 
2393
    // When we are tiling in the x direction the loop will run from
 
2394
    // the left edge of the box to the right edge of the box. We need
 
2395
    // to adjust the starting coordinate to lie within the band being
 
2396
    // rendered.
 
2397
    if (x < 0) {
 
2398
      x = -x;
 
2399
      if (x < 0) {
 
2400
        // Some joker gave us max-negative-integer.
 
2401
        x = 0;
 
2402
      }
 
2403
      x %= aTileWidth;
 
2404
      x = -x;
 
2405
    }
 
2406
    else if (x != 0) {
 
2407
      x %= aTileWidth;
 
2408
      if (x > 0) {
 
2409
        x = x - aTileWidth;
 
2410
      }
 
2411
    }
 
2412
 
 
2413
    NS_POSTCONDITION((x >= -(aTileWidth - 1)) && (x <= 0), "bad computed anchor value");
 
2414
  }
 
2415
  aResult.x = x;
 
2416
 
 
2417
  nscoord y;
 
2418
  if (NS_STYLE_BG_Y_POSITION_LENGTH & aColor.mBackgroundFlags) {
 
2419
    y = aColor.mBackgroundYPosition.mCoord;
 
2420
  }
 
2421
  else if (NS_STYLE_BG_Y_POSITION_PERCENT & aColor.mBackgroundFlags){
 
2422
    PRFloat64 percent = PRFloat64(aColor.mBackgroundYPosition.mFloat);
 
2423
    nscoord tilePos = nscoord(percent * PRFloat64(aTileHeight));
 
2424
    nscoord boxPos = nscoord(percent * PRFloat64(aOriginBounds.height));
 
2425
    y = boxPos - tilePos;
 
2426
  }
 
2427
  else {
 
2428
    y = 0;
 
2429
  }
 
2430
  y += aOriginBounds.y - aClipBounds.y;
 
2431
  if (NS_STYLE_BG_REPEAT_Y & aColor.mBackgroundRepeat) {
 
2432
    // When we are tiling in the y direction the loop will run from
 
2433
    // the top edge of the box to the bottom edge of the box. We need
 
2434
    // to adjust the starting coordinate to lie within the band being
 
2435
    // rendered.
 
2436
    if (y < 0) {
 
2437
      y = -y;
 
2438
      if (y < 0) {
 
2439
        // Some joker gave us max-negative-integer.
 
2440
        y = 0;
 
2441
      }
 
2442
      y %= aTileHeight;
 
2443
      y = -y;
 
2444
    }
 
2445
    else if (y != 0) {
 
2446
      y %= aTileHeight;
 
2447
      if (y > 0) {
 
2448
        y = y - aTileHeight;
 
2449
      }
 
2450
    }
 
2451
    
 
2452
    NS_POSTCONDITION((y >= -(aTileHeight - 1)) && (y <= 0), "bad computed anchor value");
 
2453
  }
 
2454
  aResult.y = y;
 
2455
}
 
2456
 
 
2457
// Returns the root scrollable frame, which is the first child of the root
 
2458
// frame.
 
2459
static nsIScrollableFrame*
 
2460
GetRootScrollableFrame(nsIPresContext* aPresContext, nsIFrame* aRootFrame)
 
2461
{
 
2462
  nsIScrollableFrame* scrollableFrame = nsnull;
 
2463
 
 
2464
  if (nsLayoutAtoms::viewportFrame == aRootFrame->GetType()) {
 
2465
    nsIFrame* childFrame = aRootFrame->GetFirstChild(nsnull);
 
2466
 
 
2467
    if (childFrame) {
 
2468
      if (nsLayoutAtoms::scrollFrame == childFrame->GetType()) {
 
2469
        // Use this frame, even if we are using GFX frames for the
 
2470
        // viewport, which contains another scroll frame below this
 
2471
        // frame, since the GFX scrollport frame does not implement
 
2472
        // nsIScrollableFrame.
 
2473
        CallQueryInterface(childFrame, &scrollableFrame);
 
2474
      }
 
2475
    }
 
2476
  }
 
2477
#ifdef DEBUG
 
2478
  else {
 
2479
    NS_WARNING("aRootFrame is not a viewport frame");
 
2480
  }
 
2481
#endif // DEBUG
 
2482
 
 
2483
  return scrollableFrame;
 
2484
}
 
2485
 
 
2486
const nsStyleBackground*
 
2487
nsCSSRendering::FindNonTransparentBackground(nsStyleContext* aContext,
 
2488
                                             PRBool aStartAtParent /*= PR_FALSE*/)
 
2489
{
 
2490
  NS_ASSERTION(aContext, "Cannot find NonTransparentBackground in a null context" );
 
2491
  
 
2492
  const nsStyleBackground* result = nsnull;
 
2493
  nsStyleContext* context = nsnull;
 
2494
  if (aStartAtParent) {
 
2495
    context = aContext->GetParent();
 
2496
  }
 
2497
  if (!context) {
 
2498
    context = aContext;
 
2499
  }
 
2500
  
 
2501
  while (context) {
 
2502
    result = context->GetStyleBackground();
 
2503
    if (0 == (result->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT))
 
2504
      break;
 
2505
 
 
2506
    context = context->GetParent();
 
2507
  }
 
2508
  return result;
 
2509
}
 
2510
 
 
2511
 
 
2512
/**
 
2513
 * |FindBackground| finds the correct style data to use to paint the
 
2514
 * background.  It is responsible for handling the following two
 
2515
 * statements in section 14.2 of CSS2:
 
2516
 *
 
2517
 *   The background of the box generated by the root element covers the
 
2518
 *   entire canvas.
 
2519
 *
 
2520
 *   For HTML documents, however, we recommend that authors specify the
 
2521
 *   background for the BODY element rather than the HTML element. User
 
2522
 *   agents should observe the following precedence rules to fill in the
 
2523
 *   background: if the value of the 'background' property for the HTML
 
2524
 *   element is different from 'transparent' then use it, else use the
 
2525
 *   value of the 'background' property for the BODY element. If the
 
2526
 *   resulting value is 'transparent', the rendering is undefined.
 
2527
 *
 
2528
 * Thus, in our implementation, it is responsible for ensuring that:
 
2529
 *  + we paint the correct background on the |nsCanvasFrame|,
 
2530
 *    |nsRootBoxFrame|, or |nsPageFrame|,
 
2531
 *  + we don't paint the background on the root element, and
 
2532
 *  + we don't paint the background on the BODY element in *some* cases,
 
2533
 *    and for SGML-based HTML documents only.
 
2534
 *
 
2535
 * |FindBackground| returns true if a background should be painted, and
 
2536
 * the resulting style context to use for the background information
 
2537
 * will be filled in to |aBackground|.  It fills in a boolean indicating
 
2538
 * whether the frame is the canvas frame to allow PaintBackground to
 
2539
 * ensure that it always paints something non-transparent for the
 
2540
 * canvas.
 
2541
 */
 
2542
 
 
2543
// Returns nsnull if aFrame is not a canvas frame.
 
2544
// Otherwise, it returns the frame we should look for the background on.
 
2545
// This is normally aFrame but if aFrame is the viewport, we need to
 
2546
// look for the background starting at the scroll root (which shares
 
2547
// style context with the document root) or the document root itself.
 
2548
// We need to treat the viewport as canvas because, even though
 
2549
// it does not actually paint a background, we need to get the right
 
2550
// background style so we correctly detect transparent documents.
 
2551
inline nsIFrame*
 
2552
IsCanvasFrame(nsIPresContext* aPresContext, nsIFrame *aFrame)
 
2553
{
 
2554
  nsIAtom* frameType = aFrame->GetType();
 
2555
  if (frameType == nsLayoutAtoms::canvasFrame ||
 
2556
      frameType == nsLayoutAtoms::rootFrame ||
 
2557
      frameType == nsLayoutAtoms::pageFrame) {
 
2558
    return aFrame;
 
2559
  } else if (frameType == nsLayoutAtoms::viewportFrame) {
 
2560
    nsIFrame* firstChild = aFrame->GetFirstChild(nsnull);
 
2561
    if (firstChild) {
 
2562
      return firstChild;
 
2563
    }
 
2564
  }
 
2565
  
 
2566
  return nsnull;
 
2567
}
 
2568
 
 
2569
inline PRBool
 
2570
FindCanvasBackground(nsIPresContext* aPresContext,
 
2571
                     nsIFrame* aForFrame,
 
2572
                     const nsStyleBackground** aBackground)
 
2573
{
 
2574
  // XXXldb What if the root element is positioned, etc.?  (We don't
 
2575
  // allow that yet, do we?)
 
2576
  nsIFrame *firstChild = aForFrame->GetFirstChild(nsnull);
 
2577
  if (firstChild) {
 
2578
    const nsStyleBackground* result = firstChild->GetStyleBackground();
 
2579
  
 
2580
    // for printing and print preview.. this should be a pageContentFrame
 
2581
    nsStyleContext* parentContext;
 
2582
 
 
2583
    if (firstChild->GetType() == nsLayoutAtoms::pageContentFrame) {
 
2584
      // we have to find the background style ourselves.. since the 
 
2585
      // pageContentframe does not have content
 
2586
      while(firstChild){
 
2587
        for (nsIFrame* kidFrame = firstChild; nsnull != kidFrame; ) {
 
2588
          parentContext = kidFrame->GetStyleContext();
 
2589
          result = parentContext->GetStyleBackground();
 
2590
          if (!result->IsTransparent()) {
 
2591
            *aBackground = kidFrame->GetStyleBackground();
 
2592
            return PR_TRUE;
 
2593
          } else {
 
2594
            kidFrame = kidFrame->GetNextSibling(); 
 
2595
          }
 
2596
        }
 
2597
        firstChild = firstChild->GetFirstChild(nsnull);
 
2598
      }
 
2599
      return PR_FALSE;    // nothing found for this
 
2600
    }
 
2601
 
 
2602
    // Check if we need to do propagation from BODY rather than HTML.
 
2603
    if (result->IsTransparent()) {
 
2604
      nsIContent* content = aForFrame->GetContent();
 
2605
      if (content) {
 
2606
        nsCOMPtr<nsIDOMNode> node( do_QueryInterface(content) );
 
2607
        // Use |GetOwnerDocument| so it works during destruction.
 
2608
        nsCOMPtr<nsIDOMDocument> doc;
 
2609
        node->GetOwnerDocument(getter_AddRefs(doc));
 
2610
        nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(doc);
 
2611
        if (htmlDoc) {
 
2612
          nsCOMPtr<nsIDocument> document = do_QueryInterface(doc);
 
2613
          if (!document->IsCaseSensitive()) { // HTML, not XHTML
 
2614
            nsCOMPtr<nsIDOMHTMLElement> body;
 
2615
            htmlDoc->GetBody(getter_AddRefs(body));
 
2616
            nsCOMPtr<nsIContent> bodyContent = do_QueryInterface(body);
 
2617
            // We need to null check the body node (bug 118829) since
 
2618
            // there are cases, thanks to the fix for bug 5569, where we
 
2619
            // will reflow a document with no body.  In particular, if a
 
2620
            // SCRIPT element in the head blocks the parser and then has a
 
2621
            // SCRIPT that does "document.location.href = 'foo'", then
 
2622
            // nsParser::Terminate will call |DidBuildModel| methods
 
2623
            // through to the content sink, which will call |StartLayout|
 
2624
            // and thus |InitialReflow| on the pres shell.  See bug 119351
 
2625
            // for the ugly details.
 
2626
            if (bodyContent) {
 
2627
              nsIFrame *bodyFrame;
 
2628
              nsresult rv = aPresContext->PresShell()->
 
2629
                GetPrimaryFrameFor(bodyContent, &bodyFrame);
 
2630
              if (NS_SUCCEEDED(rv) && bodyFrame)
 
2631
                result = bodyFrame->GetStyleBackground();
 
2632
            }
 
2633
          }
 
2634
        }
 
2635
      }
 
2636
    }
 
2637
 
 
2638
    *aBackground = result;
 
2639
  } else {
 
2640
    // This should always give transparent, so we'll fill it in with the
 
2641
    // default color if needed.  This seems to happen a bit while a page is
 
2642
    // being loaded.
 
2643
    *aBackground = aForFrame->GetStyleBackground();
 
2644
  }
 
2645
  
 
2646
  return PR_TRUE;
 
2647
}
 
2648
 
 
2649
inline PRBool
 
2650
FindElementBackground(nsIPresContext* aPresContext,
 
2651
                      nsIFrame* aForFrame,
 
2652
                      const nsStyleBackground** aBackground)
 
2653
{
 
2654
  nsIFrame *parentFrame = aForFrame->GetParent();
 
2655
  // XXXldb We shouldn't have to null-check |parentFrame| here.
 
2656
  if (parentFrame && IsCanvasFrame(aPresContext, parentFrame) == parentFrame) {
 
2657
    // Check that we're really the root (rather than in another child list).
 
2658
    nsIFrame *childFrame = parentFrame->GetFirstChild(nsnull);
 
2659
    if (childFrame == aForFrame)
 
2660
      return PR_FALSE; // Background was already drawn for the canvas.
 
2661
  }
 
2662
 
 
2663
  *aBackground = aForFrame->GetStyleBackground();
 
2664
 
 
2665
  nsIContent* content = aForFrame->GetContent();
 
2666
  if (!content || !content->IsContentOfType(nsIContent::eHTML))
 
2667
    return PR_TRUE;  // not frame for an HTML element
 
2668
 
 
2669
  if (!parentFrame)
 
2670
    return PR_TRUE; // no parent to look at
 
2671
 
 
2672
  if (content->Tag() != nsHTMLAtoms::body)
 
2673
    return PR_TRUE; // not frame for <BODY> element
 
2674
 
 
2675
  // We should only look at the <html> background if we're in an HTML document
 
2676
  nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
 
2677
  nsCOMPtr<nsIDOMDocument> doc;
 
2678
  node->GetOwnerDocument(getter_AddRefs(doc));
 
2679
  nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(doc));
 
2680
  if (!htmlDoc)
 
2681
    return PR_TRUE;
 
2682
 
 
2683
  nsCOMPtr<nsIDocument> document(do_QueryInterface(doc));
 
2684
  if (document->IsCaseSensitive()) // XHTML, not HTML
 
2685
    return PR_TRUE;
 
2686
  
 
2687
  const nsStyleBackground* htmlBG = parentFrame->GetStyleBackground();
 
2688
  return !htmlBG->IsTransparent();
 
2689
}
 
2690
 
 
2691
PRBool
 
2692
nsCSSRendering::FindBackground(nsIPresContext* aPresContext,
 
2693
                               nsIFrame* aForFrame,
 
2694
                               const nsStyleBackground** aBackground,
 
2695
                               PRBool* aIsCanvas)
 
2696
{
 
2697
  nsIFrame* canvasFrame = IsCanvasFrame(aPresContext, aForFrame);
 
2698
  *aIsCanvas = canvasFrame != nsnull;
 
2699
  return canvasFrame
 
2700
      ? FindCanvasBackground(aPresContext, canvasFrame, aBackground)
 
2701
      : FindElementBackground(aPresContext, aForFrame, aBackground);
 
2702
}
 
2703
 
 
2704
void
 
2705
nsCSSRendering::DidPaint()
 
2706
{
 
2707
  gInlineBGData.Reset();
 
2708
}
 
2709
 
 
2710
void
 
2711
nsCSSRendering::PaintBackground(nsIPresContext* aPresContext,
 
2712
                                nsIRenderingContext& aRenderingContext,
 
2713
                                nsIFrame* aForFrame,
 
2714
                                const nsRect& aDirtyRect,
 
2715
                                const nsRect& aBorderArea,
 
2716
                                const nsStyleBorder& aBorder,
 
2717
                                const nsStylePadding& aPadding,
 
2718
                                PRBool aUsePrintSettings,
 
2719
                                nsRect* aBGClipRect)
 
2720
{
 
2721
  NS_PRECONDITION(aForFrame,
 
2722
                  "Frame is expected to be provided to PaintBackground");
 
2723
 
 
2724
  PRBool isCanvas;
 
2725
  const nsStyleBackground *color;
 
2726
 
 
2727
  if (!FindBackground(aPresContext, aForFrame, &color, &isCanvas)) {
 
2728
    // we don't want to bail out of moz-appearance is set on a root
 
2729
    // node. If it has a parent content node, bail because it's not
 
2730
    // a root, other wise keep going in order to let the theme stuff
 
2731
    // draw the background. The canvas really should be drawing the
 
2732
    // bg, but there's no way to hook that up via css.
 
2733
    if (!aForFrame->GetStyleDisplay()->mAppearance) {
 
2734
      return;
 
2735
    }
 
2736
 
 
2737
    nsIContent* content = aForFrame->GetContent();
 
2738
    if (!content || content->GetParent()) {
 
2739
      return;
 
2740
    }
 
2741
        
 
2742
    color = aForFrame->GetStyleBackground();
 
2743
  }
 
2744
  if (!isCanvas) {
 
2745
    PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
 
2746
                          aDirtyRect, aBorderArea, *color, aBorder,
 
2747
                          aPadding, aUsePrintSettings, aBGClipRect);
 
2748
    return;
 
2749
  }
 
2750
 
 
2751
  if (!color)
 
2752
    return;
 
2753
  nsStyleBackground canvasColor(*color);
 
2754
 
 
2755
  nsIViewManager* vm = aPresContext->GetViewManager();
 
2756
 
 
2757
  if (canvasColor.mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) {
 
2758
    nsIView* rootView;
 
2759
    vm->GetRootView(rootView);
 
2760
    if (!rootView->GetParent()) {
 
2761
      PRBool widgetIsTranslucent = PR_FALSE;
 
2762
 
 
2763
      if (rootView->HasWidget()) {
 
2764
        rootView->GetWidget()->GetWindowTranslucency(widgetIsTranslucent);
 
2765
      }
 
2766
      
 
2767
      if (!widgetIsTranslucent) {
 
2768
        // Ensure that we always paint a color for the root (in case there's
 
2769
        // no background at all or a partly transparent image).
 
2770
        canvasColor.mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT;
 
2771
        canvasColor.mBackgroundColor = aPresContext->DefaultBackgroundColor();
 
2772
      }
 
2773
    }
 
2774
  }
 
2775
 
 
2776
  vm->SetDefaultBackgroundColor(canvasColor.mBackgroundColor);
 
2777
 
 
2778
  // Since nsHTMLContainerFrame::CreateViewForFrame might have created
 
2779
  // the view before we knew about the child with the fixed background
 
2780
  // attachment (root or BODY) or the stylesheet specifying that
 
2781
  // attachment, set the BitBlt flag here as well.
 
2782
  if (canvasColor.mBackgroundAttachment == NS_STYLE_BG_ATTACHMENT_FIXED) {
 
2783
    nsIView *view = aForFrame->GetView();
 
2784
    if (view)
 
2785
      vm->SetViewBitBltEnabled(view, PR_FALSE);
 
2786
  }
 
2787
 
 
2788
  PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
 
2789
                        aDirtyRect, aBorderArea, canvasColor,
 
2790
                        aBorder, aPadding, aUsePrintSettings, aBGClipRect);
 
2791
}
 
2792
 
 
2793
void
 
2794
nsCSSRendering::PaintBackgroundWithSC(nsIPresContext* aPresContext,
 
2795
                                      nsIRenderingContext& aRenderingContext,
 
2796
                                      nsIFrame* aForFrame,
 
2797
                                      const nsRect& aDirtyRect,
 
2798
                                      const nsRect& aBorderArea,
 
2799
                                      const nsStyleBackground& aColor,
 
2800
                                      const nsStyleBorder& aBorder,
 
2801
                                      const nsStylePadding& aPadding,
 
2802
                                      PRBool aUsePrintSettings,
 
2803
                                      nsRect* aBGClipRect)
 
2804
{
 
2805
  NS_PRECONDITION(aForFrame,
 
2806
                  "Frame is expected to be provided to PaintBackground");
 
2807
 
 
2808
  PRBool canDrawBackgroundImage = PR_TRUE;
 
2809
  PRBool canDrawBackgroundColor = PR_TRUE;
 
2810
 
 
2811
  if (aUsePrintSettings) {
 
2812
    canDrawBackgroundImage = aPresContext->GetBackgroundImageDraw();
 
2813
    canDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
 
2814
  }
 
2815
 
 
2816
  // Check to see if we have an appearance defined.  If so, we let the theme
 
2817
  // renderer draw the background and bail out.
 
2818
  const nsStyleDisplay* displayData = aForFrame->GetStyleDisplay();
 
2819
  if (displayData->mAppearance) {
 
2820
    nsCOMPtr<nsITheme> theme;
 
2821
    aPresContext->GetTheme(getter_AddRefs(theme));
 
2822
    if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame, displayData->mAppearance)) {
 
2823
      theme->DrawWidgetBackground(&aRenderingContext, aForFrame, 
 
2824
                                  displayData->mAppearance, aBorderArea, aDirtyRect); 
 
2825
      return;
 
2826
    }
 
2827
  }
 
2828
 
 
2829
  nsRect bgClipArea;
 
2830
  if (aBGClipRect) {
 
2831
    bgClipArea = *aBGClipRect;
 
2832
  }
 
2833
  else {
 
2834
    // The background is rendered over the 'background-clip' area.
 
2835
    bgClipArea = aBorderArea;
 
2836
    if (aColor.mBackgroundClip != NS_STYLE_BG_CLIP_BORDER) {
 
2837
      NS_ASSERTION(aColor.mBackgroundClip == NS_STYLE_BG_CLIP_PADDING,
 
2838
                   "unknown background-clip value");
 
2839
      nsMargin border;
 
2840
      aBorder.GetBorder(border);
 
2841
      bgClipArea.Deflate(border);
 
2842
    }
 
2843
  }
 
2844
 
 
2845
  // The actual dirty rect is the intersection of the 'background-clip'
 
2846
  // area and the dirty rect we were given
 
2847
  nsRect dirtyRect;
 
2848
  if (!dirtyRect.IntersectRect(bgClipArea, aDirtyRect)) {
 
2849
    // Nothing to paint
 
2850
    return;
 
2851
  }
 
2852
 
 
2853
  // if there is no background image or background images are turned off, try a color.
 
2854
  if (!aColor.mBackgroundImage || !canDrawBackgroundImage) {
 
2855
    PaintBackgroundColor(aPresContext, aRenderingContext, aForFrame, bgClipArea,
 
2856
                         aColor, aBorder, aPadding, canDrawBackgroundColor);
 
2857
    return;
 
2858
  }
 
2859
 
 
2860
  // We have a background image
 
2861
 
 
2862
  // Lookup the image
 
2863
  nsCOMPtr<imgIRequest> req;
 
2864
  nsresult rv = aPresContext->LoadImage(aColor.mBackgroundImage, aForFrame, getter_AddRefs(req));
 
2865
 
 
2866
  PRUint32 status = imgIRequest::STATUS_ERROR;
 
2867
  if (req)
 
2868
    req->GetImageStatus(&status);
 
2869
 
 
2870
  if (NS_FAILED(rv) || !req || !(status & imgIRequest::STATUS_FRAME_COMPLETE) || !(status & imgIRequest::STATUS_SIZE_AVAILABLE)) {
 
2871
    PaintBackgroundColor(aPresContext, aRenderingContext, aForFrame, bgClipArea,
 
2872
                         aColor, aBorder, aPadding, canDrawBackgroundColor);
 
2873
    return;
 
2874
  }
 
2875
 
 
2876
  nsCOMPtr<imgIContainer> image;
 
2877
  req->GetImage(getter_AddRefs(image));
 
2878
 
 
2879
  nsSize imageSize;
 
2880
  image->GetWidth(&imageSize.width);
 
2881
  image->GetHeight(&imageSize.height);
 
2882
 
 
2883
  float p2t;
 
2884
  p2t = aPresContext->PixelsToTwips();
 
2885
  imageSize.width = NSIntPixelsToTwips(imageSize.width, p2t);
 
2886
  imageSize.height = NSIntPixelsToTwips(imageSize.height, p2t);
 
2887
 
 
2888
  req = nsnull;
 
2889
 
 
2890
  nsRect bgOriginArea;
 
2891
 
 
2892
  nsIAtom* frameType = aForFrame->GetType();
 
2893
  if (frameType == nsLayoutAtoms::inlineFrame) {
 
2894
    switch (aColor.mBackgroundInlinePolicy) {
 
2895
    case NS_STYLE_BG_INLINE_POLICY_EACH_BOX:
 
2896
      bgOriginArea = aBorderArea;
 
2897
      break;
 
2898
    case NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX:
 
2899
      bgOriginArea = gInlineBGData.GetBoundingRect(aForFrame);
 
2900
      break;
 
2901
    default:
 
2902
      NS_ERROR("Unknown background-inline-policy value!  "
 
2903
               "Please, teach me what to do.");
 
2904
    case NS_STYLE_BG_INLINE_POLICY_CONTINUOUS:
 
2905
      bgOriginArea = gInlineBGData.GetContinuousRect(aForFrame);
 
2906
      break;
 
2907
    }
 
2908
  }
 
2909
  else {
 
2910
    bgOriginArea = aBorderArea;
 
2911
  }
 
2912
 
 
2913
  // Background images are tiled over the 'background-clip' area
 
2914
  // but the origin of the tiling is based on the 'background-origin' area
 
2915
  if (aColor.mBackgroundOrigin != NS_STYLE_BG_ORIGIN_BORDER) {
 
2916
    nsMargin border;
 
2917
    if (!aBorder.GetBorder(border)) {
 
2918
      NS_NOTYETIMPLEMENTED("percentage border");
 
2919
    }
 
2920
 
 
2921
    bgOriginArea.Deflate(border);
 
2922
    if (aColor.mBackgroundOrigin != NS_STYLE_BG_ORIGIN_PADDING) {
 
2923
      nsMargin padding;
 
2924
      // XXX CalcPaddingFor is deprecated, but we need it for percentage padding
 
2925
      aPadding.CalcPaddingFor(aForFrame, padding);
 
2926
      bgOriginArea.Deflate(padding);
 
2927
      NS_ASSERTION(aColor.mBackgroundOrigin == NS_STYLE_BG_ORIGIN_CONTENT,
 
2928
                   "unknown background-origin value");
 
2929
    }
 
2930
  }
 
2931
 
 
2932
  // Based on the repeat setting, compute how many tiles we should
 
2933
  // lay down for each axis. The value computed is the maximum based
 
2934
  // on the dirty rect before accounting for the background-position.
 
2935
  nscoord tileWidth = imageSize.width;
 
2936
  nscoord tileHeight = imageSize.height;
 
2937
  PRBool  needBackgroundColor = !(aColor.mBackgroundFlags &
 
2938
                                  NS_STYLE_BG_COLOR_TRANSPARENT);
 
2939
  PRIntn  repeat = aColor.mBackgroundRepeat;
 
2940
  nscoord xDistance, yDistance;
 
2941
 
 
2942
  switch (repeat) {
 
2943
    case NS_STYLE_BG_REPEAT_X:
 
2944
      xDistance = dirtyRect.width;
 
2945
      yDistance = tileHeight;
 
2946
      break;
 
2947
    case NS_STYLE_BG_REPEAT_Y:
 
2948
      xDistance = tileWidth;
 
2949
      yDistance = dirtyRect.height;
 
2950
      break;
 
2951
    case NS_STYLE_BG_REPEAT_XY:
 
2952
      xDistance = dirtyRect.width;
 
2953
      yDistance = dirtyRect.height;
 
2954
      if (needBackgroundColor) {
 
2955
        // If the image is completely opaque, we do not need to paint the
 
2956
        // background color
 
2957
        nsCOMPtr<gfxIImageFrame> gfxImgFrame;
 
2958
        image->GetCurrentFrame(getter_AddRefs(gfxImgFrame));
 
2959
        if (gfxImgFrame) {
 
2960
          gfx_format frameFormat;
 
2961
          gfxImgFrame->GetFormat(&frameFormat);
 
2962
          NS_ASSERTION(frameFormat >= 0 && frameFormat <= 7,
 
2963
                       "Unknown gfxIFormats value");
 
2964
          needBackgroundColor = frameFormat != gfxIFormats::RGB &&
 
2965
                                frameFormat != gfxIFormats::BGR;
 
2966
 
 
2967
          /* check for tiling of a image where frame smaller than container */
 
2968
          nsSize iSize;
 
2969
          image->GetWidth(&iSize.width);
 
2970
          image->GetHeight(&iSize.height);
 
2971
          nsRect iframeRect;
 
2972
          gfxImgFrame->GetRect(iframeRect);
 
2973
          if (iSize.width != iframeRect.width ||
 
2974
              iSize.height != iframeRect.height) {
 
2975
            needBackgroundColor = PR_TRUE;
 
2976
          }
 
2977
        }
 
2978
      }
 
2979
      break;
 
2980
    case NS_STYLE_BG_REPEAT_OFF:
 
2981
    default:
 
2982
      NS_ASSERTION(repeat == NS_STYLE_BG_REPEAT_OFF, "unknown background-repeat value");
 
2983
      xDistance = tileWidth;
 
2984
      yDistance = tileHeight;
 
2985
      break;
 
2986
  }
 
2987
 
 
2988
  // The background color is rendered over the 'background-clip' area
 
2989
  if (needBackgroundColor) {
 
2990
    PaintBackgroundColor(aPresContext, aRenderingContext, aForFrame, bgClipArea,
 
2991
                         aColor, aBorder, aPadding, canDrawBackgroundColor);
 
2992
  }
 
2993
 
 
2994
  if ((tileWidth == 0) || (tileHeight == 0) || dirtyRect.IsEmpty()) {
 
2995
    // Nothing left to paint
 
2996
    return;
 
2997
  }
 
2998
 
 
2999
  // Compute the anchor point.
 
3000
  //
 
3001
  // When tiling, the anchor coordinate values will be negative offsets
 
3002
  // from the background-origin area.
 
3003
 
 
3004
  nsPoint anchor;
 
3005
  if (NS_STYLE_BG_ATTACHMENT_FIXED == aColor.mBackgroundAttachment) {
 
3006
    // If it's a fixed background attachment, then the image is placed 
 
3007
    // relative to the viewport
 
3008
    nsIView* viewportView = nsnull;
 
3009
    nsRect viewportArea;
 
3010
 
 
3011
    nsIFrame* rootFrame;
 
3012
    aPresContext->PresShell()->GetRootFrame(&rootFrame);
 
3013
    NS_ASSERTION(rootFrame, "no root frame");
 
3014
 
 
3015
    if (aPresContext->IsPaginated()) {
 
3016
      nsIFrame* page = nsLayoutUtils::GetPageFrame(aForFrame);
 
3017
      NS_ASSERTION(page, "no page");
 
3018
      rootFrame = page;
 
3019
    }
 
3020
 
 
3021
    viewportView = rootFrame->GetView();
 
3022
    NS_ASSERTION(viewportView, "no viewport view");
 
3023
    viewportArea = viewportView->GetBounds();
 
3024
    viewportArea.x = 0;
 
3025
    viewportArea.y = 0;
 
3026
 
 
3027
    nsIScrollableFrame* scrollableFrame =
 
3028
      GetRootScrollableFrame(aPresContext, rootFrame);
 
3029
 
 
3030
    if (scrollableFrame) {
 
3031
      nsMargin scrollbars = scrollableFrame->GetActualScrollbarSizes();
 
3032
      viewportArea.Deflate(scrollbars);
 
3033
    }
 
3034
 
 
3035
    // Get the anchor point
 
3036
    ComputeBackgroundAnchorPoint(aColor, viewportArea, viewportArea, tileWidth, tileHeight, anchor);
 
3037
 
 
3038
    // Convert the anchor point to aForFrame's coordinate space
 
3039
    nsIView* view = aForFrame->GetView();
 
3040
    if (!view) {
 
3041
      nsPoint offset;
 
3042
      aForFrame->GetOffsetFromView(aPresContext, offset, &view);
 
3043
      anchor -= offset;
 
3044
    }
 
3045
    NS_ASSERTION(view, "expected a view");
 
3046
    while (view && (view != viewportView)) {
 
3047
      anchor -= view->GetPosition();
 
3048
      // Get the parent view until we reach the viewport view
 
3049
      view = view->GetParent();
 
3050
    }
 
3051
  } else {
 
3052
    if (frameType == nsLayoutAtoms::canvasFrame) {
 
3053
      // If the frame is the canvas, the image is placed relative to
 
3054
      // the root element's (first) frame (see bug 46446)
 
3055
      nsRect firstRootElementFrameArea;
 
3056
      nsIFrame* firstRootElementFrame = aForFrame->GetFirstChild(nsnull);
 
3057
      NS_ASSERTION(firstRootElementFrame, "A canvas with a background "
 
3058
        "image had no child frame, which is impossible according to CSS. "
 
3059
        "Make sure there isn't a background image specified on the "
 
3060
        "|:viewport| pseudo-element in |html.css|.");
 
3061
 
 
3062
      // temporary null check -- see bug 97226
 
3063
      if (firstRootElementFrame) {
 
3064
        firstRootElementFrameArea = firstRootElementFrame->GetRect();
 
3065
 
 
3066
        // Take the border out of the frame's rect
 
3067
        const nsStyleBorder* borderStyle = firstRootElementFrame->GetStyleBorder();
 
3068
        nsMargin border;
 
3069
        borderStyle->GetBorder(border);
 
3070
        firstRootElementFrameArea.Deflate(border);
 
3071
 
 
3072
        // Get the anchor point
 
3073
        ComputeBackgroundAnchorPoint(aColor, firstRootElementFrameArea, bgClipArea, tileWidth, tileHeight, anchor);
 
3074
      } else {
 
3075
        ComputeBackgroundAnchorPoint(aColor, bgOriginArea, bgClipArea, tileWidth, tileHeight, anchor);
 
3076
      }
 
3077
    } else {
 
3078
      // Otherwise, it is the normal case, and the background is
 
3079
      // simply placed relative to the frame's background-clip area
 
3080
      ComputeBackgroundAnchorPoint(aColor, bgOriginArea, bgClipArea, tileWidth, tileHeight, anchor);
 
3081
    }
 
3082
  }
 
3083
 
 
3084
 
 
3085
#if (!defined(XP_UNIX) && !defined(XP_BEOS)) || defined(XP_MACOSX)
 
3086
  // Setup clipping so that rendering doesn't leak out of the computed
 
3087
  // dirty rect
 
3088
  PRBool clipState;
 
3089
  aRenderingContext.PushState();
 
3090
  aRenderingContext.SetClipRect(dirtyRect, nsClipCombine_kIntersect,
 
3091
                                clipState);
 
3092
#endif
 
3093
 
 
3094
  // Compute the x and y starting points and limits for tiling
 
3095
 
 
3096
  /* An Overview Of The Following Logic
 
3097
 
 
3098
          A........ . . . . . . . . . . . . . .
 
3099
          :   +---:-------.-------.-------.----  /|\
 
3100
          :   |   :       .       .       .       |  nh 
 
3101
          :.......: . . . x . . . . . . . . . .  \|/   
 
3102
          .   |   .       .       .       .        
 
3103
          .   |   .       .  ###########  .        
 
3104
          . . . . . . . . . .#. . . . .#. . . .     
 
3105
          .   |   .       .  ###########  .      /|\
 
3106
          .   |   .       .       .       .       |  h
 
3107
          . . | . . . . . . . . . . . . . z . .  \|/
 
3108
          .   |   .       .       .       .    
 
3109
          |<-----nw------>|       |<--w-->|
 
3110
 
 
3111
       ---- = the background clip area edge. The painting is done within
 
3112
              to this area.  If the background is positioned relative to the 
 
3113
              viewport ('fixed') then this is the viewport edge.
 
3114
 
 
3115
       .... = the primary tile.
 
3116
 
 
3117
       . .  = the other tiles.
 
3118
 
 
3119
       #### = the dirtyRect. This is the minimum region we want to cover.
 
3120
 
 
3121
          A = The anchor point. This is the point at which the tile should
 
3122
              start. Always negative or zero.
 
3123
 
 
3124
          x = x0 and y0 in the code. The point at which tiling must start
 
3125
              so that the fewest tiles are laid out while completly
 
3126
              covering the dirtyRect area.
 
3127
 
 
3128
          z = x1 and y1 in the code. The point at which tiling must end so
 
3129
              that the fewest tiles are laid out while completly covering
 
3130
              the dirtyRect area.
 
3131
 
 
3132
          w = the width of the tile (tileWidth).
 
3133
 
 
3134
          h = the height of the tile (tileHeight).
 
3135
 
 
3136
          n = the number of whole tiles that fit between 'A' and 'x'.
 
3137
              (the vertical n and the horizontal n are different)
 
3138
 
 
3139
 
 
3140
       Therefore, 
 
3141
 
 
3142
          x0 = bgClipArea.x + anchor.x + n * tileWidth;
 
3143
 
 
3144
       ...where n is an integer greater or equal to 0 fitting:
 
3145
 
 
3146
          n * tileWidth <= 
 
3147
                      dirtyRect.x - (bgClipArea.x + anchor.x) <=
 
3148
                                                             (n+1) * tileWidth
 
3149
 
 
3150
       ...i.e.,
 
3151
 
 
3152
          n <= (dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth < n + 1
 
3153
 
 
3154
       ...which, treating the division as an integer divide rounding down, gives:
 
3155
 
 
3156
          n = (dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth
 
3157
 
 
3158
       Substituting into the original expression for x0:
 
3159
 
 
3160
          x0 = bgClipArea.x + anchor.x +
 
3161
               ((dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth) *
 
3162
               tileWidth;
 
3163
 
 
3164
       From this x1 is determined,
 
3165
 
 
3166
          x1 = x0 + m * tileWidth;
 
3167
 
 
3168
       ...where m is an integer greater than 0 fitting:
 
3169
 
 
3170
          (m - 1) * tileWidth <
 
3171
                            dirtyRect.x + dirtyRect.width - x0 <=
 
3172
                                                               m * tileWidth
 
3173
 
 
3174
       ...i.e.,
 
3175
 
 
3176
          m - 1 < (dirtyRect.x + dirtyRect.width - x0) / tileWidth <= m
 
3177
 
 
3178
       ...which, treating the division as an integer divide, and making it
 
3179
          round up, gives:
 
3180
 
 
3181
          m = (dirtyRect.x + dirtyRect.width - x0 + tileWidth - 1) / tileWidth
 
3182
 
 
3183
       Substituting into the original expression for x1:
 
3184
 
 
3185
          x1 = x0 + ((dirtyRect.x + dirtyRect.width - x0 + tileWidth - 1) /
 
3186
                     tileWidth) * tileWidth
 
3187
 
 
3188
       The vertical case is analogous. If the background is fixed, then 
 
3189
       bgClipArea.x and bgClipArea.y are set to zero when finding the parent
 
3190
       viewport, above.
 
3191
 
 
3192
  */
 
3193
 
 
3194
  // first do the horizontal case
 
3195
  nscoord x0, x1;
 
3196
  // For scrolling attachment, the anchor is within the 'background-clip'
 
3197
  // For fixed attachment, the anchor is within the bounds of the nearest
 
3198
  // scrolling ancestor (or the viewport)
 
3199
  x0 = (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) ?
 
3200
       bgClipArea.x : 0;
 
3201
  if (repeat & NS_STYLE_BG_REPEAT_X) {
 
3202
    // When tiling in the x direction, adjust the starting position of the
 
3203
    // tile to account for dirtyRect.x. When tiling in x, the anchor.x value
 
3204
    // will be a negative value used to adjust the starting coordinate.
 
3205
    x0 += anchor.x + 
 
3206
          ((dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth) * tileWidth;
 
3207
    x1 = x0 + ((dirtyRect.x + dirtyRect.width - x0 + tileWidth - 1) / tileWidth) * tileWidth;
 
3208
  }
 
3209
  else {
 
3210
    x0 += anchor.x;
 
3211
    x1 = x0 + tileWidth;
 
3212
  }
 
3213
 
 
3214
  // now do all that again with the vertical case
 
3215
  nscoord y0, y1;
 
3216
  // For scrolling attachment, the anchor is within the 'background-clip'
 
3217
  // For fixed attachment, the anchor is within the bounds of the nearest
 
3218
  // scrolling ancestor (or the viewport)
 
3219
  y0 = (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) ?
 
3220
       bgClipArea.y : 0;
 
3221
  if (repeat & NS_STYLE_BG_REPEAT_Y) {
 
3222
    // When tiling in the y direction, adjust the starting position of the
 
3223
    // tile to account for dirtyRect.y. When tiling in y, the anchor.y value
 
3224
    // will be a negative value used to adjust the starting coordinate.
 
3225
    y0 += anchor.y + 
 
3226
          ((dirtyRect.y - (bgClipArea.y + anchor.y)) / tileHeight) * tileHeight;
 
3227
    y1 = y0 + ((dirtyRect.y + dirtyRect.height - y0 + tileHeight - 1) / tileHeight) * tileHeight;
 
3228
  }
 
3229
  else {
 
3230
    y0 += anchor.y;
 
3231
    y1 = y0 + tileHeight;
 
3232
  }
 
3233
 
 
3234
  // Take the intersection again to paint only the required area
 
3235
  nsRect tileRect(x0, y0, (x1 - x0), (y1 - y0));
 
3236
  nsRect drawRect;
 
3237
 
 
3238
  if (drawRect.IntersectRect(tileRect, dirtyRect))
 
3239
    aRenderingContext.DrawTile(image, x0, y0, &drawRect);
 
3240
 
 
3241
#if (!defined(XP_UNIX) && !defined(XP_BEOS)) || defined(XP_MACOSX)
 
3242
  // Restore clipping
 
3243
  aRenderingContext.PopState(clipState);
 
3244
#endif
 
3245
 
 
3246
}
 
3247
 
 
3248
void
 
3249
nsCSSRendering::PaintBackgroundColor(nsIPresContext* aPresContext,
 
3250
                                     nsIRenderingContext& aRenderingContext,
 
3251
                                     nsIFrame* aForFrame,
 
3252
                                     const nsRect& aBgClipArea,
 
3253
                                     const nsStyleBackground& aColor,
 
3254
                                     const nsStyleBorder& aBorder,
 
3255
                                     const nsStylePadding& aPadding,
 
3256
                                     PRBool aCanPaintNonWhite)
 
3257
{
 
3258
  if (aColor.mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) {
 
3259
    // nothing to paint
 
3260
    return;
 
3261
  }
 
3262
 
 
3263
  nsStyleCoord bordStyleRadius[4];
 
3264
  PRInt16 borderRadii[4];
 
3265
  nsRect bgClipArea(aBgClipArea);
 
3266
 
 
3267
  // get the radius for our border
 
3268
  aBorder.mBorderRadius.GetTop(bordStyleRadius[NS_SIDE_TOP]);       // topleft
 
3269
  aBorder.mBorderRadius.GetRight(bordStyleRadius[NS_SIDE_RIGHT]);   // topright
 
3270
  aBorder.mBorderRadius.GetBottom(bordStyleRadius[NS_SIDE_BOTTOM]); // bottomright
 
3271
  aBorder.mBorderRadius.GetLeft(bordStyleRadius[NS_SIDE_LEFT]);     // bottomleft
 
3272
 
 
3273
  PRUint8 side = 0;
 
3274
  for (; side < 4; ++side) {
 
3275
    borderRadii[side] = 0;
 
3276
    switch (bordStyleRadius[side].GetUnit()) {
 
3277
      case eStyleUnit_Percent:
 
3278
        borderRadii[side] = nscoord(bordStyleRadius[side].GetPercentValue() * aBgClipArea.width);
 
3279
        break;
 
3280
      case eStyleUnit_Coord:
 
3281
        borderRadii[side] = bordStyleRadius[side].GetCoordValue();
 
3282
        break;
 
3283
      default:
 
3284
        break;
 
3285
    }
 
3286
  }
 
3287
 
 
3288
  // Rounded version of the border
 
3289
  // XXXdwh Composite borders (with multiple colors per side) use their own border radius
 
3290
  // algorithm now, since the current one doesn't work right for small radii.
 
3291
  if (!aBorder.mBorderColors) {
 
3292
    for (side = 0; side < 4; ++side) {
 
3293
      if (borderRadii[side] > 0) {
 
3294
        PaintRoundedBackground(aPresContext, aRenderingContext, aForFrame,
 
3295
                               bgClipArea, aColor, aBorder, borderRadii,
 
3296
                               aCanPaintNonWhite);
 
3297
        return;
 
3298
      }
 
3299
    }
 
3300
  }
 
3301
  else if (aColor.mBackgroundClip == NS_STYLE_BG_CLIP_BORDER) {
 
3302
    // XXX users of -moz-border-*-colors expect a transparent border-color
 
3303
    // to show the parent's background-color instead of its background-color.
 
3304
    // This seems wrong, but we handle that here by explictly clipping the
 
3305
    // background to the padding area.
 
3306
    nsMargin border;
 
3307
    aBorder.GetBorder(border);
 
3308
    bgClipArea.Deflate(border);
 
3309
  }
 
3310
 
 
3311
  nscolor color = aColor.mBackgroundColor;
 
3312
  if (!aCanPaintNonWhite) {
 
3313
    color = NS_RGB(255, 255, 255);
 
3314
  }
 
3315
  aRenderingContext.SetColor(color);
 
3316
  aRenderingContext.FillRect(bgClipArea);
 
3317
}
 
3318
 
 
3319
/** ---------------------------------------------------
 
3320
 *  See documentation in nsCSSRendering.h
 
3321
 *  @update 3/26/99 dwc
 
3322
 */
 
3323
void
 
3324
nsCSSRendering::PaintRoundedBackground(nsIPresContext* aPresContext,
 
3325
                                       nsIRenderingContext& aRenderingContext,
 
3326
                                       nsIFrame* aForFrame,
 
3327
                                       const nsRect& aBgClipArea,
 
3328
                                       const nsStyleBackground& aColor,
 
3329
                                       const nsStyleBorder& aBorder,
 
3330
                                       PRInt16 aTheRadius[4],
 
3331
                                       PRBool aCanPaintNonWhite)
 
3332
{
 
3333
  RoundedRect   outerPath;
 
3334
  QBCurve       cr1,cr2,cr3,cr4;
 
3335
  QBCurve       UL,UR,LL,LR;
 
3336
  PRInt32       curIndex,c1Index;
 
3337
  nsFloatPoint  thePath[MAXPATHSIZE];
 
3338
  static nsPoint       polyPath[MAXPOLYPATHSIZE];
 
3339
  PRInt16       np;
 
3340
  nscoord       twipsPerPixel;
 
3341
  float         p2t;
 
3342
 
 
3343
  // needed for our border thickness
 
3344
  p2t = aPresContext->PixelsToTwips();
 
3345
  twipsPerPixel = NSToCoordRound(p2t);
 
3346
 
 
3347
  nscolor color = aColor.mBackgroundColor;
 
3348
  if (!aCanPaintNonWhite) {
 
3349
    color = NS_RGB(255, 255, 255);
 
3350
  }
 
3351
  aRenderingContext.SetColor(color);
 
3352
 
 
3353
  // Adjust for background-clip, if necessary
 
3354
  if (aColor.mBackgroundClip != NS_STYLE_BG_CLIP_BORDER) {
 
3355
    NS_ASSERTION(aColor.mBackgroundClip == NS_STYLE_BG_CLIP_PADDING, "unknown background-clip value");
 
3356
 
 
3357
    // Get the radius to the outer edge of the padding.
 
3358
    // -moz-border-radius is the radius to the outer edge of the border.
 
3359
    nsMargin border;
 
3360
    aBorder.GetBorder(border);
 
3361
    aTheRadius[NS_SIDE_TOP]    -= border.top;
 
3362
    aTheRadius[NS_SIDE_RIGHT]  -= border.right;
 
3363
    aTheRadius[NS_SIDE_BOTTOM] -= border.bottom;
 
3364
    aTheRadius[NS_SIDE_LEFT]   -= border.left;
 
3365
    for (PRUint8 i = 0; i < 4; ++i) {
 
3366
      if (aTheRadius[i] < 0) {
 
3367
        aTheRadius[i] = 0;
 
3368
      }
 
3369
    }
 
3370
  }
 
3371
 
 
3372
  // set the rounded rect up, and let'er rip
 
3373
  outerPath.Set(aBgClipArea.x,aBgClipArea.y,aBgClipArea.width,aBgClipArea.height,aTheRadius,twipsPerPixel);
 
3374
  outerPath.GetRoundedBorders(UL,UR,LL,LR);
 
3375
 
 
3376
  // BUILD THE ENTIRE OUTSIDE PATH
 
3377
  // TOP LINE ----------------------------------------------------------------
 
3378
  UL.MidPointDivide(&cr1,&cr2);
 
3379
  UR.MidPointDivide(&cr3,&cr4);
 
3380
  np=0;
 
3381
  thePath[np++].MoveTo(cr2.mAnc1.x,cr2.mAnc1.y);
 
3382
  thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
 
3383
  thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
 
3384
  thePath[np++].MoveTo(cr3.mAnc1.x, cr3.mAnc1.y);
 
3385
  thePath[np++].MoveTo(cr3.mCon.x, cr3.mCon.y);
 
3386
  thePath[np++].MoveTo(cr3.mAnc2.x, cr3.mAnc2.y);
 
3387
 
 
3388
  polyPath[0].x = NSToCoordRound(thePath[0].x);
 
3389
  polyPath[0].y = NSToCoordRound(thePath[0].y);
 
3390
  curIndex = 1;
 
3391
  GetPath(thePath,polyPath,&curIndex,eOutside,c1Index);
 
3392
 
 
3393
  // RIGHT LINE ----------------------------------------------------------------
 
3394
  LR.MidPointDivide(&cr2,&cr3);
 
3395
  np=0;
 
3396
  thePath[np++].MoveTo(cr4.mAnc1.x,cr4.mAnc1.y);
 
3397
  thePath[np++].MoveTo(cr4.mCon.x, cr4.mCon.y);
 
3398
  thePath[np++].MoveTo(cr4.mAnc2.x, cr4.mAnc2.y);
 
3399
  thePath[np++].MoveTo(cr2.mAnc1.x, cr2.mAnc1.y);
 
3400
  thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
 
3401
  thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
 
3402
  GetPath(thePath,polyPath,&curIndex,eOutside,c1Index);
 
3403
 
 
3404
  // BOTTOM LINE ----------------------------------------------------------------
 
3405
  LL.MidPointDivide(&cr2,&cr4);
 
3406
  np=0;
 
3407
  thePath[np++].MoveTo(cr3.mAnc1.x,cr3.mAnc1.y);
 
3408
  thePath[np++].MoveTo(cr3.mCon.x, cr3.mCon.y);
 
3409
  thePath[np++].MoveTo(cr3.mAnc2.x, cr3.mAnc2.y);
 
3410
  thePath[np++].MoveTo(cr2.mAnc1.x, cr2.mAnc1.y);
 
3411
  thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
 
3412
  thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
 
3413
  GetPath(thePath,polyPath,&curIndex,eOutside,c1Index);
 
3414
 
 
3415
  // LEFT LINE ----------------------------------------------------------------
 
3416
  np=0;
 
3417
  thePath[np++].MoveTo(cr4.mAnc1.x,cr4.mAnc1.y);
 
3418
  thePath[np++].MoveTo(cr4.mCon.x, cr4.mCon.y);
 
3419
  thePath[np++].MoveTo(cr4.mAnc2.x, cr4.mAnc2.y);
 
3420
  thePath[np++].MoveTo(cr1.mAnc1.x, cr1.mAnc1.y);
 
3421
  thePath[np++].MoveTo(cr1.mCon.x, cr1.mCon.y);
 
3422
  thePath[np++].MoveTo(cr1.mAnc2.x, cr1.mAnc2.y);
 
3423
  GetPath(thePath,polyPath,&curIndex,eOutside,c1Index);
 
3424
 
 
3425
  aRenderingContext.FillPolygon(polyPath,curIndex); 
 
3426
}
 
3427
 
 
3428
 
 
3429
/** ---------------------------------------------------
 
3430
 *  See documentation in nsCSSRendering.h
 
3431
 *  @update 3/26/99 dwc
 
3432
 */
 
3433
void 
 
3434
nsCSSRendering::PaintRoundedBorder(nsIPresContext* aPresContext,
 
3435
                                 nsIRenderingContext& aRenderingContext,
 
3436
                                 nsIFrame* aForFrame,
 
3437
                                 const nsRect& aDirtyRect,
 
3438
                                 const nsRect& aBorderArea,
 
3439
                                 const nsStyleBorder* aBorderStyle,
 
3440
                                 const nsStyleOutline* aOutlineStyle,
 
3441
                                 nsStyleContext* aStyleContext,
 
3442
                                 PRIntn aSkipSides,
 
3443
                                 PRInt16 aBorderRadius[4],
 
3444
                                 nsRect* aGap,
 
3445
                                 PRBool aIsOutline)
 
3446
{
 
3447
  RoundedRect   outerPath;
 
3448
  QBCurve       UL,LL,UR,LR;
 
3449
  QBCurve       IUL,ILL,IUR,ILR;
 
3450
  QBCurve       cr1,cr2,cr3,cr4;
 
3451
  QBCurve       Icr1,Icr2,Icr3,Icr4;
 
3452
  nsFloatPoint  thePath[MAXPATHSIZE];
 
3453
  PRInt16       np;
 
3454
  nsMargin      border;
 
3455
  nscoord       twipsPerPixel,qtwips;
 
3456
  float         p2t;
 
3457
 
 
3458
  NS_ASSERTION((aIsOutline && aOutlineStyle) || (!aIsOutline && aBorderStyle), "null params not allowed");
 
3459
  if (!aIsOutline) {
 
3460
    aBorderStyle->CalcBorderFor(aForFrame, border);
 
3461
    if ((0 == border.left) && (0 == border.right) &&
 
3462
        (0 == border.top) && (0 == border.bottom)) {
 
3463
      return;
 
3464
    }
 
3465
  } else {
 
3466
    nscoord width;
 
3467
    if (!aOutlineStyle->GetOutlineWidth(width)) {
 
3468
      return;
 
3469
    }
 
3470
    border.left   = width;
 
3471
    border.right  = width;
 
3472
    border.top    = width;
 
3473
    border.bottom = width;
 
3474
  }
 
3475
 
 
3476
  // needed for our border thickness
 
3477
  p2t = aPresContext->PixelsToTwips();
 
3478
  twipsPerPixel = NSToCoordRound(p2t);
 
3479
 
 
3480
  // Base our thickness check on the segment being less than a pixel and 1/2
 
3481
  qtwips = twipsPerPixel >> 2;
 
3482
  //qtwips = twipsPerPixel;
 
3483
 
 
3484
  outerPath.Set(aBorderArea.x,aBorderArea.y,aBorderArea.width,aBorderArea.height,aBorderRadius,twipsPerPixel);
 
3485
  outerPath.GetRoundedBorders(UL,UR,LL,LR);
 
3486
  outerPath.CalcInsetCurves(IUL,IUR,ILL,ILR,border);
 
3487
 
 
3488
  // TOP LINE -- construct and divide the curves first, then put together our top and bottom paths
 
3489
  UL.MidPointDivide(&cr1,&cr2);
 
3490
  UR.MidPointDivide(&cr3,&cr4);
 
3491
  IUL.MidPointDivide(&Icr1,&Icr2);
 
3492
  IUR.MidPointDivide(&Icr3,&Icr4);
 
3493
  if(0!=border.top){
 
3494
    np=0;
 
3495
    thePath[np++].MoveTo(cr2.mAnc1.x,cr2.mAnc1.y);
 
3496
    thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
 
3497
    thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
 
3498
    thePath[np++].MoveTo(cr3.mAnc1.x, cr3.mAnc1.y);
 
3499
    thePath[np++].MoveTo(cr3.mCon.x, cr3.mCon.y);
 
3500
    thePath[np++].MoveTo(cr3.mAnc2.x, cr3.mAnc2.y);
 
3501
 
 
3502
    thePath[np++].MoveTo(Icr3.mAnc2.x,Icr3.mAnc2.y);
 
3503
    thePath[np++].MoveTo(Icr3.mCon.x, Icr3.mCon.y);
 
3504
    thePath[np++].MoveTo(Icr3.mAnc1.x, Icr3.mAnc1.y);
 
3505
    thePath[np++].MoveTo(Icr2.mAnc2.x, Icr2.mAnc2.y);
 
3506
    thePath[np++].MoveTo(Icr2.mCon.x, Icr2.mCon.y);
 
3507
    thePath[np++].MoveTo(Icr2.mAnc1.x, Icr2.mAnc1.y);
 
3508
    RenderSide(thePath,aRenderingContext,aBorderStyle,aOutlineStyle,aStyleContext,NS_SIDE_TOP,border,qtwips, aIsOutline);
 
3509
  }
 
3510
  // RIGHT  LINE ----------------------------------------------------------------
 
3511
  LR.MidPointDivide(&cr2,&cr3);
 
3512
  ILR.MidPointDivide(&Icr2,&Icr3);
 
3513
  if(0!=border.right){
 
3514
    np=0;
 
3515
    thePath[np++].MoveTo(cr4.mAnc1.x,cr4.mAnc1.y);
 
3516
    thePath[np++].MoveTo(cr4.mCon.x, cr4.mCon.y);
 
3517
    thePath[np++].MoveTo(cr4.mAnc2.x,cr4.mAnc2.y);
 
3518
    thePath[np++].MoveTo(cr2.mAnc1.x,cr2.mAnc1.y);
 
3519
    thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
 
3520
    thePath[np++].MoveTo(cr2.mAnc2.x,cr2.mAnc2.y);
 
3521
 
 
3522
    thePath[np++].MoveTo(Icr2.mAnc2.x,Icr2.mAnc2.y);
 
3523
    thePath[np++].MoveTo(Icr2.mCon.x, Icr2.mCon.y);
 
3524
    thePath[np++].MoveTo(Icr2.mAnc1.x,Icr2.mAnc1.y);
 
3525
    thePath[np++].MoveTo(Icr4.mAnc2.x,Icr4.mAnc2.y);
 
3526
    thePath[np++].MoveTo(Icr4.mCon.x, Icr4.mCon.y);
 
3527
    thePath[np++].MoveTo(Icr4.mAnc1.x,Icr4.mAnc1.y);
 
3528
    RenderSide(thePath,aRenderingContext,aBorderStyle,aOutlineStyle,aStyleContext,NS_SIDE_RIGHT,border,qtwips, aIsOutline);
 
3529
  }
 
3530
 
 
3531
  // bottom line ----------------------------------------------------------------
 
3532
  LL.MidPointDivide(&cr2,&cr4);
 
3533
  ILL.MidPointDivide(&Icr2,&Icr4);
 
3534
  if(0!=border.bottom){
 
3535
    np=0;
 
3536
    thePath[np++].MoveTo(cr3.mAnc1.x,cr3.mAnc1.y);
 
3537
    thePath[np++].MoveTo(cr3.mCon.x, cr3.mCon.y);
 
3538
    thePath[np++].MoveTo(cr3.mAnc2.x, cr3.mAnc2.y);
 
3539
    thePath[np++].MoveTo(cr2.mAnc1.x, cr2.mAnc1.y);
 
3540
    thePath[np++].MoveTo(cr2.mCon.x, cr2.mCon.y);
 
3541
    thePath[np++].MoveTo(cr2.mAnc2.x, cr2.mAnc2.y);
 
3542
 
 
3543
    thePath[np++].MoveTo(Icr2.mAnc2.x,Icr2.mAnc2.y);
 
3544
    thePath[np++].MoveTo(Icr2.mCon.x, Icr2.mCon.y);
 
3545
    thePath[np++].MoveTo(Icr2.mAnc1.x, Icr2.mAnc1.y);
 
3546
    thePath[np++].MoveTo(Icr3.mAnc2.x, Icr3.mAnc2.y);
 
3547
    thePath[np++].MoveTo(Icr3.mCon.x, Icr3.mCon.y);
 
3548
    thePath[np++].MoveTo(Icr3.mAnc1.x, Icr3.mAnc1.y);
 
3549
    RenderSide(thePath,aRenderingContext,aBorderStyle,aOutlineStyle,aStyleContext,NS_SIDE_BOTTOM,border,qtwips, aIsOutline);
 
3550
  }
 
3551
  // left line ----------------------------------------------------------------
 
3552
  if(0==border.left)
 
3553
    return;
 
3554
  np=0;
 
3555
  thePath[np++].MoveTo(cr4.mAnc1.x,cr4.mAnc1.y);
 
3556
  thePath[np++].MoveTo(cr4.mCon.x, cr4.mCon.y);
 
3557
  thePath[np++].MoveTo(cr4.mAnc2.x, cr4.mAnc2.y);
 
3558
  thePath[np++].MoveTo(cr1.mAnc1.x, cr1.mAnc1.y);
 
3559
  thePath[np++].MoveTo(cr1.mCon.x, cr1.mCon.y);
 
3560
  thePath[np++].MoveTo(cr1.mAnc2.x, cr1.mAnc2.y);
 
3561
 
 
3562
 
 
3563
  thePath[np++].MoveTo(Icr1.mAnc2.x,Icr1.mAnc2.y);
 
3564
  thePath[np++].MoveTo(Icr1.mCon.x, Icr1.mCon.y);
 
3565
  thePath[np++].MoveTo(Icr1.mAnc1.x, Icr1.mAnc1.y);
 
3566
  thePath[np++].MoveTo(Icr4.mAnc2.x, Icr4.mAnc2.y);
 
3567
  thePath[np++].MoveTo(Icr4.mCon.x, Icr4.mCon.y);
 
3568
  thePath[np++].MoveTo(Icr4.mAnc1.x, Icr4.mAnc1.y);
 
3569
 
 
3570
  RenderSide(thePath,aRenderingContext,aBorderStyle,aOutlineStyle,aStyleContext,NS_SIDE_LEFT,border,qtwips, aIsOutline);
 
3571
}
 
3572
 
 
3573
 
 
3574
/** ---------------------------------------------------
 
3575
 *  See documentation in nsCSSRendering.h
 
3576
 *  @update 3/26/99 dwc
 
3577
 */
 
3578
void 
 
3579
nsCSSRendering::RenderSide(nsFloatPoint aPoints[],nsIRenderingContext& aRenderingContext,
 
3580
                        const nsStyleBorder* aBorderStyle,const nsStyleOutline* aOutlineStyle,nsStyleContext* aStyleContext,
 
3581
                        PRUint8 aSide,nsMargin  &aBorThick,nscoord aTwipsPerPixel,
 
3582
                        PRBool aIsOutline)
 
3583
{
 
3584
  QBCurve   thecurve;
 
3585
  nscolor   sideColor = NS_RGB(0,0,0);
 
3586
  static nsPoint   polypath[MAXPOLYPATHSIZE];
 
3587
  PRInt32   curIndex,c1Index,c2Index,junk;
 
3588
  PRInt8    border_Style;
 
3589
  PRInt16   thickness;
 
3590
 
 
3591
  // Get our style context's color struct.
 
3592
  const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
 
3593
 
 
3594
  NS_ASSERTION((aIsOutline && aOutlineStyle) || (!aIsOutline && aBorderStyle), "null params not allowed");
 
3595
  // set the style information
 
3596
  if (!aIsOutline) {
 
3597
    if (!GetBorderColor(ourColor, *aBorderStyle, aSide, sideColor)) {
 
3598
      return;
 
3599
    }
 
3600
  } else {
 
3601
    aOutlineStyle->GetOutlineColor(sideColor);
 
3602
  }
 
3603
  aRenderingContext.SetColor ( sideColor );
 
3604
 
 
3605
  thickness = 0;
 
3606
  switch(aSide){
 
3607
    case  NS_SIDE_LEFT:
 
3608
      thickness = aBorThick.left;
 
3609
      break;
 
3610
    case  NS_SIDE_TOP:
 
3611
      thickness = aBorThick.top;
 
3612
      break;
 
3613
    case  NS_SIDE_RIGHT:
 
3614
      thickness = aBorThick.right;
 
3615
      break;
 
3616
    case  NS_SIDE_BOTTOM:
 
3617
      thickness = aBorThick.bottom;
 
3618
      break;
 
3619
  }
 
3620
 
 
3621
  // if the border is thin, just draw it 
 
3622
  if (thickness<=aTwipsPerPixel) {
 
3623
    // NOTHING FANCY JUST DRAW OUR OUTSIDE BORDER
 
3624
    thecurve.SetPoints(aPoints[0].x,aPoints[0].y,aPoints[1].x,aPoints[1].y,aPoints[2].x,aPoints[2].y);
 
3625
    thecurve.SubDivide((nsIRenderingContext*)&aRenderingContext,0,0);
 
3626
    aRenderingContext.DrawLine((nscoord)aPoints[2].x,(nscoord)aPoints[2].y,(nscoord)aPoints[3].x,(nscoord)aPoints[3].y);
 
3627
    thecurve.SetPoints(aPoints[3].x,aPoints[3].y,aPoints[4].x,aPoints[4].y,aPoints[5].x,aPoints[5].y);
 
3628
    thecurve.SubDivide((nsIRenderingContext*)&aRenderingContext,0,0);
 
3629
  } else {
 
3630
    
 
3631
    if (!aIsOutline) {
 
3632
      border_Style = aBorderStyle->GetBorderStyle(aSide);
 
3633
    } else {
 
3634
      border_Style = aOutlineStyle->GetOutlineStyle();
 
3635
    }
 
3636
    switch (border_Style){
 
3637
      case NS_STYLE_BORDER_STYLE_OUTSET:
 
3638
      case NS_STYLE_BORDER_STYLE_INSET:
 
3639
      case NS_STYLE_BORDER_STYLE_BG_OUTSET:
 
3640
      case NS_STYLE_BORDER_STYLE_BG_INSET:
 
3641
      case NS_STYLE_BORDER_STYLE_BG_SOLID:
 
3642
        {
 
3643
          const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
 
3644
          if (border_Style == NS_STYLE_BORDER_STYLE_BG_SOLID) {
 
3645
            nscolor colors[2]; 
 
3646
            NS_Get3DColors(colors, bgColor->mBackgroundColor); 
 
3647
            aRenderingContext.SetColor(colors[0]);
 
3648
          } else {
 
3649
            aRenderingContext.SetColor(MakeBevelColor(aSide, border_Style, bgColor->mBackgroundColor, sideColor, 
 
3650
                                       !MOZ_BG_BORDER(border_Style)));
 
3651
          }
 
3652
        }
 
3653
      case NS_STYLE_BORDER_STYLE_DOTTED:
 
3654
      case NS_STYLE_BORDER_STYLE_DASHED:
 
3655
        // break; XXX This is here until dotted and dashed are supported.  It is ok to have
 
3656
        // dotted and dashed render in solid until this style is supported.  This code should
 
3657
        // be moved when it is supported so that the above outset and inset will fall into the 
 
3658
        // solid code below....
 
3659
      case NS_STYLE_BORDER_STYLE_SOLID:
 
3660
        polypath[0].x = NSToCoordRound(aPoints[0].x);
 
3661
        polypath[0].y = NSToCoordRound(aPoints[0].y);
 
3662
        curIndex = 1;
 
3663
        GetPath(aPoints,polypath,&curIndex,eOutside,c1Index);
 
3664
        c2Index = curIndex;
 
3665
        polypath[curIndex].x = NSToCoordRound(aPoints[6].x);
 
3666
        polypath[curIndex].y = NSToCoordRound(aPoints[6].y);
 
3667
        curIndex++;
 
3668
        GetPath(aPoints,polypath,&curIndex,eInside,junk);
 
3669
        polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
 
3670
        polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
 
3671
        curIndex++;
 
3672
        aRenderingContext.FillPolygon(polypath,curIndex);
 
3673
 
 
3674
       break;
 
3675
      case NS_STYLE_BORDER_STYLE_DOUBLE:
 
3676
        polypath[0].x = NSToCoordRound(aPoints[0].x);
 
3677
        polypath[0].y = NSToCoordRound(aPoints[0].y);
 
3678
        curIndex = 1;
 
3679
        GetPath(aPoints,polypath,&curIndex,eOutside,c1Index);
 
3680
        aRenderingContext.DrawPolyline(polypath,curIndex);
 
3681
        polypath[0].x = NSToCoordRound(aPoints[6].x);
 
3682
        polypath[0].y = NSToCoordRound(aPoints[6].y);
 
3683
        curIndex = 1;
 
3684
        GetPath(aPoints,polypath,&curIndex,eInside,c1Index);
 
3685
        aRenderingContext.DrawPolyline(polypath,curIndex);
 
3686
        break;
 
3687
      case NS_STYLE_BORDER_STYLE_NONE:
 
3688
      case NS_STYLE_BORDER_STYLE_HIDDEN:
 
3689
        break;
 
3690
      case NS_STYLE_BORDER_STYLE_RIDGE:
 
3691
      case NS_STYLE_BORDER_STYLE_GROOVE:
 
3692
        {
 
3693
        const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
 
3694
        aRenderingContext.SetColor ( MakeBevelColor (aSide, border_Style, bgColor->mBackgroundColor,sideColor, PR_TRUE));
 
3695
 
 
3696
        polypath[0].x = NSToCoordRound(aPoints[0].x);
 
3697
        polypath[0].y = NSToCoordRound(aPoints[0].y);
 
3698
        curIndex = 1;
 
3699
        GetPath(aPoints,polypath,&curIndex,eOutside,c1Index);
 
3700
        polypath[curIndex].x = NSToCoordRound((aPoints[5].x + aPoints[6].x)/2.0f);
 
3701
        polypath[curIndex].y = NSToCoordRound((aPoints[5].y + aPoints[6].y)/2.0f);
 
3702
        curIndex++;
 
3703
        GetPath(aPoints,polypath,&curIndex,eCalcRev,c1Index,.5);
 
3704
        polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
 
3705
        polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
 
3706
        curIndex++;
 
3707
        aRenderingContext.FillPolygon(polypath,curIndex);
 
3708
 
 
3709
        aRenderingContext.SetColor ( MakeBevelColor (aSide, 
 
3710
                                                ((border_Style == NS_STYLE_BORDER_STYLE_RIDGE) ?
 
3711
                                                NS_STYLE_BORDER_STYLE_GROOVE :
 
3712
                                                NS_STYLE_BORDER_STYLE_RIDGE), 
 
3713
                                                bgColor->mBackgroundColor,sideColor, PR_TRUE));
 
3714
       
 
3715
        polypath[0].x = NSToCoordRound((aPoints[0].x + aPoints[11].x)/2.0f);
 
3716
        polypath[0].y = NSToCoordRound((aPoints[0].y + aPoints[11].y)/2.0f);
 
3717
        curIndex = 1;
 
3718
        GetPath(aPoints,polypath,&curIndex,eCalc,c1Index,.5);
 
3719
        polypath[curIndex].x = NSToCoordRound(aPoints[6].x) ;
 
3720
        polypath[curIndex].y = NSToCoordRound(aPoints[6].y);
 
3721
        curIndex++;
 
3722
        GetPath(aPoints,polypath,&curIndex,eInside,c1Index);
 
3723
        polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
 
3724
        polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
 
3725
        curIndex++;
 
3726
        aRenderingContext.FillPolygon(polypath,curIndex);
 
3727
        }
 
3728
        break;
 
3729
      default:
 
3730
        break;
 
3731
    }
 
3732
  }
 
3733
}
 
3734
 
 
3735
/** ---------------------------------------------------
 
3736
 *  See documentation in nsCSSRendering.h
 
3737
 *  @update 3/26/99 dwc
 
3738
 */
 
3739
void 
 
3740
RoundedRect::CalcInsetCurves(QBCurve &aULCurve,QBCurve &aURCurve,QBCurve &aLLCurve,QBCurve &aLRCurve,nsMargin &aBorder)
 
3741
{
 
3742
PRInt32   nLeft,nTop,nRight,nBottom;
 
3743
PRInt32   tLeft,bLeft,tRight,bRight,lTop,rTop,lBottom,rBottom;
 
3744
PRInt16   adjust=0;
 
3745
 
 
3746
  if(mDoRound)
 
3747
    adjust = mRoundness[0]>>3;
 
3748
 
 
3749
  nLeft = mLeft + aBorder.left;
 
3750
  tLeft = mLeft + mRoundness[0];
 
3751
  bLeft = mLeft + mRoundness[3];
 
3752
 
 
3753
  if(tLeft < nLeft){
 
3754
    tLeft = nLeft;
 
3755
  }
 
3756
 
 
3757
  if(bLeft < nLeft){
 
3758
    bLeft = nLeft;
 
3759
  }
 
3760
 
 
3761
  nRight = mRight - aBorder.right;
 
3762
  tRight = mRight - mRoundness[1];
 
3763
  bRight = mRight - mRoundness[2];
 
3764
 
 
3765
  if(tRight > nRight){
 
3766
    tRight = nRight;
 
3767
  }
 
3768
 
 
3769
  if(bRight > nRight){
 
3770
    bRight = nRight;
 
3771
  }
 
3772
 
 
3773
  nTop = mTop + aBorder.top;
 
3774
  lTop = mTop + mRoundness[0];
 
3775
  rTop = mTop + mRoundness[1];
 
3776
 
 
3777
  if(lTop < nTop){
 
3778
    lTop = nTop;
 
3779
  }
 
3780
 
 
3781
  if(rTop < nTop){
 
3782
    rTop = nTop;
 
3783
  }
 
3784
 
 
3785
  nBottom = mBottom - aBorder.bottom;
 
3786
  lBottom = mBottom - mRoundness[3];
 
3787
  rBottom = mBottom - mRoundness[2];
 
3788
 
 
3789
  if(lBottom > nBottom){
 
3790
    lBottom = nBottom;
 
3791
  }
 
3792
 
 
3793
  if(rBottom > nBottom){
 
3794
    rBottom = nBottom;
 
3795
  }
 
3796
 
 
3797
 
 
3798
  // set the passed in curves to the rounded borders of the rectangle
 
3799
  aULCurve.SetPoints( (float)nLeft,(float)lTop,
 
3800
                      (float)nLeft+adjust,(float)nTop+adjust,
 
3801
                      (float)tLeft,(float)nTop);
 
3802
  aURCurve.SetPoints( (float)tRight,(float)nTop,
 
3803
                      (float)nRight-adjust,(float)nTop+adjust,
 
3804
                      (float)nRight,(float)rTop);
 
3805
  aLRCurve.SetPoints( (float)nRight,(float)rBottom,
 
3806
                      (float)nRight-adjust,(float)nBottom-adjust,
 
3807
                      (float)bRight,(float)nBottom);
 
3808
  aLLCurve.SetPoints( (float)bLeft,(float)nBottom,
 
3809
                      (float)nLeft+adjust,(float)nBottom-adjust,
 
3810
                      (float)nLeft,(float)lBottom);
 
3811
 
 
3812
}
 
3813
 
 
3814
/** ---------------------------------------------------
 
3815
 *  See documentation in nsCSSRendering.h
 
3816
 *  @update 4/13/99 dwc
 
3817
 */
 
3818
void 
 
3819
RoundedRect::Set(nscoord aLeft,nscoord aTop,PRInt32  aWidth,PRInt32 aHeight,PRInt16 aRadius[4],PRInt16 aNumTwipPerPix)
 
3820
{
 
3821
  nscoord x,y,width,height;
 
3822
  int     i;
 
3823
 
 
3824
  // convert this rect to pixel boundaries
 
3825
  x = (aLeft/aNumTwipPerPix)*aNumTwipPerPix;
 
3826
  y = (aTop/aNumTwipPerPix)*aNumTwipPerPix;
 
3827
  width = (aWidth/aNumTwipPerPix)*aNumTwipPerPix;
 
3828
  height = (aHeight/aNumTwipPerPix)*aNumTwipPerPix;
 
3829
 
 
3830
 
 
3831
  for(i=0;i<4;i++) {
 
3832
    if( (aRadius[i]) > (aWidth>>1) ){
 
3833
      mRoundness[i] = (aWidth>>1); 
 
3834
    } else {
 
3835
      mRoundness[i] = aRadius[i];
 
3836
    }
 
3837
 
 
3838
    if( mRoundness[i] > (aHeight>>1) )
 
3839
      mRoundness[i] = aHeight>>1;
 
3840
  }
 
3841
 
 
3842
 
 
3843
  // if we are drawing a circle
 
3844
  mDoRound = PR_FALSE;
 
3845
  if(aHeight==aWidth){
 
3846
    PRBool doRound = PR_TRUE;
 
3847
    for(i=0;i<4;i++){
 
3848
      if(mRoundness[i]<(aWidth>>1)){
 
3849
        doRound = PR_FALSE;
 
3850
        break;
 
3851
      }
 
3852
    }
 
3853
 
 
3854
    if(doRound){
 
3855
      mDoRound = PR_TRUE;
 
3856
      for(i=0;i<4;i++){
 
3857
        mRoundness[i] = aWidth>>1;
 
3858
      }
 
3859
    }
 
3860
  }
 
3861
 
 
3862
 
 
3863
 
 
3864
  // important coordinates that the path hits
 
3865
  mLeft = x;
 
3866
  mTop = y;
 
3867
  mRight = x+width;
 
3868
  mBottom = y+height;
 
3869
 
 
3870
}
 
3871
 
 
3872
/** ---------------------------------------------------
 
3873
 *  See documentation in nsCSSRendering.h
 
3874
 *  @update 4/13/99 dwc
 
3875
 */
 
3876
void 
 
3877
RoundedRect::GetRoundedBorders(QBCurve &aULCurve,QBCurve &aURCurve,QBCurve &aLLCurve,QBCurve &aLRCurve)
 
3878
{
 
3879
 
 
3880
  PRInt16 adjust=0;
 
3881
 
 
3882
  if(mDoRound)
 
3883
    adjust = mRoundness[0]>>3;
 
3884
 
 
3885
  // set the passed in curves to the rounded borders of the rectangle
 
3886
  aULCurve.SetPoints( (float)mLeft,(float)mTop + mRoundness[0],
 
3887
                      (float)mLeft+adjust,(float)mTop+adjust,
 
3888
                      (float)mLeft+mRoundness[0],(float)mTop);
 
3889
  aURCurve.SetPoints( (float)mRight - mRoundness[1],(float)mTop,
 
3890
                      (float)mRight-adjust,(float)mTop+adjust,
 
3891
                      (float)mRight,(float)mTop + mRoundness[1]);
 
3892
  aLRCurve.SetPoints( (float)mRight,(float)mBottom - mRoundness[2],
 
3893
                      (float)mRight-adjust,(float)mBottom-adjust,
 
3894
                      (float)mRight - mRoundness[2],(float)mBottom);
 
3895
  aLLCurve.SetPoints( (float)mLeft + mRoundness[3],(float)mBottom,
 
3896
                      (float)mLeft+adjust,(float)mBottom-adjust,
 
3897
                      (float)mLeft,(float)mBottom - mRoundness[3]);
 
3898
}
 
3899
 
 
3900
/** ---------------------------------------------------
 
3901
 *  Given a qbezier path, convert it into a polygon path
 
3902
 *  @update 3/26/99 dwc
 
3903
 *  @param aPoints -- an array of points to use for the path
 
3904
 *  @param aPolyPath -- an array of points containing the flattened polygon to use
 
3905
 *  @param aCurIndex -- the index that points to the last element of the array
 
3906
 *  @param aPathType -- what kind of path that should be returned
 
3907
 *  @param aFrac -- the inset amount for a eCalc type path
 
3908
 */
 
3909
static void 
 
3910
GetPath(nsFloatPoint aPoints[],nsPoint aPolyPath[],PRInt32 *aCurIndex,ePathTypes  aPathType,PRInt32 &aC1Index,float aFrac)
 
3911
{
 
3912
  QBCurve thecurve;
 
3913
 
 
3914
  switch (aPathType) {
 
3915
    case eOutside:
 
3916
      thecurve.SetPoints(aPoints[0].x,aPoints[0].y,aPoints[1].x,aPoints[1].y,aPoints[2].x,aPoints[2].y);
 
3917
      thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
 
3918
      aC1Index = *aCurIndex;
 
3919
      aPolyPath[*aCurIndex].x = (nscoord)aPoints[3].x;
 
3920
      aPolyPath[*aCurIndex].y = (nscoord)aPoints[3].y;
 
3921
      (*aCurIndex)++;
 
3922
      thecurve.SetPoints(aPoints[3].x,aPoints[3].y,aPoints[4].x,aPoints[4].y,aPoints[5].x,aPoints[5].y);
 
3923
      thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
 
3924
      break;
 
3925
    case eInside:
 
3926
      thecurve.SetPoints(aPoints[6].x,aPoints[6].y,aPoints[7].x,aPoints[7].y,aPoints[8].x,aPoints[8].y);
 
3927
      thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
 
3928
      aPolyPath[*aCurIndex].x = (nscoord)aPoints[9].x;
 
3929
      aPolyPath[*aCurIndex].y = (nscoord)aPoints[9].y;
 
3930
      (*aCurIndex)++;
 
3931
      thecurve.SetPoints(aPoints[9].x,aPoints[9].y,aPoints[10].x,aPoints[10].y,aPoints[11].x,aPoints[11].y);
 
3932
      thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
 
3933
     break;
 
3934
    case eCalc:
 
3935
      thecurve.SetPoints( (aPoints[0].x+aPoints[11].x)/2.0f,(aPoints[0].y+aPoints[11].y)/2.0f,
 
3936
                          (aPoints[1].x+aPoints[10].x)/2.0f,(aPoints[1].y+aPoints[10].y)/2.0f,
 
3937
                          (aPoints[2].x+aPoints[9].x)/2.0f,(aPoints[2].y+aPoints[9].y)/2.0f);
 
3938
      thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
 
3939
      aPolyPath[*aCurIndex].x = (nscoord)((aPoints[3].x+aPoints[8].x)/2.0f);
 
3940
      aPolyPath[*aCurIndex].y = (nscoord)((aPoints[3].y+aPoints[8].y)/2.0f);
 
3941
      (*aCurIndex)++;
 
3942
      thecurve.SetPoints( (aPoints[3].x+aPoints[8].x)/2.0f,(aPoints[3].y+aPoints[8].y)/2.0f,
 
3943
                          (aPoints[4].x+aPoints[7].x)/2.0f,(aPoints[4].y+aPoints[7].y)/2.0f,
 
3944
                          (aPoints[5].x+aPoints[6].x)/2.0f,(aPoints[5].y+aPoints[6].y)/2.0f);
 
3945
      thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
 
3946
      break;
 
3947
    case eCalcRev:
 
3948
      thecurve.SetPoints( (aPoints[5].x+aPoints[6].x)/2.0f,(aPoints[5].y+aPoints[6].y)/2.0f,
 
3949
                          (aPoints[4].x+aPoints[7].x)/2.0f,(aPoints[4].y+aPoints[7].y)/2.0f,
 
3950
                          (aPoints[3].x+aPoints[8].x)/2.0f,(aPoints[3].y+aPoints[8].y)/2.0f);
 
3951
      thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
 
3952
      aPolyPath[*aCurIndex].x = (nscoord)((aPoints[2].x+aPoints[9].x)/2.0f);
 
3953
      aPolyPath[*aCurIndex].y = (nscoord)((aPoints[2].y+aPoints[9].y)/2.0f);
 
3954
      (*aCurIndex)++;
 
3955
      thecurve.SetPoints( (aPoints[2].x+aPoints[9].x)/2.0f,(aPoints[2].y+aPoints[9].y)/2.0f,
 
3956
                          (aPoints[1].x+aPoints[10].x)/2.0f,(aPoints[1].y+aPoints[10].y)/2.0f,
 
3957
                          (aPoints[0].x+aPoints[11].x)/2.0f,(aPoints[0].y+aPoints[11].y)/2.0f);
 
3958
      thecurve.SubDivide(nsnull,aPolyPath,aCurIndex);
 
3959
      break;
 
3960
  } 
 
3961
}
 
3962
 
 
3963
/** ---------------------------------------------------
 
3964
 *  See documentation in nsCSSRendering.h
 
3965
 *  @update 4/13/99 dwc
 
3966
 */
 
3967
void 
 
3968
QBCurve::SubDivide(nsIRenderingContext *aRenderingContext,nsPoint aPointArray[],PRInt32 *aCurIndex)
 
3969
{
 
3970
QBCurve   curve1,curve2;
 
3971
float     fx,fy,smag;
 
3972
 
 
3973
  // divide the curve into 2 pieces
 
3974
  MidPointDivide(&curve1,&curve2);
 
3975
 
 
3976
  fx = (float)fabs(curve1.mAnc2.x - this->mCon.x);
 
3977
  fy = (float)fabs(curve1.mAnc2.y - this->mCon.y);
 
3978
 
 
3979
  //smag = fx+fy-(PR_MIN(fx,fy)>>1);
 
3980
  smag = fx*fx + fy*fy;
 
3981
 
 
3982
  if (smag>1){
 
3983
    // split the curve again
 
3984
    curve1.SubDivide(aRenderingContext,aPointArray,aCurIndex);
 
3985
    curve2.SubDivide(aRenderingContext,aPointArray,aCurIndex);
 
3986
  }else{
 
3987
    if(aPointArray ) {
 
3988
      // save the points for further processing
 
3989
      aPointArray[*aCurIndex].x = (nscoord)curve1.mAnc2.x;
 
3990
      aPointArray[*aCurIndex].y = (nscoord)curve1.mAnc2.y;
 
3991
      (*aCurIndex)++;
 
3992
      aPointArray[*aCurIndex].x = (nscoord)curve2.mAnc2.x;
 
3993
      aPointArray[*aCurIndex].y = (nscoord)curve2.mAnc2.y;
 
3994
      (*aCurIndex)++;
 
3995
    }else{
 
3996
      // draw the curve 
 
3997
      nsTransform2D *aTransform;
 
3998
      aRenderingContext->GetCurrentTransform(aTransform);
 
3999
 
 
4000
      
 
4001
      aRenderingContext->DrawLine((nscoord)curve1.mAnc1.x,(nscoord)curve1.mAnc1.y,(nscoord)curve1.mAnc2.x,(nscoord)curve1.mAnc2.y);
 
4002
      aRenderingContext->DrawLine((nscoord)curve1.mAnc2.x,(nscoord)curve1.mAnc2.y,(nscoord)curve2.mAnc2.x,(nscoord)curve2.mAnc2.y);
 
4003
    }
 
4004
  }
 
4005
}
 
4006
 
 
4007
/** ---------------------------------------------------
 
4008
 *  See documentation in nsCSSRendering.h
 
4009
 *  @update 4/13/99 dwc
 
4010
 */
 
4011
void 
 
4012
QBCurve::MidPointDivide(QBCurve *A,QBCurve *B)
 
4013
{
 
4014
  float c1x,c1y,c2x,c2y;
 
4015
  nsFloatPoint a1;
 
4016
 
 
4017
  c1x = (mAnc1.x+mCon.x)/2.0f;
 
4018
  c1y = (mAnc1.y+mCon.y)/2.0f;
 
4019
  c2x = (mAnc2.x+mCon.x)/2.0f;
 
4020
  c2y = (mAnc2.y+mCon.y)/2.0f;
 
4021
 
 
4022
  a1.x = (c1x + c2x)/2.0f;
 
4023
  a1.y = (c1y + c2y)/2.0f;
 
4024
 
 
4025
  // put the math into our 2 new curves
 
4026
  A->mAnc1 = this->mAnc1;
 
4027
  A->mCon.x = c1x;
 
4028
  A->mCon.y = c1y;
 
4029
  A->mAnc2 = a1;
 
4030
  B->mAnc1 = a1;
 
4031
  B->mCon.x = c2x;
 
4032
  B->mCon.y = c2y;
 
4033
  B->mAnc2 = this->mAnc2;
 
4034
}
 
4035
 
 
4036
void FillOrInvertRect(nsIRenderingContext& aRC, nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aInvert)
 
4037
{
 
4038
  if (aInvert) {
 
4039
    aRC.InvertRect(aX, aY, aWidth, aHeight);
 
4040
  } else {
 
4041
    aRC.FillRect(aX, aY, aWidth, aHeight);
 
4042
  }
 
4043
}
 
4044
 
 
4045
void FillOrInvertRect(nsIRenderingContext& aRC, const nsRect& aRect, PRBool aInvert)
 
4046
{
 
4047
  if (aInvert) {
 
4048
    aRC.InvertRect(aRect);
 
4049
  } else {
 
4050
    aRC.FillRect(aRect);
 
4051
  }
 
4052
}
 
4053
 
 
4054
// Begin table border-collapsing section
 
4055
// These functions were written to not disrupt the normal ones and yet satisfy some additional requirements
 
4056
// At some point, all functions should be unified to include the additional functionality that these provide
 
4057
 
 
4058
static nscoord
 
4059
RoundIntToPixel(nscoord aValue, 
 
4060
                nscoord aTwipsPerPixel,
 
4061
                PRBool  aRoundDown = PR_FALSE)
 
4062
{
 
4063
  if (aTwipsPerPixel <= 0) 
 
4064
    // We must be rendering to a device that has a resolution greater than Twips! 
 
4065
    // In that case, aValue is as accurate as it's going to get.
 
4066
    return aValue; 
 
4067
 
 
4068
  nscoord halfPixel = NSToCoordRound(aTwipsPerPixel / 2.0f);
 
4069
  nscoord extra = aValue % aTwipsPerPixel;
 
4070
  nscoord finalValue = (!aRoundDown && (extra >= halfPixel)) ? aValue + (aTwipsPerPixel - extra) : aValue - extra;
 
4071
  return finalValue;
 
4072
}
 
4073
 
 
4074
static nscoord
 
4075
RoundFloatToPixel(float   aValue, 
 
4076
                  nscoord aTwipsPerPixel,
 
4077
                  PRBool  aRoundDown = PR_FALSE)
 
4078
{
 
4079
  return RoundIntToPixel(NSToCoordRound(aValue), aTwipsPerPixel, aRoundDown);
 
4080
}
 
4081
 
 
4082
static void
 
4083
SetPoly(const nsRect& aRect,
 
4084
        nsPoint*      poly)
 
4085
{
 
4086
  poly[0].x = aRect.x;
 
4087
  poly[0].y = aRect.y;
 
4088
  poly[1].x = aRect.x + aRect.width;
 
4089
  poly[1].y = aRect.y;
 
4090
  poly[2].x = aRect.x + aRect.width;
 
4091
  poly[2].y = aRect.y + aRect.height;
 
4092
  poly[3].x = aRect.x;
 
4093
  poly[3].y = aRect.y + aRect.height;
 
4094
  poly[4].x = aRect.x;
 
4095
  poly[4].y = aRect.y;
 
4096
}
 
4097
          
 
4098
static void 
 
4099
DrawSolidBorderSegment(nsIRenderingContext& aContext,
 
4100
                       nsRect               aRect,
 
4101
                       nscoord              aTwipsPerPixel,
 
4102
                       PRUint8              aStartBevelSide = 0,
 
4103
                       nscoord              aStartBevelOffset = 0,
 
4104
                       PRUint8              aEndBevelSide = 0,
 
4105
                       nscoord              aEndBevelOffset = 0)
 
4106
{
 
4107
 
 
4108
  if ((aRect.width == aTwipsPerPixel) || (aRect.height == aTwipsPerPixel) ||
 
4109
      ((0 == aStartBevelOffset) && (0 == aEndBevelOffset))) {
 
4110
    // simple line or rectangle
 
4111
    if ((NS_SIDE_TOP == aStartBevelSide) || (NS_SIDE_BOTTOM == aStartBevelSide)) {
 
4112
      if (1 == aRect.height) 
 
4113
        aContext.DrawLine(aRect.x, aRect.y, aRect.x, aRect.y + aRect.height); 
 
4114
      else 
 
4115
        aContext.FillRect(aRect);
 
4116
    }
 
4117
    else {
 
4118
      if (1 == aRect.width) 
 
4119
        aContext.DrawLine(aRect.x, aRect.y, aRect.x + aRect.width, aRect.y); 
 
4120
      else 
 
4121
        aContext.FillRect(aRect);
 
4122
    }
 
4123
  }
 
4124
  else {
 
4125
    // polygon with beveling
 
4126
    nsPoint poly[5];
 
4127
    SetPoly(aRect, poly);
 
4128
    switch(aStartBevelSide) {
 
4129
    case NS_SIDE_TOP:
 
4130
      poly[0].x += aStartBevelOffset;
 
4131
      poly[4].x = poly[0].x;
 
4132
      break;
 
4133
    case NS_SIDE_BOTTOM:
 
4134
      poly[3].x += aStartBevelOffset;
 
4135
      break;
 
4136
    case NS_SIDE_RIGHT:
 
4137
      poly[1].y += aStartBevelOffset;
 
4138
      break;
 
4139
    case NS_SIDE_LEFT:
 
4140
      poly[0].y += aStartBevelOffset;
 
4141
      poly[4].y = poly[0].y;
 
4142
    }
 
4143
 
 
4144
    switch(aEndBevelSide) {
 
4145
    case NS_SIDE_TOP:
 
4146
      poly[1].x -= aEndBevelOffset;
 
4147
      break;
 
4148
    case NS_SIDE_BOTTOM:
 
4149
      poly[2].x -= aEndBevelOffset;
 
4150
      break;
 
4151
    case NS_SIDE_RIGHT:
 
4152
      poly[2].y -= aEndBevelOffset;
 
4153
      break;
 
4154
    case NS_SIDE_LEFT:
 
4155
      poly[3].y -= aEndBevelOffset;
 
4156
    }
 
4157
 
 
4158
    aContext.FillPolygon(poly, 5);
 
4159
  }
 
4160
 
 
4161
 
 
4162
}
 
4163
 
 
4164
static void
 
4165
GetDashInfo(nscoord  aBorderLength,
 
4166
            nscoord  aDashLength,
 
4167
            nscoord  aTwipsPerPixel,
 
4168
            PRInt32& aNumDashSpaces,
 
4169
            nscoord& aStartDashLength,
 
4170
            nscoord& aEndDashLength)
 
4171
{
 
4172
  aNumDashSpaces = 0;
 
4173
  if (aStartDashLength + aDashLength + aEndDashLength >= aBorderLength) {
 
4174
    aStartDashLength = aBorderLength;
 
4175
    aEndDashLength = 0;
 
4176
  }
 
4177
  else {
 
4178
    aNumDashSpaces = aBorderLength / (2 * aDashLength); // round down
 
4179
    nscoord extra = aBorderLength - aStartDashLength - aEndDashLength - (((2 * aNumDashSpaces) - 1) * aDashLength);
 
4180
    if (extra > 0) {
 
4181
      nscoord half = RoundIntToPixel(extra / 2, aTwipsPerPixel);
 
4182
      aStartDashLength += half;
 
4183
      aEndDashLength += (extra - half);
 
4184
    }
 
4185
  }
 
4186
}
 
4187
 
 
4188
void 
 
4189
nsCSSRendering::DrawTableBorderSegment(nsIRenderingContext&     aContext,
 
4190
                                       PRUint8                  aBorderStyle,  
 
4191
                                       nscolor                  aBorderColor,
 
4192
                                       const nsStyleBackground* aBGColor,
 
4193
                                       const nsRect&            aBorder,
 
4194
                                       float                    aPixelsToTwips,
 
4195
                                       PRUint8                  aStartBevelSide,
 
4196
                                       nscoord                  aStartBevelOffset,
 
4197
                                       PRUint8                  aEndBevelSide,
 
4198
                                       nscoord                  aEndBevelOffset)
 
4199
{
 
4200
  aContext.SetColor (aBorderColor); 
 
4201
 
 
4202
  PRBool horizontal = ((NS_SIDE_TOP == aStartBevelSide) || (NS_SIDE_BOTTOM == aStartBevelSide));
 
4203
  nscoord twipsPerPixel = NSIntPixelsToTwips(1, aPixelsToTwips);
 
4204
  PRBool ridgeGroove = NS_STYLE_BORDER_STYLE_RIDGE;
 
4205
 
 
4206
  if ((twipsPerPixel >= aBorder.width) || (twipsPerPixel >= aBorder.height) ||
 
4207
      (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) || (NS_STYLE_BORDER_STYLE_DOTTED == aBorderStyle)) {
 
4208
    // no beveling for 1 pixel border, dash or dot
 
4209
    aStartBevelOffset = 0;
 
4210
    aEndBevelOffset = 0;
 
4211
  }
 
4212
 
 
4213
  switch (aBorderStyle) {
 
4214
  case NS_STYLE_BORDER_STYLE_NONE:
 
4215
  case NS_STYLE_BORDER_STYLE_HIDDEN:
 
4216
    //NS_ASSERTION(PR_FALSE, "style of none or hidden");
 
4217
    break;
 
4218
  case NS_STYLE_BORDER_STYLE_DOTTED:
 
4219
  case NS_STYLE_BORDER_STYLE_DASHED: 
 
4220
    {
 
4221
      nscoord dashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) ? DASH_LENGTH : DOT_LENGTH;
 
4222
      // make the dash length proportional to the border thickness
 
4223
      dashLength *= (horizontal) ? aBorder.height : aBorder.width;
 
4224
      // make the min dash length for the ends 1/2 the dash length
 
4225
      nscoord minDashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) 
 
4226
                              ? RoundFloatToPixel(((float)dashLength) / 2.0f, twipsPerPixel) : dashLength;
 
4227
      minDashLength = PR_MAX(minDashLength, twipsPerPixel);
 
4228
      nscoord numDashSpaces = 0;
 
4229
      nscoord startDashLength = minDashLength;
 
4230
      nscoord endDashLength   = minDashLength;
 
4231
      if (horizontal) {
 
4232
        GetDashInfo(aBorder.width, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength);
 
4233
        nsRect rect(aBorder.x, aBorder.y, startDashLength, aBorder.height);
 
4234
        DrawSolidBorderSegment(aContext, rect, PR_TRUE);
 
4235
        for (PRInt32 spaceX = 0; spaceX < numDashSpaces; spaceX++) {
 
4236
          rect.x += rect.width + dashLength;
 
4237
          rect.width = (spaceX == (numDashSpaces - 1)) ? endDashLength : dashLength;
 
4238
          DrawSolidBorderSegment(aContext, rect, PR_TRUE);
 
4239
        }
 
4240
      }
 
4241
      else {
 
4242
        GetDashInfo(aBorder.height, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength);
 
4243
        nsRect rect(aBorder.x, aBorder.y, aBorder.width, startDashLength);
 
4244
        DrawSolidBorderSegment(aContext, rect, PR_FALSE);
 
4245
        for (PRInt32 spaceY = 0; spaceY < numDashSpaces; spaceY++) {
 
4246
          rect.y += rect.height + dashLength;
 
4247
          rect.height = (spaceY == (numDashSpaces - 1)) ? endDashLength : dashLength;
 
4248
          DrawSolidBorderSegment(aContext, rect, PR_FALSE);
 
4249
        }
 
4250
      }
 
4251
    }
 
4252
    break;                                  
 
4253
  case NS_STYLE_BORDER_STYLE_GROOVE:
 
4254
    ridgeGroove = NS_STYLE_BORDER_STYLE_GROOVE; // and fall through to ridge
 
4255
  case NS_STYLE_BORDER_STYLE_RIDGE:
 
4256
    if ((horizontal && (twipsPerPixel >= aBorder.height)) ||
 
4257
        (!horizontal && (twipsPerPixel >= aBorder.width))) {
 
4258
      // a one pixel border
 
4259
      DrawSolidBorderSegment(aContext, aBorder, twipsPerPixel, aStartBevelSide, aStartBevelOffset,
 
4260
                             aEndBevelSide, aEndBevelOffset);
 
4261
    }
 
4262
    else {
 
4263
      nscoord startBevel = (aStartBevelOffset > 0) 
 
4264
                            ? RoundFloatToPixel(0.5f * (float)aStartBevelOffset, twipsPerPixel, PR_TRUE) : 0;
 
4265
      nscoord endBevel =   (aEndBevelOffset > 0) 
 
4266
                            ? RoundFloatToPixel(0.5f * (float)aEndBevelOffset, twipsPerPixel, PR_TRUE) : 0;
 
4267
      PRUint8 ridgeGrooveSide = (horizontal) ? NS_SIDE_TOP : NS_SIDE_LEFT;
 
4268
      aContext.SetColor ( 
 
4269
        MakeBevelColor (ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor, PR_TRUE));
 
4270
      nsRect rect(aBorder);
 
4271
      nscoord half;
 
4272
      if (horizontal) { // top, bottom
 
4273
        half = RoundFloatToPixel(0.5f * (float)aBorder.height, twipsPerPixel);
 
4274
        rect.height = half;
 
4275
        if (NS_SIDE_TOP == aStartBevelSide) {
 
4276
          rect.x += startBevel;
 
4277
          rect.width -= startBevel;
 
4278
        }
 
4279
        if (NS_SIDE_TOP == aEndBevelSide) {
 
4280
          rect.width -= endBevel;
 
4281
        }
 
4282
        DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide, 
 
4283
                               startBevel, aEndBevelSide, endBevel);
 
4284
      }
 
4285
      else { // left, right
 
4286
        half = RoundFloatToPixel(0.5f * (float)aBorder.width, twipsPerPixel);
 
4287
        rect.width = half;
 
4288
        if (NS_SIDE_LEFT == aStartBevelSide) {
 
4289
          rect.y += startBevel;
 
4290
          rect.height -= startBevel;
 
4291
        }
 
4292
        if (NS_SIDE_LEFT == aEndBevelSide) {
 
4293
          rect.height -= endBevel;
 
4294
        }
 
4295
        DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide, 
 
4296
                               startBevel, aEndBevelSide, endBevel);
 
4297
      }
 
4298
 
 
4299
      rect = aBorder;
 
4300
      ridgeGrooveSide = (NS_SIDE_TOP == ridgeGrooveSide) ? NS_SIDE_BOTTOM : NS_SIDE_RIGHT;
 
4301
      aContext.SetColor ( 
 
4302
        MakeBevelColor (ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor, PR_TRUE));
 
4303
      if (horizontal) {
 
4304
        rect.y = rect.y + half;
 
4305
        rect.height = aBorder.height - half;
 
4306
        if (NS_SIDE_BOTTOM == aStartBevelSide) {
 
4307
          rect.x += startBevel;
 
4308
          rect.width -= startBevel;
 
4309
        }
 
4310
        if (NS_SIDE_BOTTOM == aEndBevelSide) {
 
4311
          rect.width -= endBevel;
 
4312
        }
 
4313
        DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide, 
 
4314
                               startBevel, aEndBevelSide, endBevel);
 
4315
      }
 
4316
      else {
 
4317
        rect.x = rect.x + half;
 
4318
        rect.width = aBorder.width - half;
 
4319
        if (NS_SIDE_RIGHT == aStartBevelSide) {
 
4320
          rect.y += aStartBevelOffset - startBevel;
 
4321
          rect.height -= startBevel;
 
4322
        }
 
4323
        if (NS_SIDE_RIGHT == aEndBevelSide) {
 
4324
          rect.height -= endBevel;
 
4325
        }
 
4326
        DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide, 
 
4327
                               startBevel, aEndBevelSide, endBevel);
 
4328
      }
 
4329
    }
 
4330
    break;
 
4331
  case NS_STYLE_BORDER_STYLE_DOUBLE:
 
4332
    if ((aBorder.width > 2) && (aBorder.height > 2)) {
 
4333
      nscoord startBevel = (aStartBevelOffset > 0) 
 
4334
                            ? RoundFloatToPixel(0.333333f * (float)aStartBevelOffset, twipsPerPixel) : 0;
 
4335
      nscoord endBevel =   (aEndBevelOffset > 0) 
 
4336
                            ? RoundFloatToPixel(0.333333f * (float)aEndBevelOffset, twipsPerPixel) : 0;
 
4337
      if (horizontal) { // top, bottom
 
4338
        nscoord thirdHeight = RoundFloatToPixel(0.333333f * (float)aBorder.height, twipsPerPixel);
 
4339
 
 
4340
        // draw the top line or rect
 
4341
        nsRect topRect(aBorder.x, aBorder.y, aBorder.width, thirdHeight);
 
4342
        if (NS_SIDE_TOP == aStartBevelSide) {
 
4343
          topRect.x += aStartBevelOffset - startBevel;
 
4344
          topRect.width -= aStartBevelOffset - startBevel;
 
4345
        }
 
4346
        if (NS_SIDE_TOP == aEndBevelSide) {
 
4347
          topRect.width -= aEndBevelOffset - endBevel;
 
4348
        }
 
4349
        DrawSolidBorderSegment(aContext, topRect, twipsPerPixel, aStartBevelSide, 
 
4350
                               startBevel, aEndBevelSide, endBevel);
 
4351
 
 
4352
        // draw the botom line or rect
 
4353
        nscoord heightOffset = aBorder.height - thirdHeight; 
 
4354
        nsRect bottomRect(aBorder.x, aBorder.y + heightOffset, aBorder.width, aBorder.height - heightOffset);
 
4355
        if (NS_SIDE_BOTTOM == aStartBevelSide) {
 
4356
          bottomRect.x += aStartBevelOffset - startBevel;
 
4357
          bottomRect.width -= aStartBevelOffset - startBevel;
 
4358
        }
 
4359
        if (NS_SIDE_BOTTOM == aEndBevelSide) {
 
4360
          bottomRect.width -= aEndBevelOffset - endBevel;
 
4361
        }
 
4362
        DrawSolidBorderSegment(aContext, bottomRect, twipsPerPixel, aStartBevelSide, 
 
4363
                               startBevel, aEndBevelSide, endBevel);
 
4364
      }
 
4365
      else { // left, right
 
4366
        nscoord thirdWidth = RoundFloatToPixel(0.333333f * (float)aBorder.width, twipsPerPixel);
 
4367
 
 
4368
        nsRect leftRect(aBorder.x, aBorder.y, thirdWidth, aBorder.height); 
 
4369
        if (NS_SIDE_LEFT == aStartBevelSide) {
 
4370
          leftRect.y += aStartBevelOffset - startBevel;
 
4371
          leftRect.height -= aStartBevelOffset - startBevel;
 
4372
        }
 
4373
        if (NS_SIDE_LEFT == aEndBevelSide) {
 
4374
          leftRect.height -= aEndBevelOffset - endBevel;
 
4375
        }
 
4376
        DrawSolidBorderSegment(aContext, leftRect, twipsPerPixel, aStartBevelSide,
 
4377
                               startBevel, aEndBevelSide, endBevel);
 
4378
 
 
4379
        nscoord widthOffset = aBorder.width - thirdWidth; 
 
4380
        nsRect rightRect(aBorder.x + widthOffset, aBorder.y, aBorder.width - widthOffset, aBorder.height);
 
4381
        if (NS_SIDE_RIGHT == aStartBevelSide) {
 
4382
          rightRect.y += aStartBevelOffset - startBevel;
 
4383
          rightRect.height -= aStartBevelOffset - startBevel;
 
4384
        }
 
4385
        if (NS_SIDE_RIGHT == aEndBevelSide) {
 
4386
          rightRect.height -= aEndBevelOffset - endBevel;
 
4387
        }
 
4388
        DrawSolidBorderSegment(aContext, rightRect, twipsPerPixel, aStartBevelSide,
 
4389
                               startBevel, aEndBevelSide, endBevel);
 
4390
      }
 
4391
      break;
 
4392
    }
 
4393
    // else fall through to solid
 
4394
  case NS_STYLE_BORDER_STYLE_BG_SOLID:
 
4395
  case NS_STYLE_BORDER_STYLE_SOLID:
 
4396
    DrawSolidBorderSegment(aContext, aBorder, twipsPerPixel, aStartBevelSide, 
 
4397
                           aStartBevelOffset, aEndBevelSide, aEndBevelOffset);
 
4398
    break;
 
4399
  case NS_STYLE_BORDER_STYLE_BG_OUTSET:
 
4400
  case NS_STYLE_BORDER_STYLE_BG_INSET:
 
4401
  case NS_STYLE_BORDER_STYLE_OUTSET:
 
4402
  case NS_STYLE_BORDER_STYLE_INSET:
 
4403
    NS_ASSERTION(PR_FALSE, "inset, outset should have been converted to groove, ridge");
 
4404
    break;
 
4405
  }
 
4406
}
 
4407
 
 
4408
// End table border-collapsing section
 
4409