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
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/
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
16
* The Original Code is mozilla.org code.
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.
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.
37
* ***** END LICENSE BLOCK ***** */
38
#include "nsStyleConsts.h"
39
#include "nsIPresContext.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"
63
#include "nsThemeConstants.h"
64
#include "nsIServiceManager.h"
65
#include "nsIDOMHTMLBodyElement.h"
66
#include "nsIDOMHTMLDocument.h"
67
#include "nsLayoutUtils.h"
68
#include "nsINameSpaceManager.h"
70
#define BORDER_FULL 0 //entire side
71
#define BORDER_INSIDE 1 //inside half
72
#define BORDER_OUTSIDE 2 //outside half
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
79
/** The following classes are used by CSSRendering for the rounded rect implementation */
80
#define MAXPATHSIZE 12
81
#define MAXPOLYPATHSIZE 1000
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
96
InlineBackgroundData()
101
~InlineBackgroundData()
107
mBoundingBox.SetRect(0,0,0,0);
108
mContinuationPoint = mUnbrokenWidth = 0;
112
nsRect GetContinuousRect(nsIFrame* aFrame)
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);
122
nsRect GetBoundingRect(nsIFrame* aFrame)
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);
140
nscoord mContinuationPoint;
141
nscoord mUnbrokenWidth;
144
void SetFrame(nsIFrame* aFrame)
146
NS_PRECONDITION(aFrame, "Need a frame");
148
nsIFrame *prevInFlow = nsnull;
149
aFrame->GetPrevInFlow(&prevInFlow);
151
if (!prevInFlow || mFrame != prevInFlow) {
152
// Ok, we've got the wrong frame. We have to start from scratch.
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;
165
void Init(nsIFrame* aFrame)
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);
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);
180
// Next add this frame and subsequent frames to the bounding box and
182
inlineFrame = aFrame;
183
while (inlineFrame) {
184
nsRect rect = inlineFrame->GetRect();
185
mUnbrokenWidth += rect.width;
186
mBoundingBox.UnionRect(mBoundingBox, rect);
187
inlineFrame->GetNextInFlow(&inlineFrame);
194
static InlineBackgroundData gInlineBGData;
196
static void GetPath(nsFloatPoint aPoints[],nsPoint aPolyPath[],PRInt32 *aCurIndex,ePathTypes aPathType,PRInt32 &aC1Index,float aFrac=0);
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);
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,
208
if (nsnull == aGap) {
209
aContext.DrawLine(aX1, aY1, aX2, aY2);
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);
219
if ((gapLowerRight.x > x1) && (gapLowerRight.x < x2)) {
220
aContext.DrawLine(gapUpperRight.x, aY2, x2, aY2);
223
aContext.DrawLine(aX1, aY1, aX2, aY2);
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[],
237
if (NS_SUCCEEDED(aContext.GetPenMode(penMode)) &&
238
penMode == nsPenMode_kInvert) {
239
NS_WARNING( "Invert mode ignored in FillPolygon" );
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);
249
// sort the 4 points by x
251
for (PRInt32 pX = 0; pX < 4; pX++) {
252
points[pX] = aPoints[pX];
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];
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];
270
if ((aGap->y <= upperLeft.y) && (gapLowerRight.y >= lowerRight.y)) {
271
if ((aGap->x > upperLeft.x) && (aGap->x < upperRight.x)) {
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);
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);
288
aContext.FillPolygon(aPoints, aNumPoints);
296
nscolor nsCSSRendering::MakeBevelColor(PRIntn whichSide, PRUint8 style,
297
nscolor aBackgroundColor,
298
nscolor aBorderColor,
305
// Given a background color and a border color
306
// calculate the color used for the shading
308
NS_GetSpecial3DColors(colors, aBackgroundColor, aBorderColor);
310
NS_Get3DColors(colors, aBackgroundColor);
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
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;
326
theColor = colors[1];
329
theColor = colors[1];
332
theColor = colors[0];
336
theColor = colors[0];
342
// Maximum poly points in any of the polygons we generate below
343
#define MAX_POLY_POINTS 4
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
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,
355
const nsRect& outside, const nsRect& inside,
357
PRIntn borderPart, float borderFrac,
358
nscoord twipsPerPixel)
360
float borderRest = 1.0f - borderFrac;
363
nscoord thickness, outsideEdge, insideEdge, outsideTL, insideTL, outsideBR,
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.:
371
// outsideEdge --- ----------------------------------------
375
// insideEdge ------- ----------------------------------
377
// outsideTL insideTL insideBR outsideBR
379
// if we don't want the bevel, we'll get rid of it later by setting
380
// outsideXX to insideXX
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;
389
insideBR = inside.XMost();
390
outsideBR = outside.XMost();
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;
399
insideBR = inside.XMost();
400
outsideBR = outside.XMost();
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;
409
insideBR = inside.YMost();
410
outsideBR = outside.YMost();
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;
419
insideBR = inside.YMost();
420
outsideBR = outside.YMost();
424
// Don't draw the bevels if an adjacent side is skipped
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;
431
if ((1<<NS_SIDE_RIGHT) & aSkipSides) {
432
insideBR = outsideBR;
435
// a right or left side
436
if ((1<<NS_SIDE_TOP) & aSkipSides) {
437
insideTL = outsideTL;
439
if ((1<<NS_SIDE_BOTTOM) & aSkipSides) {
440
insideBR = outsideBR;
444
// move things around when only drawing part of the border
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);
456
// Base our thickness check on the segment being less than a pixel and 1/2
457
twipsPerPixel += twipsPerPixel >> 2;
459
// find the thickness of the piece being drawn
460
if ((whichSide == NS_SIDE_TOP) || (whichSide == NS_SIDE_LEFT)) {
461
thickness = insideEdge - outsideEdge;
463
thickness = outsideEdge - insideEdge;
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;
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
485
if ((thickness >= twipsPerPixel) || (borderPart != BORDER_FULL) ) {
486
aPoints[np++].MoveTo(insideBR,insideEdge);
487
aPoints[np++].MoveTo(insideTL,insideEdge);
490
// right and left borders
492
if ((thickness >= twipsPerPixel) || (borderPart != BORDER_FULL) ) {
493
aPoints[np++].MoveTo(insideEdge,insideBR);
494
aPoints[np++].MoveTo(insideEdge,insideTL);
496
aPoints[np++].MoveTo(outsideEdge,outsideTL);
497
aPoints[np++].MoveTo(outsideEdge,outsideBR);
502
void nsCSSRendering::DrawSide(nsIRenderingContext& aContext,
504
const PRUint8 borderStyle,
505
const nscolor borderColor,
506
const nscolor aBackgroundColor,
507
const nsRect& borderOutside,
508
const nsRect& borderInside,
510
nscoord twipsPerPixel,
513
nsPoint theSide[MAX_POLY_POINTS];
514
nscolor theColor = borderColor;
515
PRUint8 theStyle = borderStyle;
518
case NS_STYLE_BORDER_STYLE_NONE:
519
case NS_STYLE_BORDER_STYLE_HIDDEN:
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...
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,
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);
540
//aContext.FillPolygon (theSide, np);
541
FillPolygon (aContext, theSide, np, aGap);
543
np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
544
BORDER_OUTSIDE, 0.5f, twipsPerPixel);
545
aContext.SetColor ( MakeBevelColor (whichSide, theStyle, aBackgroundColor,
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);
551
//aContext.FillPolygon (theSide, np);
552
FillPolygon (aContext, theSide, np, aGap);
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);
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);
564
//aContext.FillPolygon (theSide, np);
565
FillPolygon (aContext, theSide, np, aGap);
569
case NS_STYLE_BORDER_STYLE_BG_SOLID:
570
np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, aSkipSides,
571
BORDER_FULL, 1.0f, twipsPerPixel);
573
NS_Get3DColors(colors, aBackgroundColor);
574
aContext.SetColor (colors[0]);
576
DrawLine (aContext, theSide[0].x, theSide[0].y, theSide[1].x, theSide[1].y, aGap);
578
FillPolygon (aContext, theSide, np, aGap);
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);
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);
590
//aContext.FillPolygon (theSide, np);
591
FillPolygon (aContext, theSide, np, aGap);
593
np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside,aSkipSides,
594
BORDER_OUTSIDE, 0.333333f, twipsPerPixel);
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);
599
//aContext.FillPolygon (theSide, np);
600
FillPolygon (aContext, theSide, np, aGap);
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));
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);
614
//aContext.FillPolygon (theSide, np);
615
FillPolygon (aContext, theSide, np, aGap);
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,
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);
628
//aContext.FillPolygon (theSide, np);
629
FillPolygon (aContext, theSide, np, aGap);
637
* Draw a dotted/dashed sides of a box
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,
648
/* XXX unused */ nsRect* aGap)
651
nsRect dashRect, firstRect, currRect;
652
PRBool bSolid = PR_TRUE;
654
PRUint8 style = borderStyles[startSide];
655
PRBool skippedSide = PR_FALSE;
657
for (PRIntn whichSide = startSide; whichSide < 4; whichSide++) {
658
PRUint8 prevStyle = style;
659
style = borderStyles[whichSide];
660
if ((1<<whichSide) & aSkipSides) {
662
skippedSide = PR_TRUE;
665
if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
666
(style == NS_STYLE_BORDER_STYLE_DOTTED))
668
if ((style != prevStyle) || skippedSide) {
669
//style discontinuity
674
// XXX units for dash & dot?
675
if (style == NS_STYLE_BORDER_STYLE_DASHED) {
676
dashLength = DASH_LENGTH;
678
dashLength = DOT_LENGTH;
681
aContext.SetColor(borderColors[whichSide]);
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;
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);
697
currRect = firstRect;
702
while (currRect.YMost() > borderInside.y) {
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;
713
aContext.FillRect(currRect);
716
//setup for next iteration
718
bSolid = PRBool(!bSolid);
720
dashRect.y = dashRect.y - currRect.height;
726
//if we are continuing a solid rect, fill in the corner first
728
aContext.FillRect(borderOutside.x, borderOutside.y,
729
borderInside.x - borderOutside.x,
730
borderInside.y - borderOutside.y);
733
dashRect.height = borderInside.y - borderOutside.y;
734
dashRect.width = dashRect.height * dashLength;
735
dashRect.x = borderInside.x;
736
dashRect.y = borderOutside.y;
739
firstRect.x = dashRect.x;
740
firstRect.y = dashRect.y;
741
firstRect.width = nscoord(dashRect.width * over);
742
firstRect.height = dashRect.height;
744
currRect = firstRect;
749
while (currRect.x < borderInside.XMost()) {
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());
760
aContext.FillRect(currRect);
763
//setup for next iteration
765
bSolid = PRBool(!bSolid);
767
dashRect.x = dashRect.x + currRect.width;
773
//if we are continuing a solid rect, fill in the corner first
775
aContext.FillRect(borderInside.XMost(), borderOutside.y,
776
borderOutside.XMost() - borderInside.XMost(),
777
borderInside.y - borderOutside.y);
780
dashRect.width = borderOutside.XMost() - borderInside.XMost();
781
dashRect.height = nscoord(dashRect.width * dashLength);
782
dashRect.x = borderInside.XMost();
783
dashRect.y = borderInside.y;
786
firstRect.x = dashRect.x;
787
firstRect.y = dashRect.y;
788
firstRect.width = dashRect.width;
789
firstRect.height = nscoord(dashRect.height * over);
791
currRect = firstRect;
796
while (currRect.y < borderInside.YMost()) {
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());
807
aContext.FillRect(currRect);
810
//setup for next iteration
812
bSolid = PRBool(!bSolid);
814
dashRect.y = dashRect.y + currRect.height;
820
//if we are continuing a solid rect, fill in the corner first
822
aContext.FillRect(borderInside.XMost(), borderInside.YMost(),
823
borderOutside.XMost() - borderInside.XMost(),
824
borderOutside.YMost() - borderInside.YMost());
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();
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);
838
currRect = firstRect;
843
while (currRect.XMost() > borderInside.x) {
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;
853
aContext.FillRect(currRect);
856
//setup for next iteration
858
bSolid = PRBool(!bSolid);
860
dashRect.x = dashRect.x - currRect.width;
866
skippedSide = PR_FALSE;
870
/** ---------------------------------------------------
871
* See documentation in nsCSSRendering.h
872
* @update 10/22/99 dwc
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,
881
const nsRect& borderOutside,
882
const nsRect& borderInside,
884
/* XXX unused */ nsRect* aGap)
888
nsRect dashRect, currRect;
889
nscoord temp, temp1, adjust;
890
PRBool bSolid = PR_TRUE;
892
PRBool skippedSide = PR_FALSE;
893
const nscolor kBlackColor = NS_RGB(0,0,0);
895
NS_ASSERTION((aDoOutline && aOutlineStyle) || (!aDoOutline && aBorderStyle), "null params not allowed");
896
PRUint8 style = aDoOutline
897
? aOutlineStyle->GetOutlineStyle()
898
: aBorderStyle->GetBorderStyle(startSide);
900
// find the x and y width
901
nscoord xwidth = aDirtyRect.XMost();
902
nscoord ywidth = aDirtyRect.YMost();
904
for (PRIntn whichSide = startSide; whichSide < 4; whichSide++) {
905
PRUint8 prevStyle = style;
907
? aOutlineStyle->GetOutlineStyle()
908
: aBorderStyle->GetBorderStyle(whichSide);
909
if ((1<<whichSide) & aSkipSides) {
911
skippedSide = PR_TRUE;
914
if ((style == NS_STYLE_BORDER_STYLE_DASHED) ||
915
(style == NS_STYLE_BORDER_STYLE_DOTTED))
917
if ((style != prevStyle) || skippedSide) {
918
//style discontinuity
923
if (style == NS_STYLE_BORDER_STYLE_DASHED) {
924
dashLength = DASH_LENGTH;
926
dashLength = DOT_LENGTH;
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;
933
// see if the outline color is 'invert'
934
if (aOutlineStyle->GetOutlineInvert()) {
937
aOutlineStyle->GetOutlineColor(sideColor);
942
aBorderStyle->GetBorderColor(whichSide, sideColor, transparent, foreground);
944
sideColor = aColorStyle->mColor;
946
continue; // side is transparent
948
aContext.SetColor(sideColor);
955
// This is our dot or dash..
956
if(whichSide==NS_SIDE_LEFT){
957
dashRect.width = borderInside.x - borderOutside.x;
959
dashRect.width = borderOutside.XMost() - borderInside.XMost();
961
if( dashRect.width >0 ) {
962
dashRect.height = dashRect.width * dashLength;
963
dashRect.y = borderOutside.y;
965
if(whichSide == NS_SIDE_RIGHT){
966
dashRect.x = borderInside.XMost();
968
dashRect.x = borderOutside.x;
971
temp = borderOutside.YMost();
972
temp1 = temp/dashRect.height;
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);
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);
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;
1004
while(currRect.y<temp) {
1007
FillOrInvertRect(aContext, currRect,isInvert);
1010
bSolid = PRBool(!bSolid);
1011
currRect.y += dashRect.height;
1016
case NS_SIDE_BOTTOM:
1020
// This is our dot or dash..
1022
if(whichSide==NS_SIDE_TOP){
1023
dashRect.height = borderInside.y - borderOutside.y;
1025
dashRect.height = borderOutside.YMost() - borderInside.YMost();
1027
if( dashRect.height >0 ) {
1028
dashRect.width = dashRect.height * dashLength;
1029
dashRect.x = borderOutside.x;
1031
if(whichSide == NS_SIDE_BOTTOM){
1032
dashRect.y = borderInside.YMost();
1034
dashRect.y = borderOutside.y;
1037
temp = borderOutside.XMost();
1038
temp1 = temp/dashRect.width;
1040
currRect = dashRect;
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);
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);
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;
1071
while(currRect.x<temp) {
1074
FillOrInvertRect(aContext, currRect,isInvert);
1077
bSolid = PRBool(!bSolid);
1078
currRect.x += dashRect.width;
1084
skippedSide = PR_FALSE;
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
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,
1102
/* XXX unused */ nsRect* aGap)
1105
nsRect dashRect, currRect;
1107
PRBool bSolid = PR_TRUE;
1109
PRBool skippedSide = PR_FALSE;
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++)
1119
if ((1<<whichSide) & aSkipSides) {
1121
skippedSide = PR_TRUE;
1124
nscoord x=0; nscoord y=0;
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++)
1133
segment = (nsBorderEdge *)(aBorderEdges->mEdges[whichSide].ElementAt(i));
1134
style = segment->mStyle;
1136
// XXX units for dash & dot?
1137
if (style == NS_STYLE_BORDER_STYLE_DASHED) {
1138
dashLength = DASH_LENGTH;
1140
dashLength = DOT_LENGTH;
1143
aContext.SetColor(segment->mColor);
1144
switch (whichSide) {
1146
{ // draw left segment i
1147
nsBorderEdge * topEdge = (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(0));
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;
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))
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)
1171
if (segment->mInsideNeighbor == neighborBorderEdges)
1173
neighborEdgeCount++;
1177
neighborBorderEdges = segment->mInsideNeighbor;
1178
neighborEdgeCount=0;
1180
nsBorderEdge * neighborLeft = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_LEFT].ElementAt(neighborEdgeCount));
1181
totalLength = neighborLeft->mLength;
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
1191
printf(" L: totalLength = %d, borderOutside.y = %d, midpoint %d, dashRect.y = %d\n",
1192
totalLength, borderOutside.y, borderOutside.y +(totalLength/2), dashRect.y);
1194
currRect = dashRect;
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.
1199
// draw the top half
1200
while (currRect.YMost() > borderInside.y) {
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;
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");
1216
aContext.FillRect(currRect);
1219
//setup for next iteration
1221
bSolid = PRBool(!bSolid);
1223
dashRect.y = dashRect.y - currRect.height;
1224
currRect = dashRect;
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;
1234
while (currRect.YMost() < borderInside.YMost()) {
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;
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");
1250
aContext.FillRect(currRect);
1253
//setup for next iteration
1255
bSolid = PRBool(!bSolid);
1257
dashRect.y = dashRect.y + currRect.height;
1258
currRect = dashRect;
1265
{ // draw top segment i
1268
nsBorderEdge * leftEdge = (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_LEFT].ElementAt(0));
1269
x = aBorderEdges->mMaxBorderWidth.left - leftEdge->mWidth;
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))
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));
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)
1293
firstRectWidth = borderInside.x - borderOutside.x;
1294
aContext.FillRect(borderOutside.x, borderOutside.y,
1296
borderInside.y - borderOutside.y);
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;
1305
while (currRect.x < borderInside.XMost()) {
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());
1316
aContext.FillRect(currRect);
1319
//setup for next iteration
1321
bSolid = PRBool(!bSolid);
1323
dashRect.x = dashRect.x + currRect.width;
1324
currRect = dashRect;
1331
{ // draw right segment i
1332
nsBorderEdge * topEdge = (nsBorderEdge *)
1333
(aBorderEdges->mEdges[NS_SIDE_TOP].ElementAt(aBorderEdges->mEdges[NS_SIDE_TOP].Count()-1));
1336
y = aBorderEdges->mMaxBorderWidth.top - topEdge->mWidth;
1337
if (PR_TRUE==aBorderEdges->mOutsideEdge)
1338
y += topEdge->mWidth;
1341
if (PR_TRUE==aBorderEdges->mOutsideEdge)
1343
width = aBounds.width - aBorderEdges->mMaxBorderWidth.right;
1344
width += segment->mWidth;
1348
width = aBounds.width;
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))
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)
1362
if (segment->mInsideNeighbor == neighborBorderEdges)
1364
neighborEdgeCount++;
1368
neighborBorderEdges = segment->mInsideNeighbor;
1369
neighborEdgeCount=0;
1371
nsBorderEdge * neighborRight = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_RIGHT].ElementAt(neighborEdgeCount));
1372
totalLength = neighborRight->mLength;
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;
1382
// draw the top half
1383
while (currRect.YMost() > borderInside.y) {
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;
1394
aContext.FillRect(currRect);
1397
//setup for next iteration
1399
bSolid = PRBool(!bSolid);
1401
dashRect.y = dashRect.y - currRect.height;
1402
currRect = dashRect;
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;
1412
while (currRect.YMost() < borderInside.YMost()) {
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;
1423
aContext.FillRect(currRect);
1426
//setup for next iteration
1428
bSolid = PRBool(!bSolid);
1430
dashRect.y = dashRect.y + currRect.height;
1431
currRect = dashRect;
1438
case NS_SIDE_BOTTOM:
1439
{ // draw bottom segment i
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;
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))
1454
nsRect borderInside(borderOutside);
1455
nsBorderEdge * neighbor;
1456
if (PR_TRUE==aBorderEdges->mOutsideEdge)
1457
neighbor = (nsBorderEdge *)(segment->mInsideNeighbor->mEdges[NS_SIDE_LEFT].ElementAt(0));
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)
1465
firstRectWidth = borderInside.x - borderOutside.x;
1466
aContext.FillRect(borderOutside.x, borderInside.YMost(),
1468
borderOutside.YMost() - borderInside.YMost());
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;
1477
while (currRect.x < borderInside.XMost()) {
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());
1488
aContext.FillRect(currRect);
1491
//setup for next iteration
1493
bSolid = PRBool(!bSolid);
1495
dashRect.x = dashRect.x + currRect.width;
1496
currRect = dashRect;
1503
skippedSide = PR_FALSE;
1508
nsCSSRendering::TransformColor(nscolor aMapColor,PRBool aNoBackGround)
1510
PRUint16 hue,sat,value;
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.
1525
// convert this color back into the RGB color space.
1526
NS_HSV2RGB(newcolor,hue,sat,value);
1532
// method GetBGColorForHTMLElement
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.
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.
1542
PRBool GetBGColorForHTMLElement( nsIPresContext *aPresContext,
1543
const nsStyleBackground *&aBGColor )
1545
NS_ASSERTION(aPresContext, "null params not allowed");
1546
PRBool result = PR_FALSE; // assume we did not find the HTML element
1548
nsIPresShell* shell = aPresContext->GetPresShell();
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)) &&
1563
nsStyleContext *pContext = pFrame->GetStyleContext();
1565
const nsStyleBackground* color = pContext->GetStyleBackground();
1566
if (0 == (color->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT)) {
1568
// set the reslt to TRUE to indicate we mapped the color
1573
}// if tag == html or body
1576
printf( "Root Content is not HTML or BODY: cannot get bgColor of HTML or BODY\n");
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))
1593
PRBool GetBorderColor(const nsStyleColor* aColor, const nsStyleBorder& aBorder, PRUint8 aSide, nscolor& aColorVal,
1594
nsBorderColors** aCompositeColors = nsnull)
1599
if (aCompositeColors) {
1600
aBorder.GetCompositeColors(aSide, aCompositeColors);
1601
if (*aCompositeColors)
1605
aBorder.GetBorderColor(aSide, aColorVal, transparent, foreground);
1607
aColorVal = aColor->mColor;
1609
return !transparent;
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,
1622
nscoord aHardBorderSize,
1623
PRBool aShouldIgnoreRounded)
1627
nsStyleCoord bordStyleRadius[4];
1628
PRInt16 borderRadii[4],i;
1630
nsCompatibility compatMode = aPresContext->CompatibilityMode();
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.
1642
// Get our style context's color struct.
1643
const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
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);
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;
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
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) {
1669
if (bNeedBodyBGColor) {
1670
GetBGColorForHTMLElement(aPresContext, mozBGColor);
1674
if (aHardBorderSize > 0) {
1675
border.SizeTo(aHardBorderSize, aHardBorderSize, aHardBorderSize, aHardBorderSize);
1677
aBorderStyle.CalcBorderFor(aForFrame, border);
1679
if ((0 == border.left) && (0 == border.right) &&
1680
(0 == border.top) && (0 == border.bottom)) {
1681
// Empty border area
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
1694
switch ( bordStyleRadius[i].GetUnit()) {
1695
case eStyleUnit_Percent:
1696
percent = bordStyleRadius[i].GetPercentValue();
1697
borderRadii[i] = (nscoord)(percent * aBorderArea.width);
1699
case eStyleUnit_Coord:
1700
borderRadii[i] = bordStyleRadius[i].GetCoordValue();
1707
// rounded version of the outline
1708
// check for any corner that is rounded
1710
if(borderRadii[i] > 0 && !aBorderStyle.mBorderColors){
1711
PaintRoundedBorder(aPresContext,aRenderingContext,aForFrame,aDirtyRect,aBorderArea,&aBorderStyle,nsnull,aStyleContext,aSkipSides,borderRadii,aGap,PR_FALSE);
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);
1722
// get the inside and outside parts of the border
1723
nsRect outerRect(aBorderArea);
1724
nsRect innerRect(outerRect);
1725
innerRect.Deflate(border);
1727
if (border.left + border.right > aBorderArea.width) {
1728
innerRect.x = outerRect.x;
1729
innerRect.width = outerRect.width;
1731
if (border.top + border.bottom > aBorderArea.height) {
1732
innerRect.y = outerRect.y;
1733
innerRect.height = outerRect.height;
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)) {
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)) {
1752
DrawDashedSides(cnt, aRenderingContext,aDirtyRect, ourColor, &aBorderStyle,nsnull, PR_FALSE,
1753
outerRect, innerRect, aSkipSides, aGap);
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);
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;
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;
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;
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;
1797
/* Get our conversion values */
1798
nscoord twipsPerPixel;
1800
aPresContext->GetScaledPixelsToTwips(&p2t);
1801
twipsPerPixel = NSIntPixelsToTwips(1,p2t);
1803
static PRUint8 sideOrder[] = { NS_SIDE_BOTTOM, NS_SIDE_LEFT, NS_SIDE_TOP, NS_SIDE_RIGHT };
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);
1814
DrawSide(aRenderingContext, side,
1815
aBorderStyle.GetBorderStyle(side),
1817
MOZ_BG_BORDER(aBorderStyle.GetBorderStyle(side)) ?
1818
mozBGColor->mBackgroundColor :
1819
bgColor->mBackgroundColor,
1820
outerRect,innerRect, aSkipSides,
1821
twipsPerPixel, aGap);
1827
void nsCSSRendering::DrawCompositeSide(nsIRenderingContext& aRenderingContext,
1829
nsBorderColors* aCompositeColors,
1830
const nsRect& aOuterRect,
1831
const nsRect& aInnerRect,
1832
PRInt16* aBorderRadii,
1833
nscoord twipsPerPixel,
1837
// Loop over each color and at each iteration shrink the length of the
1838
// lines that we draw.
1839
nsRect currOuterRect(aOuterRect);
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).
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];
1870
while (shrinkage > 0) {
1871
nscoord xshrink = 0;
1872
nscoord yshrink = 0;
1873
nscoord widthshrink = 0;
1874
nscoord heightshrink = 0;
1876
if (startRadius || endRadius) {
1877
if (aWhichSide == NS_SIDE_TOP || aWhichSide == NS_SIDE_BOTTOM) {
1878
xshrink = startRadius;
1879
widthshrink = startRadius + endRadius;
1881
else if (aWhichSide == NS_SIDE_LEFT || aWhichSide == NS_SIDE_RIGHT) {
1882
yshrink = startRadius-1;
1883
heightshrink = yshrink + endRadius;
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;
1894
nsRect borderInside(currOuterRect);
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;
1902
if (borderInside.x+borderInside.width > aInnerRect.x+aInnerRect.width) // shrink right
1903
borderInside.width -= twipsPerPixel;
1905
if (aInnerRect.y > borderInside.y) { // shrink top
1906
borderInside.y += twipsPerPixel;
1907
borderInside.height -= twipsPerPixel;
1909
if (borderInside.y+borderInside.height > aInnerRect.y+aInnerRect.height) // shrink bottom
1910
borderInside.height -= twipsPerPixel;
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);
1920
if (aWhichSide == NS_SIDE_TOP) {
1922
// Connecting line between top/left
1923
nscoord distance = (startRadius+twipsPerPixel)/2;
1924
nscoord remainder = distance%twipsPerPixel;
1926
distance += twipsPerPixel - remainder;
1927
DrawLine(aRenderingContext,
1928
currOuterRect.x+startRadius,
1930
currOuterRect.x+startRadius-distance,
1931
currOuterRect.y+distance,
1935
// Connecting line between top/right
1936
nscoord distance = (endRadius+twipsPerPixel)/2;
1937
nscoord remainder = distance%twipsPerPixel;
1939
distance += twipsPerPixel - remainder;
1940
DrawLine(aRenderingContext,
1941
currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel,
1943
currOuterRect.x+currOuterRect.width-endRadius-twipsPerPixel+distance,
1944
currOuterRect.y+distance,
1948
else if (aWhichSide == NS_SIDE_BOTTOM) {
1950
// Connecting line between bottom/left
1951
nscoord distance = (startRadius+twipsPerPixel)/2;
1952
nscoord remainder = distance%twipsPerPixel;
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,
1963
// Connecting line between bottom/right
1964
nscoord distance = (endRadius+twipsPerPixel)/2;
1965
nscoord remainder = distance%twipsPerPixel;
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,
1976
else if (aWhichSide == NS_SIDE_LEFT) {
1978
// Connecting line between left/top
1979
nscoord distance = (startRadius-twipsPerPixel)/2;
1980
nscoord remainder = distance%twipsPerPixel;
1982
distance -= remainder;
1983
DrawLine(aRenderingContext,
1984
currOuterRect.x+distance,
1985
currOuterRect.y+startRadius-distance,
1987
currOuterRect.y+startRadius,
1991
// Connecting line between left/bottom
1992
nscoord distance = (endRadius-twipsPerPixel)/2;
1993
nscoord remainder = distance%twipsPerPixel;
1995
distance -= remainder;
1996
DrawLine(aRenderingContext,
1997
currOuterRect.x+distance,
1998
currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius+distance,
2000
currOuterRect.y+currOuterRect.height-twipsPerPixel-endRadius,
2004
else if (aWhichSide == NS_SIDE_RIGHT) {
2006
// Connecting line between right/top
2007
nscoord distance = (startRadius-twipsPerPixel)/2;
2008
nscoord remainder = distance%twipsPerPixel;
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,
2019
// Connecting line between right/bottom
2020
nscoord distance = (endRadius-twipsPerPixel)/2;
2021
nscoord remainder = distance%twipsPerPixel;
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,
2034
if (aCompositeColors->mNext)
2035
aCompositeColors = aCompositeColors->mNext;
2037
currOuterRect = borderInside;
2038
shrinkage -= twipsPerPixel;
2040
startRadius -= twipsPerPixel;
2041
if (startRadius < 0) startRadius = 0;
2042
endRadius -= twipsPerPixel;
2043
if (endRadius < 0) endRadius = 0;
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,
2059
nsStyleCoord bordStyleRadius[4];
2060
PRInt16 borderRadii[4],i;
2062
const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
2065
// Get our style context's color struct.
2066
const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
2068
aOutlineStyle.GetOutlineWidth(width);
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
2083
switch ( bordStyleRadius[i].GetUnit()) {
2084
case eStyleUnit_Percent:
2085
percent = bordStyleRadius[i].GetPercentValue();
2086
borderRadii[i] = (nscoord)(percent * aBorderArea.width);
2088
case eStyleUnit_Coord:
2089
borderRadii[i] = bordStyleRadius[i].GetCoordValue();
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
2102
nsRect inside(aBorderArea);
2103
nsRect outside(inside);
2104
inside.Inflate(width, width);
2106
nsRect clipRect(aBorderArea);
2107
clipRect.Inflate(width, width); // make clip extra big for now
2110
nsMargin borderWidth;
2111
aBorderStyle.GetBorder(borderWidth);
2113
nsRect outside(aBorderArea);
2114
outside.Deflate(borderWidth);
2115
nsRect inside(outside);
2116
inside.Deflate(width, width);
2118
nsRect clipRect(outside);
2121
PRBool clipState = PR_FALSE;
2122
aRenderingContext.PushState();
2123
aRenderingContext.SetClipRect(clipRect, nsClipCombine_kReplace, clipState);
2125
// rounded version of the border
2127
if(borderRadii[i] > 0){
2128
PaintRoundedBorder(aPresContext,aRenderingContext,aForFrame,aDirtyRect,aBorderArea,nsnull,&aOutlineStyle,aStyleContext,aSkipSides,borderRadii,aGap,PR_TRUE);
2129
aRenderingContext.PopState(clipState);
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);
2145
// Draw all the other sides
2147
/* XXX something is misnamed here!!!! */
2148
nscoord twipsPerPixel;/* XXX */
2150
p2t = aPresContext->PixelsToTwips();/* XXX */
2151
twipsPerPixel = (nscoord) p2t;/* XXX */
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;
2157
// see if the outline color is 'invert' or can invert.
2158
if (aOutlineStyle.GetOutlineInvert()) {
2160
if( NS_SUCCEEDED(aRenderingContext.SetPenMode(nsPenMode_kInvert)) ) {
2161
modeChanged=PR_TRUE;
2164
canDraw = aOutlineStyle.GetOutlineColor(outlineColor);
2167
if (PR_TRUE == canDraw) {
2168
DrawSide(aRenderingContext, NS_SIDE_BOTTOM,
2171
bgColor->mBackgroundColor, outside, inside, aSkipSides,
2172
twipsPerPixel, aGap);
2174
DrawSide(aRenderingContext, NS_SIDE_LEFT,
2177
bgColor->mBackgroundColor,outside, inside,aSkipSides,
2178
twipsPerPixel, aGap);
2180
DrawSide(aRenderingContext, NS_SIDE_TOP,
2183
bgColor->mBackgroundColor,outside, inside,aSkipSides,
2184
twipsPerPixel, aGap);
2186
DrawSide(aRenderingContext, NS_SIDE_RIGHT,
2189
bgColor->mBackgroundColor,outside, inside,aSkipSides,
2190
twipsPerPixel, aGap);
2193
aRenderingContext.SetPenMode(nsPenMode_kNone);
2197
aRenderingContext.PopState(clipState);
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().
2207
// XXX: doesn't do corners or junctions well at all. Just uses logic stolen
2208
// from PaintBorder which is insufficient
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,
2220
const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
2222
if (nsnull==aBorderEdges) { // Empty border segments
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);
2236
// Draw any dashed or dotted segments separately
2237
DrawDashedSegments(aRenderingContext, aBorderArea, aBorderEdges, aSkipSides, aGap);
2239
// Draw all the other sides
2240
nscoord twipsPerPixel;
2242
p2t = aPresContext->PixelsToTwips();
2243
twipsPerPixel = (nscoord) p2t;/* XXX huh!*/
2245
if (0 == (aSkipSides & (1<<NS_SIDE_TOP))) {
2246
PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_TOP].Count();
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++)
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,
2264
bgColor->mBackgroundColor,
2265
inside, outside,aSkipSides,
2266
twipsPerPixel, aGap);
2269
if (0 == (aSkipSides & (1<<NS_SIDE_LEFT))) {
2270
PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_LEFT].Count();
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++)
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,
2286
bgColor->mBackgroundColor,
2287
inside, outside, aSkipSides,
2288
twipsPerPixel, aGap);
2291
if (0 == (aSkipSides & (1<<NS_SIDE_BOTTOM))) {
2292
PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_BOTTOM].Count();
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++)
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,
2311
bgColor->mBackgroundColor,
2312
inside, outside,aSkipSides,
2313
twipsPerPixel, aGap);
2316
if (0 == (aSkipSides & (1<<NS_SIDE_RIGHT))) {
2317
PRInt32 segmentCount = aBorderEdges->mEdges[NS_SIDE_RIGHT].Count();
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++)
2324
nsBorderEdge * borderEdge = (nsBorderEdge *)(aBorderEdges->mEdges[NS_SIDE_RIGHT].ElementAt(i));
2326
if (PR_TRUE==aBorderEdges->mOutsideEdge)
2328
width = aBorderArea.width - aBorderEdges->mMaxBorderWidth.right;
2329
width += borderEdge->mWidth;
2333
width = aBorderArea.width;
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,
2343
bgColor->mBackgroundColor,
2344
inside, outside,aSkipSides,
2345
twipsPerPixel, aGap);
2351
//----------------------------------------------------------------------
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
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
2362
// i.e., they are either 0 or a negative number whose absolute value is
2363
// less than the tile size in that dimension
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.
2372
ComputeBackgroundAnchorPoint(const nsStyleBackground& aColor,
2373
const nsRect& aOriginBounds,
2374
const nsRect& aClipBounds,
2375
nscoord aTileWidth, nscoord aTileHeight,
2379
if (NS_STYLE_BG_X_POSITION_LENGTH & aColor.mBackgroundFlags) {
2380
x = aColor.mBackgroundXPosition.mCoord;
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;
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
2400
// Some joker gave us max-negative-integer.
2413
NS_POSTCONDITION((x >= -(aTileWidth - 1)) && (x <= 0), "bad computed anchor value");
2418
if (NS_STYLE_BG_Y_POSITION_LENGTH & aColor.mBackgroundFlags) {
2419
y = aColor.mBackgroundYPosition.mCoord;
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;
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
2439
// Some joker gave us max-negative-integer.
2448
y = y - aTileHeight;
2452
NS_POSTCONDITION((y >= -(aTileHeight - 1)) && (y <= 0), "bad computed anchor value");
2457
// Returns the root scrollable frame, which is the first child of the root
2459
static nsIScrollableFrame*
2460
GetRootScrollableFrame(nsIPresContext* aPresContext, nsIFrame* aRootFrame)
2462
nsIScrollableFrame* scrollableFrame = nsnull;
2464
if (nsLayoutAtoms::viewportFrame == aRootFrame->GetType()) {
2465
nsIFrame* childFrame = aRootFrame->GetFirstChild(nsnull);
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);
2479
NS_WARNING("aRootFrame is not a viewport frame");
2483
return scrollableFrame;
2486
const nsStyleBackground*
2487
nsCSSRendering::FindNonTransparentBackground(nsStyleContext* aContext,
2488
PRBool aStartAtParent /*= PR_FALSE*/)
2490
NS_ASSERTION(aContext, "Cannot find NonTransparentBackground in a null context" );
2492
const nsStyleBackground* result = nsnull;
2493
nsStyleContext* context = nsnull;
2494
if (aStartAtParent) {
2495
context = aContext->GetParent();
2502
result = context->GetStyleBackground();
2503
if (0 == (result->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT))
2506
context = context->GetParent();
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:
2517
* The background of the box generated by the root element covers the
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.
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.
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
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.
2552
IsCanvasFrame(nsIPresContext* aPresContext, nsIFrame *aFrame)
2554
nsIAtom* frameType = aFrame->GetType();
2555
if (frameType == nsLayoutAtoms::canvasFrame ||
2556
frameType == nsLayoutAtoms::rootFrame ||
2557
frameType == nsLayoutAtoms::pageFrame) {
2559
} else if (frameType == nsLayoutAtoms::viewportFrame) {
2560
nsIFrame* firstChild = aFrame->GetFirstChild(nsnull);
2570
FindCanvasBackground(nsIPresContext* aPresContext,
2571
nsIFrame* aForFrame,
2572
const nsStyleBackground** aBackground)
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);
2578
const nsStyleBackground* result = firstChild->GetStyleBackground();
2580
// for printing and print preview.. this should be a pageContentFrame
2581
nsStyleContext* parentContext;
2583
if (firstChild->GetType() == nsLayoutAtoms::pageContentFrame) {
2584
// we have to find the background style ourselves.. since the
2585
// pageContentframe does not have content
2587
for (nsIFrame* kidFrame = firstChild; nsnull != kidFrame; ) {
2588
parentContext = kidFrame->GetStyleContext();
2589
result = parentContext->GetStyleBackground();
2590
if (!result->IsTransparent()) {
2591
*aBackground = kidFrame->GetStyleBackground();
2594
kidFrame = kidFrame->GetNextSibling();
2597
firstChild = firstChild->GetFirstChild(nsnull);
2599
return PR_FALSE; // nothing found for this
2602
// Check if we need to do propagation from BODY rather than HTML.
2603
if (result->IsTransparent()) {
2604
nsIContent* content = aForFrame->GetContent();
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);
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.
2627
nsIFrame *bodyFrame;
2628
nsresult rv = aPresContext->PresShell()->
2629
GetPrimaryFrameFor(bodyContent, &bodyFrame);
2630
if (NS_SUCCEEDED(rv) && bodyFrame)
2631
result = bodyFrame->GetStyleBackground();
2638
*aBackground = result;
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
2643
*aBackground = aForFrame->GetStyleBackground();
2650
FindElementBackground(nsIPresContext* aPresContext,
2651
nsIFrame* aForFrame,
2652
const nsStyleBackground** aBackground)
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.
2663
*aBackground = aForFrame->GetStyleBackground();
2665
nsIContent* content = aForFrame->GetContent();
2666
if (!content || !content->IsContentOfType(nsIContent::eHTML))
2667
return PR_TRUE; // not frame for an HTML element
2670
return PR_TRUE; // no parent to look at
2672
if (content->Tag() != nsHTMLAtoms::body)
2673
return PR_TRUE; // not frame for <BODY> element
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));
2683
nsCOMPtr<nsIDocument> document(do_QueryInterface(doc));
2684
if (document->IsCaseSensitive()) // XHTML, not HTML
2687
const nsStyleBackground* htmlBG = parentFrame->GetStyleBackground();
2688
return !htmlBG->IsTransparent();
2692
nsCSSRendering::FindBackground(nsIPresContext* aPresContext,
2693
nsIFrame* aForFrame,
2694
const nsStyleBackground** aBackground,
2697
nsIFrame* canvasFrame = IsCanvasFrame(aPresContext, aForFrame);
2698
*aIsCanvas = canvasFrame != nsnull;
2700
? FindCanvasBackground(aPresContext, canvasFrame, aBackground)
2701
: FindElementBackground(aPresContext, aForFrame, aBackground);
2705
nsCSSRendering::DidPaint()
2707
gInlineBGData.Reset();
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)
2721
NS_PRECONDITION(aForFrame,
2722
"Frame is expected to be provided to PaintBackground");
2725
const nsStyleBackground *color;
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) {
2737
nsIContent* content = aForFrame->GetContent();
2738
if (!content || content->GetParent()) {
2742
color = aForFrame->GetStyleBackground();
2745
PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
2746
aDirtyRect, aBorderArea, *color, aBorder,
2747
aPadding, aUsePrintSettings, aBGClipRect);
2753
nsStyleBackground canvasColor(*color);
2755
nsIViewManager* vm = aPresContext->GetViewManager();
2757
if (canvasColor.mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) {
2759
vm->GetRootView(rootView);
2760
if (!rootView->GetParent()) {
2761
PRBool widgetIsTranslucent = PR_FALSE;
2763
if (rootView->HasWidget()) {
2764
rootView->GetWidget()->GetWindowTranslucency(widgetIsTranslucent);
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();
2776
vm->SetDefaultBackgroundColor(canvasColor.mBackgroundColor);
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();
2785
vm->SetViewBitBltEnabled(view, PR_FALSE);
2788
PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
2789
aDirtyRect, aBorderArea, canvasColor,
2790
aBorder, aPadding, aUsePrintSettings, aBGClipRect);
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)
2805
NS_PRECONDITION(aForFrame,
2806
"Frame is expected to be provided to PaintBackground");
2808
PRBool canDrawBackgroundImage = PR_TRUE;
2809
PRBool canDrawBackgroundColor = PR_TRUE;
2811
if (aUsePrintSettings) {
2812
canDrawBackgroundImage = aPresContext->GetBackgroundImageDraw();
2813
canDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
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);
2831
bgClipArea = *aBGClipRect;
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");
2840
aBorder.GetBorder(border);
2841
bgClipArea.Deflate(border);
2845
// The actual dirty rect is the intersection of the 'background-clip'
2846
// area and the dirty rect we were given
2848
if (!dirtyRect.IntersectRect(bgClipArea, aDirtyRect)) {
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);
2860
// We have a background image
2863
nsCOMPtr<imgIRequest> req;
2864
nsresult rv = aPresContext->LoadImage(aColor.mBackgroundImage, aForFrame, getter_AddRefs(req));
2866
PRUint32 status = imgIRequest::STATUS_ERROR;
2868
req->GetImageStatus(&status);
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);
2876
nsCOMPtr<imgIContainer> image;
2877
req->GetImage(getter_AddRefs(image));
2880
image->GetWidth(&imageSize.width);
2881
image->GetHeight(&imageSize.height);
2884
p2t = aPresContext->PixelsToTwips();
2885
imageSize.width = NSIntPixelsToTwips(imageSize.width, p2t);
2886
imageSize.height = NSIntPixelsToTwips(imageSize.height, p2t);
2890
nsRect bgOriginArea;
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;
2898
case NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX:
2899
bgOriginArea = gInlineBGData.GetBoundingRect(aForFrame);
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);
2910
bgOriginArea = aBorderArea;
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) {
2917
if (!aBorder.GetBorder(border)) {
2918
NS_NOTYETIMPLEMENTED("percentage border");
2921
bgOriginArea.Deflate(border);
2922
if (aColor.mBackgroundOrigin != NS_STYLE_BG_ORIGIN_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");
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;
2943
case NS_STYLE_BG_REPEAT_X:
2944
xDistance = dirtyRect.width;
2945
yDistance = tileHeight;
2947
case NS_STYLE_BG_REPEAT_Y:
2948
xDistance = tileWidth;
2949
yDistance = dirtyRect.height;
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
2957
nsCOMPtr<gfxIImageFrame> gfxImgFrame;
2958
image->GetCurrentFrame(getter_AddRefs(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;
2967
/* check for tiling of a image where frame smaller than container */
2969
image->GetWidth(&iSize.width);
2970
image->GetHeight(&iSize.height);
2972
gfxImgFrame->GetRect(iframeRect);
2973
if (iSize.width != iframeRect.width ||
2974
iSize.height != iframeRect.height) {
2975
needBackgroundColor = PR_TRUE;
2980
case NS_STYLE_BG_REPEAT_OFF:
2982
NS_ASSERTION(repeat == NS_STYLE_BG_REPEAT_OFF, "unknown background-repeat value");
2983
xDistance = tileWidth;
2984
yDistance = tileHeight;
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);
2994
if ((tileWidth == 0) || (tileHeight == 0) || dirtyRect.IsEmpty()) {
2995
// Nothing left to paint
2999
// Compute the anchor point.
3001
// When tiling, the anchor coordinate values will be negative offsets
3002
// from the background-origin area.
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;
3011
nsIFrame* rootFrame;
3012
aPresContext->PresShell()->GetRootFrame(&rootFrame);
3013
NS_ASSERTION(rootFrame, "no root frame");
3015
if (aPresContext->IsPaginated()) {
3016
nsIFrame* page = nsLayoutUtils::GetPageFrame(aForFrame);
3017
NS_ASSERTION(page, "no page");
3021
viewportView = rootFrame->GetView();
3022
NS_ASSERTION(viewportView, "no viewport view");
3023
viewportArea = viewportView->GetBounds();
3027
nsIScrollableFrame* scrollableFrame =
3028
GetRootScrollableFrame(aPresContext, rootFrame);
3030
if (scrollableFrame) {
3031
nsMargin scrollbars = scrollableFrame->GetActualScrollbarSizes();
3032
viewportArea.Deflate(scrollbars);
3035
// Get the anchor point
3036
ComputeBackgroundAnchorPoint(aColor, viewportArea, viewportArea, tileWidth, tileHeight, anchor);
3038
// Convert the anchor point to aForFrame's coordinate space
3039
nsIView* view = aForFrame->GetView();
3042
aForFrame->GetOffsetFromView(aPresContext, offset, &view);
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();
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|.");
3062
// temporary null check -- see bug 97226
3063
if (firstRootElementFrame) {
3064
firstRootElementFrameArea = firstRootElementFrame->GetRect();
3066
// Take the border out of the frame's rect
3067
const nsStyleBorder* borderStyle = firstRootElementFrame->GetStyleBorder();
3069
borderStyle->GetBorder(border);
3070
firstRootElementFrameArea.Deflate(border);
3072
// Get the anchor point
3073
ComputeBackgroundAnchorPoint(aColor, firstRootElementFrameArea, bgClipArea, tileWidth, tileHeight, anchor);
3075
ComputeBackgroundAnchorPoint(aColor, bgOriginArea, bgClipArea, tileWidth, tileHeight, anchor);
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);
3085
#if (!defined(XP_UNIX) && !defined(XP_BEOS)) || defined(XP_MACOSX)
3086
// Setup clipping so that rendering doesn't leak out of the computed
3089
aRenderingContext.PushState();
3090
aRenderingContext.SetClipRect(dirtyRect, nsClipCombine_kIntersect,
3094
// Compute the x and y starting points and limits for tiling
3096
/* An Overview Of The Following Logic
3098
A........ . . . . . . . . . . . . . .
3099
: +---:-------.-------.-------.---- /|\
3101
:.......: . . . x . . . . . . . . . . \|/
3103
. | . . ########### .
3104
. . . . . . . . . .#. . . . .#. . . .
3105
. | . . ########### . /|\
3107
. . | . . . . . . . . . . . . . z . . \|/
3109
|<-----nw------>| |<--w-->|
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.
3115
.... = the primary tile.
3117
. . = the other tiles.
3119
#### = the dirtyRect. This is the minimum region we want to cover.
3121
A = The anchor point. This is the point at which the tile should
3122
start. Always negative or zero.
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.
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
3132
w = the width of the tile (tileWidth).
3134
h = the height of the tile (tileHeight).
3136
n = the number of whole tiles that fit between 'A' and 'x'.
3137
(the vertical n and the horizontal n are different)
3142
x0 = bgClipArea.x + anchor.x + n * tileWidth;
3144
...where n is an integer greater or equal to 0 fitting:
3147
dirtyRect.x - (bgClipArea.x + anchor.x) <=
3152
n <= (dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth < n + 1
3154
...which, treating the division as an integer divide rounding down, gives:
3156
n = (dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth
3158
Substituting into the original expression for x0:
3160
x0 = bgClipArea.x + anchor.x +
3161
((dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth) *
3164
From this x1 is determined,
3166
x1 = x0 + m * tileWidth;
3168
...where m is an integer greater than 0 fitting:
3170
(m - 1) * tileWidth <
3171
dirtyRect.x + dirtyRect.width - x0 <=
3176
m - 1 < (dirtyRect.x + dirtyRect.width - x0) / tileWidth <= m
3178
...which, treating the division as an integer divide, and making it
3181
m = (dirtyRect.x + dirtyRect.width - x0 + tileWidth - 1) / tileWidth
3183
Substituting into the original expression for x1:
3185
x1 = x0 + ((dirtyRect.x + dirtyRect.width - x0 + tileWidth - 1) /
3186
tileWidth) * tileWidth
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
3194
// first do the horizontal case
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) ?
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.
3206
((dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth) * tileWidth;
3207
x1 = x0 + ((dirtyRect.x + dirtyRect.width - x0 + tileWidth - 1) / tileWidth) * tileWidth;
3211
x1 = x0 + tileWidth;
3214
// now do all that again with the vertical case
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) ?
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.
3226
((dirtyRect.y - (bgClipArea.y + anchor.y)) / tileHeight) * tileHeight;
3227
y1 = y0 + ((dirtyRect.y + dirtyRect.height - y0 + tileHeight - 1) / tileHeight) * tileHeight;
3231
y1 = y0 + tileHeight;
3234
// Take the intersection again to paint only the required area
3235
nsRect tileRect(x0, y0, (x1 - x0), (y1 - y0));
3238
if (drawRect.IntersectRect(tileRect, dirtyRect))
3239
aRenderingContext.DrawTile(image, x0, y0, &drawRect);
3241
#if (!defined(XP_UNIX) && !defined(XP_BEOS)) || defined(XP_MACOSX)
3243
aRenderingContext.PopState(clipState);
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)
3258
if (aColor.mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) {
3263
nsStyleCoord bordStyleRadius[4];
3264
PRInt16 borderRadii[4];
3265
nsRect bgClipArea(aBgClipArea);
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
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);
3280
case eStyleUnit_Coord:
3281
borderRadii[side] = bordStyleRadius[side].GetCoordValue();
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,
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.
3307
aBorder.GetBorder(border);
3308
bgClipArea.Deflate(border);
3311
nscolor color = aColor.mBackgroundColor;
3312
if (!aCanPaintNonWhite) {
3313
color = NS_RGB(255, 255, 255);
3315
aRenderingContext.SetColor(color);
3316
aRenderingContext.FillRect(bgClipArea);
3319
/** ---------------------------------------------------
3320
* See documentation in nsCSSRendering.h
3321
* @update 3/26/99 dwc
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)
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];
3340
nscoord twipsPerPixel;
3343
// needed for our border thickness
3344
p2t = aPresContext->PixelsToTwips();
3345
twipsPerPixel = NSToCoordRound(p2t);
3347
nscolor color = aColor.mBackgroundColor;
3348
if (!aCanPaintNonWhite) {
3349
color = NS_RGB(255, 255, 255);
3351
aRenderingContext.SetColor(color);
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");
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.
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) {
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);
3376
// BUILD THE ENTIRE OUTSIDE PATH
3377
// TOP LINE ----------------------------------------------------------------
3378
UL.MidPointDivide(&cr1,&cr2);
3379
UR.MidPointDivide(&cr3,&cr4);
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);
3388
polyPath[0].x = NSToCoordRound(thePath[0].x);
3389
polyPath[0].y = NSToCoordRound(thePath[0].y);
3391
GetPath(thePath,polyPath,&curIndex,eOutside,c1Index);
3393
// RIGHT LINE ----------------------------------------------------------------
3394
LR.MidPointDivide(&cr2,&cr3);
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);
3404
// BOTTOM LINE ----------------------------------------------------------------
3405
LL.MidPointDivide(&cr2,&cr4);
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);
3415
// LEFT LINE ----------------------------------------------------------------
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);
3425
aRenderingContext.FillPolygon(polyPath,curIndex);
3429
/** ---------------------------------------------------
3430
* See documentation in nsCSSRendering.h
3431
* @update 3/26/99 dwc
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,
3443
PRInt16 aBorderRadius[4],
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];
3455
nscoord twipsPerPixel,qtwips;
3458
NS_ASSERTION((aIsOutline && aOutlineStyle) || (!aIsOutline && aBorderStyle), "null params not allowed");
3460
aBorderStyle->CalcBorderFor(aForFrame, border);
3461
if ((0 == border.left) && (0 == border.right) &&
3462
(0 == border.top) && (0 == border.bottom)) {
3467
if (!aOutlineStyle->GetOutlineWidth(width)) {
3470
border.left = width;
3471
border.right = width;
3473
border.bottom = width;
3476
// needed for our border thickness
3477
p2t = aPresContext->PixelsToTwips();
3478
twipsPerPixel = NSToCoordRound(p2t);
3480
// Base our thickness check on the segment being less than a pixel and 1/2
3481
qtwips = twipsPerPixel >> 2;
3482
//qtwips = twipsPerPixel;
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);
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);
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);
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);
3510
// RIGHT LINE ----------------------------------------------------------------
3511
LR.MidPointDivide(&cr2,&cr3);
3512
ILR.MidPointDivide(&Icr2,&Icr3);
3513
if(0!=border.right){
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);
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);
3531
// bottom line ----------------------------------------------------------------
3532
LL.MidPointDivide(&cr2,&cr4);
3533
ILL.MidPointDivide(&Icr2,&Icr4);
3534
if(0!=border.bottom){
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);
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);
3551
// left line ----------------------------------------------------------------
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);
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);
3570
RenderSide(thePath,aRenderingContext,aBorderStyle,aOutlineStyle,aStyleContext,NS_SIDE_LEFT,border,qtwips, aIsOutline);
3574
/** ---------------------------------------------------
3575
* See documentation in nsCSSRendering.h
3576
* @update 3/26/99 dwc
3579
nsCSSRendering::RenderSide(nsFloatPoint aPoints[],nsIRenderingContext& aRenderingContext,
3580
const nsStyleBorder* aBorderStyle,const nsStyleOutline* aOutlineStyle,nsStyleContext* aStyleContext,
3581
PRUint8 aSide,nsMargin &aBorThick,nscoord aTwipsPerPixel,
3585
nscolor sideColor = NS_RGB(0,0,0);
3586
static nsPoint polypath[MAXPOLYPATHSIZE];
3587
PRInt32 curIndex,c1Index,c2Index,junk;
3588
PRInt8 border_Style;
3591
// Get our style context's color struct.
3592
const nsStyleColor* ourColor = aStyleContext->GetStyleColor();
3594
NS_ASSERTION((aIsOutline && aOutlineStyle) || (!aIsOutline && aBorderStyle), "null params not allowed");
3595
// set the style information
3597
if (!GetBorderColor(ourColor, *aBorderStyle, aSide, sideColor)) {
3601
aOutlineStyle->GetOutlineColor(sideColor);
3603
aRenderingContext.SetColor ( sideColor );
3608
thickness = aBorThick.left;
3611
thickness = aBorThick.top;
3614
thickness = aBorThick.right;
3616
case NS_SIDE_BOTTOM:
3617
thickness = aBorThick.bottom;
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);
3632
border_Style = aBorderStyle->GetBorderStyle(aSide);
3634
border_Style = aOutlineStyle->GetOutlineStyle();
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:
3643
const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
3644
if (border_Style == NS_STYLE_BORDER_STYLE_BG_SOLID) {
3646
NS_Get3DColors(colors, bgColor->mBackgroundColor);
3647
aRenderingContext.SetColor(colors[0]);
3649
aRenderingContext.SetColor(MakeBevelColor(aSide, border_Style, bgColor->mBackgroundColor, sideColor,
3650
!MOZ_BG_BORDER(border_Style)));
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);
3663
GetPath(aPoints,polypath,&curIndex,eOutside,c1Index);
3665
polypath[curIndex].x = NSToCoordRound(aPoints[6].x);
3666
polypath[curIndex].y = NSToCoordRound(aPoints[6].y);
3668
GetPath(aPoints,polypath,&curIndex,eInside,junk);
3669
polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
3670
polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
3672
aRenderingContext.FillPolygon(polypath,curIndex);
3675
case NS_STYLE_BORDER_STYLE_DOUBLE:
3676
polypath[0].x = NSToCoordRound(aPoints[0].x);
3677
polypath[0].y = NSToCoordRound(aPoints[0].y);
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);
3684
GetPath(aPoints,polypath,&curIndex,eInside,c1Index);
3685
aRenderingContext.DrawPolyline(polypath,curIndex);
3687
case NS_STYLE_BORDER_STYLE_NONE:
3688
case NS_STYLE_BORDER_STYLE_HIDDEN:
3690
case NS_STYLE_BORDER_STYLE_RIDGE:
3691
case NS_STYLE_BORDER_STYLE_GROOVE:
3693
const nsStyleBackground* bgColor = nsCSSRendering::FindNonTransparentBackground(aStyleContext);
3694
aRenderingContext.SetColor ( MakeBevelColor (aSide, border_Style, bgColor->mBackgroundColor,sideColor, PR_TRUE));
3696
polypath[0].x = NSToCoordRound(aPoints[0].x);
3697
polypath[0].y = NSToCoordRound(aPoints[0].y);
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);
3703
GetPath(aPoints,polypath,&curIndex,eCalcRev,c1Index,.5);
3704
polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
3705
polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
3707
aRenderingContext.FillPolygon(polypath,curIndex);
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));
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);
3718
GetPath(aPoints,polypath,&curIndex,eCalc,c1Index,.5);
3719
polypath[curIndex].x = NSToCoordRound(aPoints[6].x) ;
3720
polypath[curIndex].y = NSToCoordRound(aPoints[6].y);
3722
GetPath(aPoints,polypath,&curIndex,eInside,c1Index);
3723
polypath[curIndex].x = NSToCoordRound(aPoints[0].x);
3724
polypath[curIndex].y = NSToCoordRound(aPoints[0].y);
3726
aRenderingContext.FillPolygon(polypath,curIndex);
3735
/** ---------------------------------------------------
3736
* See documentation in nsCSSRendering.h
3737
* @update 3/26/99 dwc
3740
RoundedRect::CalcInsetCurves(QBCurve &aULCurve,QBCurve &aURCurve,QBCurve &aLLCurve,QBCurve &aLRCurve,nsMargin &aBorder)
3742
PRInt32 nLeft,nTop,nRight,nBottom;
3743
PRInt32 tLeft,bLeft,tRight,bRight,lTop,rTop,lBottom,rBottom;
3747
adjust = mRoundness[0]>>3;
3749
nLeft = mLeft + aBorder.left;
3750
tLeft = mLeft + mRoundness[0];
3751
bLeft = mLeft + mRoundness[3];
3761
nRight = mRight - aBorder.right;
3762
tRight = mRight - mRoundness[1];
3763
bRight = mRight - mRoundness[2];
3765
if(tRight > nRight){
3769
if(bRight > nRight){
3773
nTop = mTop + aBorder.top;
3774
lTop = mTop + mRoundness[0];
3775
rTop = mTop + mRoundness[1];
3785
nBottom = mBottom - aBorder.bottom;
3786
lBottom = mBottom - mRoundness[3];
3787
rBottom = mBottom - mRoundness[2];
3789
if(lBottom > nBottom){
3793
if(rBottom > nBottom){
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);
3814
/** ---------------------------------------------------
3815
* See documentation in nsCSSRendering.h
3816
* @update 4/13/99 dwc
3819
RoundedRect::Set(nscoord aLeft,nscoord aTop,PRInt32 aWidth,PRInt32 aHeight,PRInt16 aRadius[4],PRInt16 aNumTwipPerPix)
3821
nscoord x,y,width,height;
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;
3832
if( (aRadius[i]) > (aWidth>>1) ){
3833
mRoundness[i] = (aWidth>>1);
3835
mRoundness[i] = aRadius[i];
3838
if( mRoundness[i] > (aHeight>>1) )
3839
mRoundness[i] = aHeight>>1;
3843
// if we are drawing a circle
3844
mDoRound = PR_FALSE;
3845
if(aHeight==aWidth){
3846
PRBool doRound = PR_TRUE;
3848
if(mRoundness[i]<(aWidth>>1)){
3857
mRoundness[i] = aWidth>>1;
3864
// important coordinates that the path hits
3872
/** ---------------------------------------------------
3873
* See documentation in nsCSSRendering.h
3874
* @update 4/13/99 dwc
3877
RoundedRect::GetRoundedBorders(QBCurve &aULCurve,QBCurve &aURCurve,QBCurve &aLLCurve,QBCurve &aLRCurve)
3883
adjust = mRoundness[0]>>3;
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]);
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
3910
GetPath(nsFloatPoint aPoints[],nsPoint aPolyPath[],PRInt32 *aCurIndex,ePathTypes aPathType,PRInt32 &aC1Index,float aFrac)
3914
switch (aPathType) {
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;
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);
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;
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);
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);
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);
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);
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);
3963
/** ---------------------------------------------------
3964
* See documentation in nsCSSRendering.h
3965
* @update 4/13/99 dwc
3968
QBCurve::SubDivide(nsIRenderingContext *aRenderingContext,nsPoint aPointArray[],PRInt32 *aCurIndex)
3970
QBCurve curve1,curve2;
3973
// divide the curve into 2 pieces
3974
MidPointDivide(&curve1,&curve2);
3976
fx = (float)fabs(curve1.mAnc2.x - this->mCon.x);
3977
fy = (float)fabs(curve1.mAnc2.y - this->mCon.y);
3979
//smag = fx+fy-(PR_MIN(fx,fy)>>1);
3980
smag = fx*fx + fy*fy;
3983
// split the curve again
3984
curve1.SubDivide(aRenderingContext,aPointArray,aCurIndex);
3985
curve2.SubDivide(aRenderingContext,aPointArray,aCurIndex);
3988
// save the points for further processing
3989
aPointArray[*aCurIndex].x = (nscoord)curve1.mAnc2.x;
3990
aPointArray[*aCurIndex].y = (nscoord)curve1.mAnc2.y;
3992
aPointArray[*aCurIndex].x = (nscoord)curve2.mAnc2.x;
3993
aPointArray[*aCurIndex].y = (nscoord)curve2.mAnc2.y;
3997
nsTransform2D *aTransform;
3998
aRenderingContext->GetCurrentTransform(aTransform);
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);
4007
/** ---------------------------------------------------
4008
* See documentation in nsCSSRendering.h
4009
* @update 4/13/99 dwc
4012
QBCurve::MidPointDivide(QBCurve *A,QBCurve *B)
4014
float c1x,c1y,c2x,c2y;
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;
4022
a1.x = (c1x + c2x)/2.0f;
4023
a1.y = (c1y + c2y)/2.0f;
4025
// put the math into our 2 new curves
4026
A->mAnc1 = this->mAnc1;
4033
B->mAnc2 = this->mAnc2;
4036
void FillOrInvertRect(nsIRenderingContext& aRC, nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aInvert)
4039
aRC.InvertRect(aX, aY, aWidth, aHeight);
4041
aRC.FillRect(aX, aY, aWidth, aHeight);
4045
void FillOrInvertRect(nsIRenderingContext& aRC, const nsRect& aRect, PRBool aInvert)
4048
aRC.InvertRect(aRect);
4050
aRC.FillRect(aRect);
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
4059
RoundIntToPixel(nscoord aValue,
4060
nscoord aTwipsPerPixel,
4061
PRBool aRoundDown = PR_FALSE)
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.
4068
nscoord halfPixel = NSToCoordRound(aTwipsPerPixel / 2.0f);
4069
nscoord extra = aValue % aTwipsPerPixel;
4070
nscoord finalValue = (!aRoundDown && (extra >= halfPixel)) ? aValue + (aTwipsPerPixel - extra) : aValue - extra;
4075
RoundFloatToPixel(float aValue,
4076
nscoord aTwipsPerPixel,
4077
PRBool aRoundDown = PR_FALSE)
4079
return RoundIntToPixel(NSToCoordRound(aValue), aTwipsPerPixel, aRoundDown);
4083
SetPoly(const nsRect& aRect,
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;
4099
DrawSolidBorderSegment(nsIRenderingContext& aContext,
4101
nscoord aTwipsPerPixel,
4102
PRUint8 aStartBevelSide = 0,
4103
nscoord aStartBevelOffset = 0,
4104
PRUint8 aEndBevelSide = 0,
4105
nscoord aEndBevelOffset = 0)
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);
4115
aContext.FillRect(aRect);
4118
if (1 == aRect.width)
4119
aContext.DrawLine(aRect.x, aRect.y, aRect.x + aRect.width, aRect.y);
4121
aContext.FillRect(aRect);
4125
// polygon with beveling
4127
SetPoly(aRect, poly);
4128
switch(aStartBevelSide) {
4130
poly[0].x += aStartBevelOffset;
4131
poly[4].x = poly[0].x;
4133
case NS_SIDE_BOTTOM:
4134
poly[3].x += aStartBevelOffset;
4137
poly[1].y += aStartBevelOffset;
4140
poly[0].y += aStartBevelOffset;
4141
poly[4].y = poly[0].y;
4144
switch(aEndBevelSide) {
4146
poly[1].x -= aEndBevelOffset;
4148
case NS_SIDE_BOTTOM:
4149
poly[2].x -= aEndBevelOffset;
4152
poly[2].y -= aEndBevelOffset;
4155
poly[3].y -= aEndBevelOffset;
4158
aContext.FillPolygon(poly, 5);
4165
GetDashInfo(nscoord aBorderLength,
4166
nscoord aDashLength,
4167
nscoord aTwipsPerPixel,
4168
PRInt32& aNumDashSpaces,
4169
nscoord& aStartDashLength,
4170
nscoord& aEndDashLength)
4173
if (aStartDashLength + aDashLength + aEndDashLength >= aBorderLength) {
4174
aStartDashLength = aBorderLength;
4178
aNumDashSpaces = aBorderLength / (2 * aDashLength); // round down
4179
nscoord extra = aBorderLength - aStartDashLength - aEndDashLength - (((2 * aNumDashSpaces) - 1) * aDashLength);
4181
nscoord half = RoundIntToPixel(extra / 2, aTwipsPerPixel);
4182
aStartDashLength += half;
4183
aEndDashLength += (extra - half);
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)
4200
aContext.SetColor (aBorderColor);
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;
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;
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");
4218
case NS_STYLE_BORDER_STYLE_DOTTED:
4219
case NS_STYLE_BORDER_STYLE_DASHED:
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;
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);
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);
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);
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;
4269
MakeBevelColor (ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor, PR_TRUE));
4270
nsRect rect(aBorder);
4272
if (horizontal) { // top, bottom
4273
half = RoundFloatToPixel(0.5f * (float)aBorder.height, twipsPerPixel);
4275
if (NS_SIDE_TOP == aStartBevelSide) {
4276
rect.x += startBevel;
4277
rect.width -= startBevel;
4279
if (NS_SIDE_TOP == aEndBevelSide) {
4280
rect.width -= endBevel;
4282
DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
4283
startBevel, aEndBevelSide, endBevel);
4285
else { // left, right
4286
half = RoundFloatToPixel(0.5f * (float)aBorder.width, twipsPerPixel);
4288
if (NS_SIDE_LEFT == aStartBevelSide) {
4289
rect.y += startBevel;
4290
rect.height -= startBevel;
4292
if (NS_SIDE_LEFT == aEndBevelSide) {
4293
rect.height -= endBevel;
4295
DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
4296
startBevel, aEndBevelSide, endBevel);
4300
ridgeGrooveSide = (NS_SIDE_TOP == ridgeGrooveSide) ? NS_SIDE_BOTTOM : NS_SIDE_RIGHT;
4302
MakeBevelColor (ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor, PR_TRUE));
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;
4310
if (NS_SIDE_BOTTOM == aEndBevelSide) {
4311
rect.width -= endBevel;
4313
DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
4314
startBevel, aEndBevelSide, endBevel);
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;
4323
if (NS_SIDE_RIGHT == aEndBevelSide) {
4324
rect.height -= endBevel;
4326
DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
4327
startBevel, aEndBevelSide, endBevel);
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);
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;
4346
if (NS_SIDE_TOP == aEndBevelSide) {
4347
topRect.width -= aEndBevelOffset - endBevel;
4349
DrawSolidBorderSegment(aContext, topRect, twipsPerPixel, aStartBevelSide,
4350
startBevel, aEndBevelSide, endBevel);
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;
4359
if (NS_SIDE_BOTTOM == aEndBevelSide) {
4360
bottomRect.width -= aEndBevelOffset - endBevel;
4362
DrawSolidBorderSegment(aContext, bottomRect, twipsPerPixel, aStartBevelSide,
4363
startBevel, aEndBevelSide, endBevel);
4365
else { // left, right
4366
nscoord thirdWidth = RoundFloatToPixel(0.333333f * (float)aBorder.width, twipsPerPixel);
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;
4373
if (NS_SIDE_LEFT == aEndBevelSide) {
4374
leftRect.height -= aEndBevelOffset - endBevel;
4376
DrawSolidBorderSegment(aContext, leftRect, twipsPerPixel, aStartBevelSide,
4377
startBevel, aEndBevelSide, endBevel);
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;
4385
if (NS_SIDE_RIGHT == aEndBevelSide) {
4386
rightRect.height -= aEndBevelOffset - endBevel;
4388
DrawSolidBorderSegment(aContext, rightRect, twipsPerPixel, aStartBevelSide,
4389
startBevel, aEndBevelSide, endBevel);
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);
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");
4408
// End table border-collapsing section