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: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
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.
24 * Mats Palmgren <mats.palmgren@bredband.net>
25 * Takeshi Ichimaru <ayakawa.m@gmail.com>
26 * Masayuki Nakano <masayuki@d-toybox.com>
27 * L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
28 * Michael Ventnor <m.ventnor@gmail.com>
29 * Rob Arnold <robarnold@mozilla.com>
31 * Alternatively, the contents of this file may be used under the terms of
32 * either of the GNU General Public License Version 2 or later (the "GPL"),
33 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 * in which case the provisions of the GPL or the LGPL are applicable instead
35 * of those above. If you wish to allow use of your version of this file only
36 * under the terms of either the GPL or the LGPL, and not to allow others to
37 * use your version of this file under the terms of the MPL, indicate your
38 * decision by deleting the provisions above and replace them with the notice
39 * and other provisions required by the GPL or the LGPL. If you do not delete
40 * the provisions above, a recipient may use your version of this file under
41 * the terms of any one of the MPL, the GPL or the LGPL.
43 * ***** END LICENSE BLOCK ***** */
45 /* utility functions for drawing borders and backgrounds */
47 #include "nsStyleConsts.h"
48 #include "nsPresContext.h"
53 #include "nsIViewManager.h"
54 #include "nsIPresShell.h"
55 #include "nsFrameManager.h"
56 #include "nsStyleContext.h"
57 #include "nsGkAtoms.h"
58 #include "nsCSSAnonBoxes.h"
59 #include "nsTransform2D.h"
60 #include "nsIDeviceContext.h"
61 #include "nsIContent.h"
62 #include "nsIDocument.h"
63 #include "nsIScrollableFrame.h"
64 #include "imgIRequest.h"
65 #include "imgIContainer.h"
66 #include "gfxIImageFrame.h"
67 #include "nsCSSRendering.h"
68 #include "nsCSSColorUtils.h"
70 #include "nsThemeConstants.h"
71 #include "nsIServiceManager.h"
72 #include "nsIHTMLDocument.h"
73 #include "nsLayoutUtils.h"
74 #include "nsINameSpaceManager.h"
75 #include "nsBlockFrame.h"
76 #include "gfxContext.h"
77 #include "nsIInterfaceRequestorUtils.h"
78 #include "gfxPlatform.h"
79 #include "gfxImageSurface.h"
80 #include "nsStyleStructInlines.h"
81 #include "nsCSSFrameConstructor.h"
83 #include "nsCSSRenderingBorders.h"
85 // To avoid storing this data on nsInlineFrame (bloat) and to avoid
86 // recalculating this for each frame in a continuation (perf), hold
87 // a cache of various coordinate information that we need in order
88 // to paint inline backgrounds.
89 struct InlineBackgroundData
91 InlineBackgroundData()
92 : mFrame(nsnull
), mBlockFrame(nsnull
)
96 ~InlineBackgroundData()
102 mBoundingBox
.SetRect(0,0,0,0);
103 mContinuationPoint
= mLineContinuationPoint
= mUnbrokenWidth
= 0;
104 mFrame
= mBlockFrame
= nsnull
;
107 nsRect
GetContinuousRect(nsIFrame
* aFrame
)
113 x
= mLineContinuationPoint
;
115 // Scan continuations on the same line as aFrame and accumulate the widths
116 // of frames that are to the left (if this is an LTR block) or right
117 // (if it's RTL) of the current one.
118 PRBool isRtlBlock
= (mBlockFrame
->GetStyleVisibility()->mDirection
==
119 NS_STYLE_DIRECTION_RTL
);
120 nscoord curOffset
= aFrame
->GetOffsetTo(mBlockFrame
).x
;
122 nsIFrame
* inlineFrame
= aFrame
->GetPrevContinuation();
123 // If the continuation is fluid we know inlineFrame is not on the same line.
124 // If it's not fluid, we need to test furhter to be sure.
125 while (inlineFrame
&& !inlineFrame
->GetNextInFlow() &&
126 AreOnSameLine(aFrame
, inlineFrame
)) {
127 nscoord frameXOffset
= inlineFrame
->GetOffsetTo(mBlockFrame
).x
;
128 if(isRtlBlock
== (frameXOffset
>= curOffset
)) {
129 x
+= inlineFrame
->GetSize().width
;
131 inlineFrame
= inlineFrame
->GetPrevContinuation();
134 inlineFrame
= aFrame
->GetNextContinuation();
135 while (inlineFrame
&& !inlineFrame
->GetPrevInFlow() &&
136 AreOnSameLine(aFrame
, inlineFrame
)) {
137 nscoord frameXOffset
= inlineFrame
->GetOffsetTo(mBlockFrame
).x
;
138 if(isRtlBlock
== (frameXOffset
>= curOffset
)) {
139 x
+= inlineFrame
->GetSize().width
;
141 inlineFrame
= inlineFrame
->GetNextContinuation();
144 // aFrame itself is also to the right of its left edge, so add its width.
145 x
+= aFrame
->GetSize().width
;
146 // x is now the distance from the left edge of aFrame to the right edge
147 // of the unbroken content. Change it to indicate the distance from the
148 // left edge of the unbroken content to the left edge of aFrame.
149 x
= mUnbrokenWidth
- x
;
152 x
= mContinuationPoint
;
155 // Assume background-origin: border and return a rect with offsets
156 // relative to (0,0). If we have a different background-origin,
157 // then our rect should be deflated appropriately by our caller.
158 return nsRect(-x
, 0, mUnbrokenWidth
, mFrame
->GetSize().height
);
161 nsRect
GetBoundingRect(nsIFrame
* aFrame
)
165 // Move the offsets relative to (0,0) which puts the bounding box into
166 // our coordinate system rather than our parent's. We do this by
167 // moving it the back distance from us to the bounding box.
168 // This also assumes background-origin: border, so our caller will
169 // need to deflate us if needed.
170 nsRect
boundingBox(mBoundingBox
);
171 nsPoint point
= mFrame
->GetPosition();
172 boundingBox
.MoveBy(-point
.x
, -point
.y
);
179 nscoord mContinuationPoint
;
180 nscoord mUnbrokenWidth
;
184 nsBlockFrame
* mBlockFrame
;
185 nscoord mLineContinuationPoint
;
187 void SetFrame(nsIFrame
* aFrame
)
189 NS_PRECONDITION(aFrame
, "Need a frame");
191 nsIFrame
*prevContinuation
= aFrame
->GetPrevContinuation();
193 if (!prevContinuation
|| mFrame
!= prevContinuation
) {
194 // Ok, we've got the wrong frame. We have to start from scratch.
200 // Get our last frame's size and add its width to our continuation
201 // point before we cache the new frame.
202 mContinuationPoint
+= mFrame
->GetSize().width
;
204 // If this a new line, update mLineContinuationPoint.
206 (aFrame
->GetPrevInFlow() || !AreOnSameLine(mFrame
, aFrame
))) {
207 mLineContinuationPoint
= mContinuationPoint
;
213 void Init(nsIFrame
* aFrame
)
215 // Start with the previous flow frame as our continuation point
216 // is the total of the widths of the previous frames.
217 nsIFrame
* inlineFrame
= aFrame
->GetPrevContinuation();
219 while (inlineFrame
) {
220 nsRect rect
= inlineFrame
->GetRect();
221 mContinuationPoint
+= rect
.width
;
222 mUnbrokenWidth
+= rect
.width
;
223 mBoundingBox
.UnionRect(mBoundingBox
, rect
);
224 inlineFrame
= inlineFrame
->GetPrevContinuation();
227 // Next add this frame and subsequent frames to the bounding box and
229 inlineFrame
= aFrame
;
230 while (inlineFrame
) {
231 nsRect rect
= inlineFrame
->GetRect();
232 mUnbrokenWidth
+= rect
.width
;
233 mBoundingBox
.UnionRect(mBoundingBox
, rect
);
234 inlineFrame
= inlineFrame
->GetNextContinuation();
239 mBidiEnabled
= aFrame
->PresContext()->BidiEnabled();
241 // Find the containing block frame
242 nsIFrame
* frame
= aFrame
;
243 nsresult rv
= NS_ERROR_FAILURE
;
245 frame
->IsFrameOfType(nsIFrame::eLineParticipant
) &&
247 frame
= frame
->GetParent();
248 rv
= frame
->QueryInterface(kBlockFrameCID
, (void**)&mBlockFrame
);
250 NS_ASSERTION(NS_SUCCEEDED(rv
) && mBlockFrame
, "Cannot find containing block.");
252 mLineContinuationPoint
= mContinuationPoint
;
256 PRBool
AreOnSameLine(nsIFrame
* aFrame1
, nsIFrame
* aFrame2
) {
257 // Assumes that aFrame1 and aFrame2 are both decsendants of mBlockFrame.
258 PRBool isValid1
, isValid2
;
259 nsBlockInFlowLineIterator
it1(mBlockFrame
, aFrame1
, &isValid1
);
260 nsBlockInFlowLineIterator
it2(mBlockFrame
, aFrame2
, &isValid2
);
261 return isValid1
&& isValid2
&& it1
.GetLine() == it2
.GetLine();
265 /* Local functions */
266 static void DrawBorderImage(nsPresContext
* aPresContext
,
267 nsIRenderingContext
& aRenderingContext
,
269 const nsRect
& aBorderArea
,
270 const nsStyleBorder
& aBorderStyle
);
272 static void DrawBorderImageSide(gfxContext
*aThebesContext
,
273 nsIDeviceContext
* aDeviceContext
,
274 imgIContainer
* aImage
,
277 gfxRect
& aSourceRect
,
281 static void PaintBackgroundColor(nsPresContext
* aPresContext
,
282 nsIRenderingContext
& aRenderingContext
,
284 const nsRect
& aBgClipArea
,
285 const nsStyleBackground
& aColor
,
286 const nsStyleBorder
& aBorder
,
287 PRBool aCanPaintNonWhite
);
289 static nscolor
MakeBevelColor(PRIntn whichSide
, PRUint8 style
,
290 nscolor aBackgroundColor
,
291 nscolor aBorderColor
);
293 static gfxRect
GetTextDecorationRectInternal(const gfxPoint
& aPt
,
294 const gfxSize
& aLineSize
,
295 const gfxFloat aAscent
,
296 const gfxFloat aOffset
,
297 const PRUint8 aDecoration
,
298 const PRUint8 aStyle
);
300 /* Returns FALSE iff all returned aTwipsRadii == 0, TRUE otherwise */
301 static PRBool
GetBorderRadiusTwips(const nsStyleCorners
& aBorderRadius
,
302 const nscoord
& aFrameWidth
,
303 nscoord aTwipsRadii
[8]);
305 static InlineBackgroundData
* gInlineBGData
= nsnull
;
307 // Initialize any static variables used by nsCSSRendering.
308 nsresult
nsCSSRendering::Init()
310 NS_ASSERTION(!gInlineBGData
, "Init called twice");
311 gInlineBGData
= new InlineBackgroundData();
313 return NS_ERROR_OUT_OF_MEMORY
;
318 // Clean up any global variables used by nsCSSRendering.
319 void nsCSSRendering::Shutdown()
321 delete gInlineBGData
;
322 gInlineBGData
= nsnull
;
329 MakeBevelColor(PRIntn whichSide
, PRUint8 style
,
330 nscolor aBackgroundColor
, nscolor aBorderColor
)
336 // Given a background color and a border color
337 // calculate the color used for the shading
338 NS_GetSpecial3DColors(colors
, aBackgroundColor
, aBorderColor
);
340 if ((style
== NS_STYLE_BORDER_STYLE_OUTSET
) ||
341 (style
== NS_STYLE_BORDER_STYLE_RIDGE
)) {
342 // Flip colors for these two border styles
344 case NS_SIDE_BOTTOM
: whichSide
= NS_SIDE_TOP
; break;
345 case NS_SIDE_RIGHT
: whichSide
= NS_SIDE_LEFT
; break;
346 case NS_SIDE_TOP
: whichSide
= NS_SIDE_BOTTOM
; break;
347 case NS_SIDE_LEFT
: whichSide
= NS_SIDE_RIGHT
; break;
353 theColor
= colors
[1];
356 theColor
= colors
[1];
359 theColor
= colors
[0];
363 theColor
= colors
[0];
369 //----------------------------------------------------------------------
370 // Thebes Border Rendering Code Start
372 // helper function to convert a nsRect to a gfxRect
374 RectToGfxRect(const nsRect
& rect
, nscoord twipsPerPixel
)
376 return gfxRect(gfxFloat(rect
.x
) / twipsPerPixel
,
377 gfxFloat(rect
.y
) / twipsPerPixel
,
378 gfxFloat(rect
.width
) / twipsPerPixel
,
379 gfxFloat(rect
.height
) / twipsPerPixel
);
383 * Compute the float-pixel radii that should be used for drawing
384 * this border/outline, given the various input bits.
386 * If a side is skipped via skipSides, its corners are forced to 0.
387 * All corner radii are then adjusted so they do not require more
388 * space than outerRect, according to the algorithm in css3-background.
391 ComputePixelRadii(const nscoord
*aTwipsRadii
,
392 const nsRect
& outerRect
,
394 nscoord twipsPerPixel
,
395 gfxCornerSizes
*oBorderRadii
)
397 nscoord twipsRadii
[8];
398 memcpy(twipsRadii
, aTwipsRadii
, sizeof twipsRadii
);
400 if (skipSides
& SIDE_BIT_TOP
) {
401 twipsRadii
[NS_CORNER_TOP_LEFT_X
] = 0;
402 twipsRadii
[NS_CORNER_TOP_LEFT_Y
] = 0;
403 twipsRadii
[NS_CORNER_TOP_RIGHT_X
] = 0;
404 twipsRadii
[NS_CORNER_TOP_RIGHT_Y
] = 0;
407 if (skipSides
& SIDE_BIT_RIGHT
) {
408 twipsRadii
[NS_CORNER_TOP_RIGHT_X
] = 0;
409 twipsRadii
[NS_CORNER_TOP_RIGHT_Y
] = 0;
410 twipsRadii
[NS_CORNER_BOTTOM_RIGHT_X
] = 0;
411 twipsRadii
[NS_CORNER_BOTTOM_RIGHT_Y
] = 0;
414 if (skipSides
& SIDE_BIT_BOTTOM
) {
415 twipsRadii
[NS_CORNER_BOTTOM_RIGHT_X
] = 0;
416 twipsRadii
[NS_CORNER_BOTTOM_RIGHT_Y
] = 0;
417 twipsRadii
[NS_CORNER_BOTTOM_LEFT_X
] = 0;
418 twipsRadii
[NS_CORNER_BOTTOM_LEFT_Y
] = 0;
421 if (skipSides
& SIDE_BIT_LEFT
) {
422 twipsRadii
[NS_CORNER_BOTTOM_LEFT_X
] = 0;
423 twipsRadii
[NS_CORNER_BOTTOM_LEFT_Y
] = 0;
424 twipsRadii
[NS_CORNER_TOP_LEFT_X
] = 0;
425 twipsRadii
[NS_CORNER_TOP_LEFT_Y
] = 0;
429 NS_FOR_CSS_HALF_CORNERS(corner
)
430 radii
[corner
] = twipsRadii
[corner
] / twipsPerPixel
;
432 // css3-background specifies this algorithm for reducing
433 // corner radii when they are too big.
434 gfxFloat maxWidth
= outerRect
.width
/ twipsPerPixel
;
435 gfxFloat maxHeight
= outerRect
.height
/ twipsPerPixel
;
437 NS_FOR_CSS_SIDES(side
) {
438 PRUint32 hc1
= NS_SIDE_TO_HALF_CORNER(side
, PR_FALSE
, PR_TRUE
);
439 PRUint32 hc2
= NS_SIDE_TO_HALF_CORNER(side
, PR_TRUE
, PR_TRUE
);
440 gfxFloat length
= NS_SIDE_IS_VERTICAL(side
) ? maxHeight
: maxWidth
;
441 gfxFloat sum
= radii
[hc1
] + radii
[hc2
];
442 // avoid floating point division in the normal case
444 f
= PR_MIN(f
, length
/sum
);
447 NS_FOR_CSS_HALF_CORNERS(corner
) {
452 (*oBorderRadii
)[C_TL
] = gfxSize(radii
[NS_CORNER_TOP_LEFT_X
],
453 radii
[NS_CORNER_TOP_LEFT_Y
]);
454 (*oBorderRadii
)[C_TR
] = gfxSize(radii
[NS_CORNER_TOP_RIGHT_X
],
455 radii
[NS_CORNER_TOP_RIGHT_Y
]);
456 (*oBorderRadii
)[C_BR
] = gfxSize(radii
[NS_CORNER_BOTTOM_RIGHT_X
],
457 radii
[NS_CORNER_BOTTOM_RIGHT_Y
]);
458 (*oBorderRadii
)[C_BL
] = gfxSize(radii
[NS_CORNER_BOTTOM_LEFT_X
],
459 radii
[NS_CORNER_BOTTOM_LEFT_Y
]);
463 nsCSSRendering::PaintBorder(nsPresContext
* aPresContext
,
464 nsIRenderingContext
& aRenderingContext
,
466 const nsRect
& aDirtyRect
,
467 const nsRect
& aBorderArea
,
468 const nsStyleBorder
& aBorderStyle
,
469 nsStyleContext
* aStyleContext
,
473 nscoord twipsRadii
[8];
474 nsCompatibility compatMode
= aPresContext
->CompatibilityMode();
476 SN("++ PaintBorder");
478 // Check to see if we have an appearance defined. If so, we let the theme
479 // renderer draw the border. DO not get the data from aForFrame, since the passed in style context
480 // may be different! Always use |aStyleContext|!
481 const nsStyleDisplay
* displayData
= aStyleContext
->GetStyleDisplay();
482 if (displayData
->mAppearance
) {
483 nsITheme
*theme
= aPresContext
->GetTheme();
484 if (theme
&& theme
->ThemeSupportsWidget(aPresContext
, aForFrame
, displayData
->mAppearance
))
485 return; // Let the theme handle it.
488 if (aBorderStyle
.IsBorderImageLoaded()) {
489 DrawBorderImage(aPresContext
, aRenderingContext
, aForFrame
,
490 aBorderArea
, aBorderStyle
);
494 // Get our style context's color struct.
495 const nsStyleColor
* ourColor
= aStyleContext
->GetStyleColor();
497 // in NavQuirks mode we want to use the parent's context as a starting point
498 // for determining the background color
499 const nsStyleBackground
* bgColor
= nsCSSRendering::FindNonTransparentBackground
500 (aStyleContext
, compatMode
== eCompatibility_NavQuirks
? PR_TRUE
: PR_FALSE
);
502 border
= aBorderStyle
.GetComputedBorder();
503 if ((0 == border
.left
) && (0 == border
.right
) &&
504 (0 == border
.top
) && (0 == border
.bottom
)) {
509 GetBorderRadiusTwips(aBorderStyle
.mBorderRadius
, aForFrame
->GetSize().width
,
512 // Turn off rendering for all of the zero sized sides
513 if (aSkipSides
& SIDE_BIT_TOP
) border
.top
= 0;
514 if (aSkipSides
& SIDE_BIT_RIGHT
) border
.right
= 0;
515 if (aSkipSides
& SIDE_BIT_BOTTOM
) border
.bottom
= 0;
516 if (aSkipSides
& SIDE_BIT_LEFT
) border
.left
= 0;
518 // get the inside and outside parts of the border
519 nsRect
outerRect(aBorderArea
);
521 SF(" outerRect: %d %d %d %d\n", outerRect
.x
, outerRect
.y
, outerRect
.width
, outerRect
.height
);
523 // we can assume that we're already clipped to aDirtyRect -- I think? (!?)
525 // Get our conversion values
526 nscoord twipsPerPixel
= aPresContext
->DevPixelsToAppUnits(1);
528 // convert outer and inner rects
529 gfxRect
oRect(RectToGfxRect(outerRect
, twipsPerPixel
));
531 // convert the border widths
532 gfxFloat borderWidths
[4] = { border
.top
/ twipsPerPixel
,
533 border
.right
/ twipsPerPixel
,
534 border
.bottom
/ twipsPerPixel
,
535 border
.left
/ twipsPerPixel
};
538 gfxCornerSizes borderRadii
;
539 ComputePixelRadii(twipsRadii
, outerRect
, aSkipSides
, twipsPerPixel
,
542 PRUint8 borderStyles
[4];
543 nscolor borderColors
[4];
544 nsBorderColors
*compositeColors
[4];
546 // pull out styles, colors, composite colors
547 NS_FOR_CSS_SIDES (i
) {
549 borderStyles
[i
] = aBorderStyle
.GetBorderStyle(i
);
550 aBorderStyle
.GetBorderColor(i
, borderColors
[i
], foreground
);
551 aBorderStyle
.GetCompositeColors(i
, &compositeColors
[i
]);
554 borderColors
[i
] = ourColor
->mColor
;
557 SF(" borderStyles: %d %d %d %d\n", borderStyles
[0], borderStyles
[1], borderStyles
[2], borderStyles
[3]);
560 gfxContext
*ctx
= aRenderingContext
.ThebesContext();
565 // this will draw a transparent red backround underneath the oRect area
567 ctx
->Rectangle(oRect
);
568 ctx
->SetColor(gfxRGBA(1.0, 0.0, 0.0, 0.5));
573 //SF ("borderRadii: %f %f %f %f\n", borderRadii[0], borderRadii[1], borderRadii[2], borderRadii[3]);
575 nsCSSBorderRenderer
br(twipsPerPixel
,
584 bgColor
->mBackgroundColor
);
593 GetOutlineInnerRect(nsIFrame
* aFrame
)
595 nsRect
* savedOutlineInnerRect
= static_cast<nsRect
*>
596 (aFrame
->GetProperty(nsGkAtoms::outlineInnerRectProperty
));
597 if (savedOutlineInnerRect
)
598 return *savedOutlineInnerRect
;
599 return aFrame
->GetOverflowRect();
603 nsCSSRendering::PaintOutline(nsPresContext
* aPresContext
,
604 nsIRenderingContext
& aRenderingContext
,
606 const nsRect
& aDirtyRect
,
607 const nsRect
& aBorderArea
,
608 const nsStyleBorder
& aBorderStyle
,
609 const nsStyleOutline
& aOutlineStyle
,
610 nsStyleContext
* aStyleContext
)
612 nscoord twipsRadii
[8];
614 // Get our style context's color struct.
615 const nsStyleColor
* ourColor
= aStyleContext
->GetStyleColor();
618 aOutlineStyle
.GetOutlineWidth(width
);
625 const nsStyleBackground
* bgColor
= nsCSSRendering::FindNonTransparentBackground
626 (aStyleContext
, PR_FALSE
);
628 // get the radius for our outline
629 GetBorderRadiusTwips(aOutlineStyle
.mOutlineRadius
, aBorderArea
.width
,
632 // When the outline property is set on :-moz-anonymous-block or
633 // :-moz-anonyomus-positioned-block pseudo-elements, it inherited that
634 // outline from the inline that was broken because it contained a
635 // block. In that case, we don't want a really wide outline if the
636 // block inside the inline is narrow, so union the actual contents of
637 // the anonymous blocks.
638 nsIFrame
*frameForArea
= aForFrame
;
640 nsIAtom
*pseudoType
= frameForArea
->GetStyleContext()->GetPseudoType();
641 if (pseudoType
!= nsCSSAnonBoxes::mozAnonymousBlock
&&
642 pseudoType
!= nsCSSAnonBoxes::mozAnonymousPositionedBlock
)
644 // If we're done, we really want it and all its later siblings.
645 frameForArea
= frameForArea
->GetFirstChild(nsnull
);
646 NS_ASSERTION(frameForArea
, "anonymous block with no children?");
647 } while (frameForArea
);
648 nsRect innerRect
; // relative to aBorderArea.TopLeft()
649 if (frameForArea
== aForFrame
) {
650 innerRect
= GetOutlineInnerRect(aForFrame
);
652 for (; frameForArea
; frameForArea
= frameForArea
->GetNextSibling()) {
653 // The outline has already been included in aForFrame's overflow
654 // area, but not in those of its descendants, so we have to
655 // include it. Otherwise we'll end up drawing the outline inside
657 nsRect
r(GetOutlineInnerRect(frameForArea
) +
658 frameForArea
->GetOffsetTo(aForFrame
));
659 innerRect
.UnionRect(innerRect
, r
);
663 innerRect
+= aBorderArea
.TopLeft();
664 nscoord offset
= aOutlineStyle
.mOutlineOffset
;
665 innerRect
.Inflate(offset
, offset
);
666 // If the dirty rect is completely inside the border area (e.g., only the
667 // content is being painted), then we can skip out now
668 // XXX this isn't exactly true for rounded borders, where the inside curves may
669 // encroach into the content area. A safer calculation would be to
670 // shorten insideRect by the radius one each side before performing this test.
671 if (innerRect
.Contains(aDirtyRect
))
674 nsRect outerRect
= innerRect
;
675 outerRect
.Inflate(width
, width
);
677 // Get our conversion values
678 nscoord twipsPerPixel
= aPresContext
->DevPixelsToAppUnits(1);
680 // get the outer rectangles
681 gfxRect
oRect(RectToGfxRect(outerRect
, twipsPerPixel
));
684 nsMargin
outlineMargin(width
, width
, width
, width
);
685 gfxCornerSizes outlineRadii
;
686 ComputePixelRadii(twipsRadii
, outerRect
, 0, twipsPerPixel
,
689 PRUint8 outlineStyle
= aOutlineStyle
.GetOutlineStyle();
690 PRUint8 outlineStyles
[4] = { outlineStyle
,
695 nscolor outlineColor
;
696 // PR_FALSE means use the initial color; PR_TRUE means a color was
698 if (!aOutlineStyle
.GetOutlineColor(outlineColor
))
699 outlineColor
= ourColor
->mColor
;
700 nscolor outlineColors
[4] = { outlineColor
,
705 // convert the border widths
706 gfxFloat outlineWidths
[4] = { width
/ twipsPerPixel
,
707 width
/ twipsPerPixel
,
708 width
/ twipsPerPixel
,
709 width
/ twipsPerPixel
};
712 gfxContext
*ctx
= aRenderingContext
.ThebesContext();
716 nsCSSBorderRenderer
br(twipsPerPixel
,
724 bgColor
->mBackgroundColor
);
733 nsCSSRendering::PaintFocus(nsPresContext
* aPresContext
,
734 nsIRenderingContext
& aRenderingContext
,
735 const nsRect
& aFocusRect
,
738 nscoord oneCSSPixel
= nsPresContext::CSSPixelsToAppUnits(1);
739 nscoord oneDevPixel
= aPresContext
->DevPixelsToAppUnits(1);
741 gfxRect
focusRect(RectToGfxRect(aFocusRect
, oneDevPixel
));
743 gfxCornerSizes focusRadii
;
745 nscoord twipsRadii
[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
746 ComputePixelRadii(twipsRadii
, aFocusRect
, 0, oneDevPixel
, &focusRadii
);
748 gfxFloat focusWidths
[4] = { oneCSSPixel
/ oneDevPixel
,
749 oneCSSPixel
/ oneDevPixel
,
750 oneCSSPixel
/ oneDevPixel
,
751 oneCSSPixel
/ oneDevPixel
};
753 PRUint8 focusStyles
[4] = { NS_STYLE_BORDER_STYLE_DOTTED
,
754 NS_STYLE_BORDER_STYLE_DOTTED
,
755 NS_STYLE_BORDER_STYLE_DOTTED
,
756 NS_STYLE_BORDER_STYLE_DOTTED
};
757 nscolor focusColors
[4] = { aColor
, aColor
, aColor
, aColor
};
759 gfxContext
*ctx
= aRenderingContext
.ThebesContext();
763 // Because this renders a dotted border, the background color
764 // should not be used. Therefore, we provide a value that will
765 // be blatantly wrong if it ever does get used. (If this becomes
766 // something that CSS can style, this function will then have access
767 // to a style context and can use the same logic that PaintBorder
768 // and PaintOutline do.)
769 nsCSSBorderRenderer
br(oneDevPixel
,
785 // Thebes Border Rendering Code End
786 //----------------------------------------------------------------------
789 //----------------------------------------------------------------------
792 * Computes the placement of a background image.
794 * @param aOriginBounds is the box to which the tiling position should be
796 * This should correspond to 'background-origin' for the frame,
797 * except when painting on the canvas, in which case the origin bounds
798 * should be the bounds of the root element's frame.
799 * @param aTopLeft the top-left corner where an image tile should be drawn
800 * @param aAnchorPoint a point which should be pixel-aligned by
801 * nsLayoutUtils::DrawImage. This is the same as aTopLeft, unless CSS
802 * specifies a percentage (including 'right' or 'bottom'), in which case
803 * it's that percentage within of aOriginBounds. So 'right' would set
804 * aAnchorPoint.x to aOriginBounds.XMost().
806 * Points are returned relative to aOriginBounds.
809 ComputeBackgroundAnchorPoint(const nsStyleBackground
& aColor
,
810 const nsSize
& aOriginBounds
,
811 const nsSize
& aImageSize
,
813 nsPoint
* aAnchorPoint
)
815 if (NS_STYLE_BG_X_POSITION_LENGTH
& aColor
.mBackgroundFlags
) {
816 aTopLeft
->x
= aAnchorPoint
->x
= aColor
.mBackgroundXPosition
.mCoord
;
818 else if (NS_STYLE_BG_X_POSITION_PERCENT
& aColor
.mBackgroundFlags
) {
819 double percent
= aColor
.mBackgroundXPosition
.mFloat
;
820 aAnchorPoint
->x
= NSToCoordRound(percent
*aOriginBounds
.width
);
821 aTopLeft
->x
= NSToCoordRound(percent
*(aOriginBounds
.width
- aImageSize
.width
));
824 aTopLeft
->x
= aAnchorPoint
->x
= 0;
827 if (NS_STYLE_BG_Y_POSITION_LENGTH
& aColor
.mBackgroundFlags
) {
828 aTopLeft
->y
= aAnchorPoint
->y
= aColor
.mBackgroundYPosition
.mCoord
;
830 else if (NS_STYLE_BG_Y_POSITION_PERCENT
& aColor
.mBackgroundFlags
) {
831 double percent
= aColor
.mBackgroundYPosition
.mFloat
;
832 aAnchorPoint
->y
= NSToCoordRound(percent
*aOriginBounds
.height
);
833 aTopLeft
->y
= NSToCoordRound(percent
*(aOriginBounds
.height
- aImageSize
.height
));
836 aTopLeft
->y
= aAnchorPoint
->y
= 0;
840 const nsStyleBackground
*
841 nsCSSRendering::FindNonTransparentBackground(nsStyleContext
* aContext
,
842 PRBool aStartAtParent
/*= PR_FALSE*/)
844 NS_ASSERTION(aContext
, "Cannot find NonTransparentBackground in a null context" );
846 const nsStyleBackground
* result
= nsnull
;
847 nsStyleContext
* context
= nsnull
;
848 if (aStartAtParent
) {
849 context
= aContext
->GetParent();
856 result
= context
->GetStyleBackground();
857 if (NS_GET_A(result
->mBackgroundColor
) > 0)
860 context
= context
->GetParent();
867 * |FindBackground| finds the correct style data to use to paint the
868 * background. It is responsible for handling the following two
869 * statements in section 14.2 of CSS2:
871 * The background of the box generated by the root element covers the
874 * For HTML documents, however, we recommend that authors specify the
875 * background for the BODY element rather than the HTML element. User
876 * agents should observe the following precedence rules to fill in the
877 * background: if the value of the 'background' property for the HTML
878 * element is different from 'transparent' then use it, else use the
879 * value of the 'background' property for the BODY element. If the
880 * resulting value is 'transparent', the rendering is undefined.
882 * Thus, in our implementation, it is responsible for ensuring that:
883 * + we paint the correct background on the |nsCanvasFrame|,
884 * |nsRootBoxFrame|, or |nsPageFrame|,
885 * + we don't paint the background on the root element, and
886 * + we don't paint the background on the BODY element in *some* cases,
887 * and for SGML-based HTML documents only.
889 * |FindBackground| returns true if a background should be painted, and
890 * the resulting style context to use for the background information
891 * will be filled in to |aBackground|. It fills in a boolean indicating
892 * whether the frame is the canvas frame to allow PaintBackground to
893 * ensure that it always paints something non-transparent for the
897 // Returns true if aFrame is a canvas frame.
898 // We need to treat the viewport as canvas because, even though
899 // it does not actually paint a background, we need to get the right
900 // background style so we correctly detect transparent documents.
902 IsCanvasFrame(nsIFrame
*aFrame
)
904 nsIAtom
* frameType
= aFrame
->GetType();
905 return frameType
== nsGkAtoms::canvasFrame
||
906 frameType
== nsGkAtoms::rootFrame
||
907 frameType
== nsGkAtoms::pageFrame
||
908 frameType
== nsGkAtoms::pageContentFrame
||
909 frameType
== nsGkAtoms::viewportFrame
;
913 FindCanvasBackground(nsIFrame
* aForFrame
, nsIFrame
* aRootElementFrame
,
914 const nsStyleBackground
** aBackground
)
916 if (aRootElementFrame
) {
917 const nsStyleBackground
* result
= aRootElementFrame
->GetStyleBackground();
919 // Check if we need to do propagation from BODY rather than HTML.
920 if (result
->IsTransparent()) {
921 nsIContent
* content
= aRootElementFrame
->GetContent();
922 // The root element content can't be null. We wouldn't know what
923 // frame to create for aRootElementFrame.
924 // Use |GetOwnerDoc| so it works during destruction.
925 nsIDocument
* document
= content
->GetOwnerDoc();
926 nsCOMPtr
<nsIHTMLDocument
> htmlDoc
= do_QueryInterface(document
);
928 nsIContent
* bodyContent
= htmlDoc
->GetBodyContentExternal();
929 // We need to null check the body node (bug 118829) since
930 // there are cases, thanks to the fix for bug 5569, where we
931 // will reflow a document with no body. In particular, if a
932 // SCRIPT element in the head blocks the parser and then has a
933 // SCRIPT that does "document.location.href = 'foo'", then
934 // nsParser::Terminate will call |DidBuildModel| methods
935 // through to the content sink, which will call |StartLayout|
936 // and thus |InitialReflow| on the pres shell. See bug 119351
937 // for the ugly details.
939 nsIFrame
*bodyFrame
= aForFrame
->PresContext()->GetPresShell()->
940 GetPrimaryFrameFor(bodyContent
);
942 result
= bodyFrame
->GetStyleBackground();
947 *aBackground
= result
;
949 // This should always give transparent, so we'll fill it in with the
950 // default color if needed. This seems to happen a bit while a page is
952 *aBackground
= aForFrame
->GetStyleBackground();
959 FindElementBackground(nsIFrame
* aForFrame
, nsIFrame
* aRootElementFrame
,
960 const nsStyleBackground
** aBackground
)
962 if (aForFrame
== aRootElementFrame
) {
963 // We must have propagated our background to the viewport or canvas. Abort.
967 *aBackground
= aForFrame
->GetStyleBackground();
969 // Return true unless the frame is for a BODY element whose background
970 // was propagated to the viewport.
972 nsIContent
* content
= aForFrame
->GetContent();
973 if (!content
|| content
->Tag() != nsGkAtoms::body
)
974 return PR_TRUE
; // not frame for a "body" element
975 // It could be a non-HTML "body" element but that's OK, we'd fail the
976 // bodyContent check below
978 if (aForFrame
->GetStyleContext()->GetPseudoType())
979 return PR_TRUE
; // A pseudo-element frame.
981 // We should only look at the <html> background if we're in an HTML document
982 nsIDocument
* document
= content
->GetOwnerDoc();
983 nsCOMPtr
<nsIHTMLDocument
> htmlDoc
= do_QueryInterface(document
);
987 nsIContent
* bodyContent
= htmlDoc
->GetBodyContentExternal();
988 if (bodyContent
!= content
)
989 return PR_TRUE
; // this wasn't the background that was propagated
991 // This can be called even when there's no root element yet, during frame
992 // construction, via nsLayoutUtils::FrameHasTransparency and
993 // nsContainerFrame::SyncFrameViewProperties.
994 if (!aRootElementFrame
)
997 const nsStyleBackground
* htmlBG
= aRootElementFrame
->GetStyleBackground();
998 return !htmlBG
->IsTransparent();
1002 nsCSSRendering::FindBackground(nsPresContext
* aPresContext
,
1003 nsIFrame
* aForFrame
,
1004 const nsStyleBackground
** aBackground
,
1007 nsIFrame
* rootElementFrame
=
1008 aPresContext
->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
1009 PRBool isCanvasFrame
= IsCanvasFrame(aForFrame
);
1010 *aIsCanvas
= isCanvasFrame
;
1011 return isCanvasFrame
1012 ? FindCanvasBackground(aForFrame
, rootElementFrame
, aBackground
)
1013 : FindElementBackground(aForFrame
, rootElementFrame
, aBackground
);
1017 nsCSSRendering::DidPaint()
1019 gInlineBGData
->Reset();
1023 GetBorderRadiusTwips(const nsStyleCorners
& aBorderRadius
,
1024 const nscoord
& aFrameWidth
, nscoord aTwipsRadii
[8])
1026 PRBool result
= PR_FALSE
;
1028 // Convert percentage values
1029 NS_FOR_CSS_HALF_CORNERS(i
) {
1030 const nsStyleCoord c
= aBorderRadius
.Get(i
);
1032 switch (c
.GetUnit()) {
1033 case eStyleUnit_Percent
:
1034 aTwipsRadii
[i
] = (nscoord
)(c
.GetPercentValue() * aFrameWidth
);
1037 case eStyleUnit_Coord
:
1038 aTwipsRadii
[i
] = c
.GetCoordValue();
1042 NS_NOTREACHED("GetBorderRadiusTwips: bad unit");
1054 nsCSSRendering::PaintBoxShadow(nsPresContext
* aPresContext
,
1055 nsIRenderingContext
& aRenderingContext
,
1056 nsIFrame
* aForFrame
,
1057 const nsPoint
& aForFramePt
,
1058 const nsRect
& aDirtyRect
)
1060 nsMargin borderValues
;
1064 const nsStyleBorder
* styleBorder
= aForFrame
->GetStyleBorder();
1065 borderValues
= styleBorder
->GetActualBorder();
1066 sidesToSkip
= aForFrame
->GetSkipSides();
1067 frameRect
= nsRect(aForFramePt
, aForFrame
->GetSize());
1069 // Get any border radius, since box-shadow must also have rounded corners if the frame does
1070 nscoord twipsRadii
[8];
1071 PRBool hasBorderRadius
= GetBorderRadiusTwips(styleBorder
->mBorderRadius
,
1072 frameRect
.width
, twipsRadii
);
1073 nscoord twipsPerPixel
= aPresContext
->DevPixelsToAppUnits(1);
1075 gfxCornerSizes borderRadii
;
1076 ComputePixelRadii(twipsRadii
, frameRect
, sidesToSkip
,
1077 twipsPerPixel
, &borderRadii
);
1079 gfxRect frameGfxRect
= RectToGfxRect(frameRect
, twipsPerPixel
);
1080 gfxRect dirtyGfxRect
= RectToGfxRect(aDirtyRect
, twipsPerPixel
);
1082 for (PRUint32 i
= styleBorder
->mBoxShadow
->Length(); i
> 0; --i
) {
1083 nsCSSShadowItem
* shadowItem
= styleBorder
->mBoxShadow
->ShadowAt(i
- 1);
1084 gfxRect
shadowRect(frameRect
.x
, frameRect
.y
, frameRect
.width
, frameRect
.height
);
1085 shadowRect
.MoveBy(gfxPoint(shadowItem
->mXOffset
, shadowItem
->mYOffset
));
1086 shadowRect
.Outset(shadowItem
->mSpread
);
1088 gfxRect shadowRectPlusBlur
= shadowRect
;
1089 shadowRect
.ScaleInverse(twipsPerPixel
);
1090 shadowRect
.RoundOut();
1092 // shadowRect won't include the blur, so make an extra rect here that includes the blur
1093 // for use in the even-odd rule below.
1094 nscoord blurRadius
= shadowItem
->mRadius
;
1095 shadowRectPlusBlur
.Outset(blurRadius
);
1096 shadowRectPlusBlur
.ScaleInverse(twipsPerPixel
);
1097 shadowRectPlusBlur
.RoundOut();
1099 gfxContext
* renderContext
= aRenderingContext
.ThebesContext();
1100 nsRefPtr
<gfxContext
> shadowContext
;
1101 nsContextBoxBlur blurringArea
;
1103 // shadowRect is already in device pixels, pass 1 as the appunits/pixel value
1104 blurRadius
/= twipsPerPixel
;
1105 shadowContext
= blurringArea
.Init(shadowRect
, blurRadius
, 1, renderContext
, dirtyGfxRect
);
1109 // Set the shadow color; if not specified, use the foreground color
1110 nscolor shadowColor
;
1111 if (shadowItem
->mHasColor
)
1112 shadowColor
= shadowItem
->mColor
;
1114 shadowColor
= aForFrame
->GetStyleColor()->mColor
;
1116 renderContext
->Save();
1117 renderContext
->SetColor(gfxRGBA(shadowColor
));
1119 // Clip out the area of the actual frame so the shadow is not shown within
1121 renderContext
->NewPath();
1122 renderContext
->Rectangle(shadowRectPlusBlur
);
1123 if (hasBorderRadius
)
1124 renderContext
->RoundedRectangle(frameGfxRect
, borderRadii
);
1126 renderContext
->Rectangle(frameGfxRect
);
1127 renderContext
->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD
);
1128 renderContext
->Clip();
1130 // Draw the shape of the frame so it can be blurred. Recall how nsContextBoxBlur
1131 // doesn't make any temporary surfaces if blur is 0 and it just returns the original
1132 // surface? If we have no blur, we're painting this fill on the actual content surface
1133 // (renderContext == shadowContext) which is why we set up the color and clip
1134 // before doing this.
1135 shadowContext
->NewPath();
1136 if (hasBorderRadius
)
1137 shadowContext
->RoundedRectangle(shadowRect
, borderRadii
);
1139 shadowContext
->Rectangle(shadowRect
);
1140 shadowContext
->Fill();
1142 blurringArea
.DoPaint();
1143 renderContext
->Restore();
1148 nsCSSRendering::PaintBackground(nsPresContext
* aPresContext
,
1149 nsIRenderingContext
& aRenderingContext
,
1150 nsIFrame
* aForFrame
,
1151 const nsRect
& aDirtyRect
,
1152 const nsRect
& aBorderArea
,
1153 PRBool aUsePrintSettings
,
1154 nsRect
* aBGClipRect
)
1156 NS_PRECONDITION(aForFrame
,
1157 "Frame is expected to be provided to PaintBackground");
1160 const nsStyleBackground
*color
;
1161 const nsStyleBorder
* border
= aForFrame
->GetStyleBorder();
1163 if (!FindBackground(aPresContext
, aForFrame
, &color
, &isCanvas
)) {
1164 // we don't want to bail out of moz-appearance is set on a root
1165 // node. If it has a parent content node, bail because it's not
1166 // a root, other wise keep going in order to let the theme stuff
1167 // draw the background. The canvas really should be drawing the
1168 // bg, but there's no way to hook that up via css.
1169 if (!aForFrame
->GetStyleDisplay()->mAppearance
) {
1173 nsIContent
* content
= aForFrame
->GetContent();
1174 if (!content
|| content
->GetParent()) {
1178 color
= aForFrame
->GetStyleBackground();
1181 PaintBackgroundWithSC(aPresContext
, aRenderingContext
, aForFrame
,
1182 aDirtyRect
, aBorderArea
, *color
, *border
,
1183 aUsePrintSettings
, aBGClipRect
);
1187 nsStyleBackground
canvasColor(*color
);
1189 nsIViewManager
* vm
= aPresContext
->GetViewManager();
1191 if (NS_GET_A(canvasColor
.mBackgroundColor
) < 255) {
1192 // If the window is intended to be opaque, ensure that we always
1193 // paint an opaque color for its root element, in case there's no
1194 // background at all or a partly transparent image.
1196 vm
->GetRootView(rView
);
1197 if (!rView
->GetParent() &&
1198 (!rView
->HasWidget() ||
1199 rView
->GetWidget()->GetTransparencyMode() == eTransparencyOpaque
)) {
1200 nscolor backColor
= aPresContext
->DefaultBackgroundColor();
1201 NS_ASSERTION(NS_GET_A(backColor
) == 255,
1202 "default background color is not opaque");
1204 canvasColor
.mBackgroundColor
=
1205 NS_ComposeColors(backColor
, canvasColor
.mBackgroundColor
);
1209 vm
->SetDefaultBackgroundColor(canvasColor
.mBackgroundColor
);
1211 PaintBackgroundWithSC(aPresContext
, aRenderingContext
, aForFrame
,
1212 aDirtyRect
, aBorderArea
, canvasColor
,
1213 *border
, aUsePrintSettings
, aBGClipRect
);
1217 IsSolidBorderEdge(const nsStyleBorder
& aBorder
, PRUint32 aSide
)
1219 if (aBorder
.GetActualBorder().side(aSide
) == 0)
1221 if (aBorder
.GetBorderStyle(aSide
) != NS_STYLE_BORDER_STYLE_SOLID
)
1224 // If we're using a border image, assume it's not fully opaque,
1225 // because we may not even have the image loaded at this point, and
1226 // even if we did, checking whether the relevant tile is fully
1227 // opaque would be too much work.
1228 if (aBorder
.GetBorderImage())
1232 PRBool isForeground
;
1233 aBorder
.GetBorderColor(aSide
, color
, isForeground
);
1235 // We don't know the foreground color here, so if it's being used
1236 // we must assume it might be transparent.
1240 return NS_GET_A(color
) == 255;
1244 * Returns true if all border edges are either missing or opaque.
1247 IsSolidBorder(const nsStyleBorder
& aBorder
)
1249 if (aBorder
.mBorderColors
||
1250 nsLayoutUtils::HasNonZeroCorner(aBorder
.mBorderRadius
))
1252 for (PRUint32 i
= 0; i
< 4; ++i
) {
1253 if (!IsSolidBorderEdge(aBorder
, i
))
1260 nsCSSRendering::PaintBackgroundWithSC(nsPresContext
* aPresContext
,
1261 nsIRenderingContext
& aRenderingContext
,
1262 nsIFrame
* aForFrame
,
1263 const nsRect
& aDirtyRect
,
1264 const nsRect
& aBorderArea
,
1265 const nsStyleBackground
& aColor
,
1266 const nsStyleBorder
& aBorder
,
1267 PRBool aUsePrintSettings
,
1268 nsRect
* aBGClipRect
)
1270 NS_PRECONDITION(aForFrame
,
1271 "Frame is expected to be provided to PaintBackground");
1273 PRBool canDrawBackgroundImage
= PR_TRUE
;
1274 PRBool canDrawBackgroundColor
= PR_TRUE
;
1276 if (aUsePrintSettings
) {
1277 canDrawBackgroundImage
= aPresContext
->GetBackgroundImageDraw();
1278 canDrawBackgroundColor
= aPresContext
->GetBackgroundColorDraw();
1281 // Check to see if we have an appearance defined. If so, we let the theme
1282 // renderer draw the background and bail out.
1283 const nsStyleDisplay
* displayData
= aForFrame
->GetStyleDisplay();
1284 if (displayData
->mAppearance
) {
1285 nsITheme
*theme
= aPresContext
->GetTheme();
1286 if (theme
&& theme
->ThemeSupportsWidget(aPresContext
, aForFrame
, displayData
->mAppearance
)) {
1288 dirty
.IntersectRect(aDirtyRect
, aBorderArea
);
1289 theme
->DrawWidgetBackground(&aRenderingContext
, aForFrame
,
1290 displayData
->mAppearance
, aBorderArea
, dirty
);
1295 // Same coordinate space as aBorderArea
1298 bgClipArea
= *aBGClipRect
;
1301 // The background is rendered over the 'background-clip' area.
1302 bgClipArea
= aBorderArea
;
1303 // If the border is solid, then clip the background to the padding-box
1304 // so that we don't draw unnecessary tiles.
1305 if (aColor
.mBackgroundClip
!= NS_STYLE_BG_CLIP_BORDER
||
1306 IsSolidBorder(aBorder
)) {
1307 nsMargin border
= aForFrame
->GetUsedBorder();
1308 aForFrame
->ApplySkipSides(border
);
1309 bgClipArea
.Deflate(border
);
1313 gfxContext
*ctx
= aRenderingContext
.ThebesContext();
1315 // The actual dirty rect is the intersection of the 'background-clip'
1316 // area and the dirty rect we were given
1318 if (!dirtyRect
.IntersectRect(bgClipArea
, aDirtyRect
)) {
1323 // if there is no background image or background images are turned off, try a color.
1324 if (!aColor
.mBackgroundImage
|| !canDrawBackgroundImage
) {
1325 PaintBackgroundColor(aPresContext
, aRenderingContext
, aForFrame
, bgClipArea
,
1326 aColor
, aBorder
, canDrawBackgroundColor
);
1330 // We have a background image
1333 imgIRequest
*req
= aPresContext
->LoadImage(aColor
.mBackgroundImage
,
1336 PRUint32 status
= imgIRequest::STATUS_ERROR
;
1338 req
->GetImageStatus(&status
);
1340 if (!req
|| !(status
& imgIRequest::STATUS_FRAME_COMPLETE
) || !(status
& imgIRequest::STATUS_SIZE_AVAILABLE
)) {
1341 PaintBackgroundColor(aPresContext
, aRenderingContext
, aForFrame
, bgClipArea
,
1342 aColor
, aBorder
, canDrawBackgroundColor
);
1346 nsCOMPtr
<imgIContainer
> image
;
1347 req
->GetImage(getter_AddRefs(image
));
1350 image
->GetWidth(&imageSize
.width
);
1351 image
->GetHeight(&imageSize
.height
);
1353 imageSize
.width
= nsPresContext::CSSPixelsToAppUnits(imageSize
.width
);
1354 imageSize
.height
= nsPresContext::CSSPixelsToAppUnits(imageSize
.height
);
1358 // relative to aBorderArea
1359 nsRect bgOriginRect
;
1361 nsIAtom
* frameType
= aForFrame
->GetType();
1362 nsIFrame
* geometryFrame
= aForFrame
;
1363 if (frameType
== nsGkAtoms::inlineFrame
||
1364 frameType
== nsGkAtoms::positionedInlineFrame
) {
1365 switch (aColor
.mBackgroundInlinePolicy
) {
1366 case NS_STYLE_BG_INLINE_POLICY_EACH_BOX
:
1367 bgOriginRect
= nsRect(nsPoint(0,0), aBorderArea
.Size());
1369 case NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX
:
1370 bgOriginRect
= gInlineBGData
->GetBoundingRect(aForFrame
);
1373 NS_ERROR("Unknown background-inline-policy value! "
1374 "Please, teach me what to do.");
1375 case NS_STYLE_BG_INLINE_POLICY_CONTINUOUS
:
1376 bgOriginRect
= gInlineBGData
->GetContinuousRect(aForFrame
);
1379 } else if (frameType
== nsGkAtoms::canvasFrame
) {
1380 geometryFrame
= aForFrame
->GetFirstChild(nsnull
);
1381 NS_ASSERTION(geometryFrame
, "A canvas with a background "
1382 "image had no child frame, which is impossible according to CSS. "
1383 "Make sure there isn't a background image specified on the "
1384 "|:viewport| pseudo-element in |html.css|.");
1385 bgOriginRect
= geometryFrame
->GetRect();
1387 bgOriginRect
= nsRect(nsPoint(0,0), aBorderArea
.Size());
1390 // Background images are tiled over the 'background-clip' area
1391 // but the origin of the tiling is based on the 'background-origin' area
1392 if (aColor
.mBackgroundOrigin
!= NS_STYLE_BG_ORIGIN_BORDER
) {
1393 nsMargin border
= geometryFrame
->GetUsedBorder();
1394 geometryFrame
->ApplySkipSides(border
);
1395 bgOriginRect
.Deflate(border
);
1396 if (aColor
.mBackgroundOrigin
!= NS_STYLE_BG_ORIGIN_PADDING
) {
1397 nsMargin padding
= geometryFrame
->GetUsedPadding();
1398 geometryFrame
->ApplySkipSides(padding
);
1399 bgOriginRect
.Deflate(padding
);
1400 NS_ASSERTION(aColor
.mBackgroundOrigin
== NS_STYLE_BG_ORIGIN_CONTENT
,
1401 "unknown background-origin value");
1405 PRBool needBackgroundColor
= NS_GET_A(aColor
.mBackgroundColor
) > 0;
1406 PRIntn repeat
= aColor
.mBackgroundRepeat
;
1409 case NS_STYLE_BG_REPEAT_X
:
1411 case NS_STYLE_BG_REPEAT_Y
:
1413 case NS_STYLE_BG_REPEAT_XY
:
1414 if (needBackgroundColor
) {
1415 // If the image is completely opaque, we do not need to paint the
1417 nsCOMPtr
<gfxIImageFrame
> gfxImgFrame
;
1418 image
->GetCurrentFrame(getter_AddRefs(gfxImgFrame
));
1420 gfxImgFrame
->GetNeedsBackground(&needBackgroundColor
);
1422 /* check for tiling of a image where frame smaller than container */
1424 image
->GetWidth(&iSize
.width
);
1425 image
->GetHeight(&iSize
.height
);
1427 gfxImgFrame
->GetRect(iframeRect
);
1428 if (iSize
.width
!= iframeRect
.width
||
1429 iSize
.height
!= iframeRect
.height
) {
1430 needBackgroundColor
= PR_TRUE
;
1435 case NS_STYLE_BG_REPEAT_OFF
:
1437 NS_ASSERTION(repeat
== NS_STYLE_BG_REPEAT_OFF
, "unknown background-repeat value");
1441 // The background color is rendered over the 'background-clip' area
1442 if (needBackgroundColor
) {
1443 PaintBackgroundColor(aPresContext
, aRenderingContext
, aForFrame
, bgClipArea
,
1444 aColor
, aBorder
, canDrawBackgroundColor
);
1447 // Compute the anchor point.
1449 // relative to aBorderArea.TopLeft() (which is where the top-left
1450 // of aForFrame's border-box will be rendered)
1451 nsPoint imageTopLeft
, anchor
;
1452 if (NS_STYLE_BG_ATTACHMENT_FIXED
== aColor
.mBackgroundAttachment
) {
1453 // If it's a fixed background attachment, then the image is placed
1454 // relative to the viewport, which is the area of the root frame
1455 // in a screen context or the page content frame in a print context.
1457 // Remember that we've drawn position-varying content in this prescontext
1458 aPresContext
->SetRenderedPositionVaryingContent();
1460 nsIFrame
* topFrame
=
1461 aPresContext
->PresShell()->FrameManager()->GetRootFrame();
1462 NS_ASSERTION(topFrame
, "no root frame");
1463 nsIFrame
* pageContentFrame
= nsnull
;
1464 if (aPresContext
->IsPaginated()) {
1466 nsLayoutUtils::GetClosestFrameOfType(aForFrame
, nsGkAtoms::pageContentFrame
);
1467 if (pageContentFrame
) {
1468 topFrame
= pageContentFrame
;
1470 // else this is an embedded shell and its root frame is what we want
1473 nsRect
viewportArea(nsPoint(0, 0), topFrame
->GetSize());
1475 if (!pageContentFrame
) {
1476 // Subtract the size of scrollbars.
1477 nsIScrollableFrame
* scrollableFrame
=
1478 aPresContext
->PresShell()->GetRootScrollFrameAsScrollable();
1479 if (scrollableFrame
) {
1480 nsMargin scrollbars
= scrollableFrame
->GetActualScrollbarSizes();
1481 viewportArea
.Deflate(scrollbars
);
1485 // Get the anchor point, relative to the viewport.
1486 ComputeBackgroundAnchorPoint(aColor
, viewportArea
.Size(), imageSize
,
1487 &imageTopLeft
, &anchor
);
1489 // Convert the anchor point from viewport coordinates to aForFrame
1491 nsPoint offset
= viewportArea
.TopLeft() - aForFrame
->GetOffsetTo(topFrame
);
1492 imageTopLeft
+= offset
;
1495 ComputeBackgroundAnchorPoint(aColor
, bgOriginRect
.Size(), imageSize
,
1496 &imageTopLeft
, &anchor
);
1497 imageTopLeft
+= bgOriginRect
.TopLeft();
1498 anchor
+= bgOriginRect
.TopLeft();
1503 nscoord borderRadii
[8];
1504 PRBool haveRadius
= GetBorderRadiusTwips(aBorder
.mBorderRadius
,
1505 aForFrame
->GetSize().width
,
1508 nscoord appUnitsPerPixel
= aPresContext
->DevPixelsToAppUnits(1);
1509 gfxCornerSizes radii
;
1510 ComputePixelRadii(borderRadii
, bgClipArea
,
1511 aForFrame
? aForFrame
->GetSkipSides() : 0,
1512 appUnitsPerPixel
, &radii
);
1514 gfxRect
oRect(RectToGfxRect(bgClipArea
, appUnitsPerPixel
));
1519 ctx
->RoundedRectangle(oRect
, radii
);
1523 nsRect
destArea(imageTopLeft
+ aBorderArea
.TopLeft(), imageSize
);
1524 nsRect fillArea
= destArea
;
1525 if (repeat
& NS_STYLE_BG_REPEAT_X
) {
1526 fillArea
.x
= bgClipArea
.x
;
1527 fillArea
.width
= bgClipArea
.width
;
1529 if (repeat
& NS_STYLE_BG_REPEAT_Y
) {
1530 fillArea
.y
= bgClipArea
.y
;
1531 fillArea
.height
= bgClipArea
.height
;
1533 fillArea
.IntersectRect(fillArea
, bgClipArea
);
1535 nsLayoutUtils::DrawImage(&aRenderingContext
, image
,
1536 destArea
, fillArea
, anchor
+ aBorderArea
.TopLeft(), dirtyRect
);
1542 DrawBorderImage(nsPresContext
* aPresContext
,
1543 nsIRenderingContext
& aRenderingContext
,
1544 nsIFrame
* aForFrame
, const nsRect
& aBorderArea
,
1545 const nsStyleBorder
& aBorderStyle
)
1548 nsStyleCoord borderImageSplit
[4];
1549 PRInt32 borderImageSplitInt
[4];
1551 gfxFloat borderTop
, borderRight
, borderBottom
, borderLeft
;
1552 gfxFloat borderImageSplitGfx
[4];
1554 border
= aBorderStyle
.GetActualBorder();
1555 if ((0 == border
.left
) && (0 == border
.right
) &&
1556 (0 == border
.top
) && (0 == border
.bottom
)) {
1557 // Empty border area
1561 borderImageSplit
[NS_SIDE_TOP
] = aBorderStyle
.mBorderImageSplit
.GetTop();
1562 borderImageSplit
[NS_SIDE_RIGHT
] = aBorderStyle
.mBorderImageSplit
.GetRight();
1563 borderImageSplit
[NS_SIDE_BOTTOM
] = aBorderStyle
.mBorderImageSplit
.GetBottom();
1564 borderImageSplit
[NS_SIDE_LEFT
] = aBorderStyle
.mBorderImageSplit
.GetLeft();
1566 imgIRequest
*req
= aPresContext
->LoadBorderImage(aBorderStyle
.GetBorderImage(), aForFrame
);
1568 nsCOMPtr
<imgIContainer
> image
;
1569 req
->GetImage(getter_AddRefs(image
));
1572 image
->GetWidth(&imageSize
.width
);
1573 image
->GetHeight(&imageSize
.height
);
1574 imageSize
.width
= nsPresContext::CSSPixelsToAppUnits(imageSize
.width
);
1575 imageSize
.height
= nsPresContext::CSSPixelsToAppUnits(imageSize
.height
);
1577 // convert percentage values
1578 NS_FOR_CSS_SIDES(side
) {
1579 borderImageSplitInt
[side
] = 0;
1580 switch (borderImageSplit
[side
].GetUnit()) {
1581 case eStyleUnit_Percent
:
1582 percent
= borderImageSplit
[side
].GetPercentValue();
1583 if (side
== NS_SIDE_TOP
|| side
== NS_SIDE_BOTTOM
)
1584 borderImageSplitInt
[side
] = (nscoord
)(percent
* imageSize
.height
);
1586 borderImageSplitInt
[side
] = (nscoord
)(percent
* imageSize
.width
);
1588 case eStyleUnit_Integer
:
1589 borderImageSplitInt
[side
] = nsPresContext::CSSPixelsToAppUnits(borderImageSplit
[side
].
1592 case eStyleUnit_Factor
:
1593 borderImageSplitInt
[side
] = nsPresContext::CSSPixelsToAppUnits(borderImageSplit
[side
].GetFactorValue());
1600 gfxContext
*thebesCtx
= aRenderingContext
.ThebesContext();
1601 nsCOMPtr
<nsIDeviceContext
> dc
;
1602 aRenderingContext
.GetDeviceContext(*getter_AddRefs(dc
));
1604 NS_FOR_CSS_SIDES(side
) {
1605 borderImageSplitGfx
[side
] = nsPresContext::AppUnitsToFloatCSSPixels(borderImageSplitInt
[side
]);
1608 borderTop
= dc
->AppUnitsToGfxUnits(border
.top
);
1609 borderRight
= dc
->AppUnitsToGfxUnits(border
.right
);
1610 borderBottom
= dc
->AppUnitsToGfxUnits(border
.bottom
);
1611 borderLeft
= dc
->AppUnitsToGfxUnits(border
.left
);
1613 gfxSize gfxImageSize
;
1614 gfxImageSize
.width
= nsPresContext::AppUnitsToFloatCSSPixels(imageSize
.width
);
1615 gfxImageSize
.height
= nsPresContext::AppUnitsToFloatCSSPixels(imageSize
.height
);
1617 nsRect
outerRect(aBorderArea
);
1622 clipRect
.pos
.x
= dc
->AppUnitsToGfxUnits(outerRect
.x
);
1623 clipRect
.pos
.y
= dc
->AppUnitsToGfxUnits(outerRect
.y
);
1624 clipRect
.size
.width
= dc
->AppUnitsToGfxUnits(outerRect
.width
);
1625 clipRect
.size
.height
= dc
->AppUnitsToGfxUnits(outerRect
.height
);
1626 if (thebesCtx
->UserToDevicePixelSnapped(clipRect
))
1627 clipRect
= thebesCtx
->DeviceToUser(clipRect
);
1630 thebesCtx
->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA
);
1632 gfxSize
middleSize(clipRect
.size
.width
- (borderLeft
+ borderRight
),
1633 clipRect
.size
.height
- (borderTop
+ borderBottom
));
1635 // middle size in source space
1636 gfxIntSize
middleSizeSource(gfxImageSize
.width
- (borderImageSplitGfx
[NS_SIDE_RIGHT
] + borderImageSplitGfx
[NS_SIDE_LEFT
]),
1637 gfxImageSize
.height
- (borderImageSplitGfx
[NS_SIDE_TOP
] + borderImageSplitGfx
[NS_SIDE_BOTTOM
]));
1639 gfxSize interSizeTop
, interSizeBottom
, interSizeLeft
, interSizeRight
,
1641 gfxFloat topScale
= borderTop
/borderImageSplitGfx
[NS_SIDE_TOP
];
1642 gfxFloat bottomScale
= borderBottom
/borderImageSplitGfx
[NS_SIDE_BOTTOM
];
1643 gfxFloat leftScale
= borderLeft
/borderImageSplitGfx
[NS_SIDE_LEFT
];
1644 gfxFloat rightScale
= borderRight
/borderImageSplitGfx
[NS_SIDE_RIGHT
];
1645 gfxFloat middleScaleH
,
1647 // TODO: check for nan and properly check for inf
1648 if (topScale
!= 0.0 && borderImageSplitGfx
[NS_SIDE_TOP
] != 0.0) {
1649 middleScaleH
= topScale
;
1650 } else if (bottomScale
!= 0.0 && borderImageSplitGfx
[NS_SIDE_BOTTOM
] != 0.0) {
1651 middleScaleH
= bottomScale
;
1656 if (leftScale
!= 0.0 && borderImageSplitGfx
[NS_SIDE_LEFT
] != 0.0) {
1657 middleScaleV
= leftScale
;
1658 } else if (rightScale
!= 0.0 && borderImageSplitGfx
[NS_SIDE_RIGHT
] != 0.0) {
1659 middleScaleV
= rightScale
;
1664 interSizeTop
.height
= borderTop
;
1665 interSizeTop
.width
= middleSizeSource
.width
*topScale
;
1667 interSizeBottom
.height
= borderBottom
;
1668 interSizeBottom
.width
= middleSizeSource
.width
*bottomScale
;
1670 interSizeLeft
.width
= borderLeft
;
1671 interSizeLeft
.height
= middleSizeSource
.height
*leftScale
;
1673 interSizeRight
.width
= borderRight
;
1674 interSizeRight
.height
= middleSizeSource
.height
*rightScale
;
1676 interSizeMiddle
.width
= middleSizeSource
.width
*middleScaleH
;
1677 interSizeMiddle
.height
= middleSizeSource
.height
*middleScaleV
;
1679 // draw top left corner
1680 rectToDraw
= clipRect
;
1681 rectToDraw
.size
.width
= borderLeft
;
1682 rectToDraw
.size
.height
= borderTop
;
1683 rectToDrawSource
.pos
.x
= 0;
1684 rectToDrawSource
.pos
.y
= 0;
1685 rectToDrawSource
.size
.width
= borderImageSplitGfx
[NS_SIDE_LEFT
];
1686 rectToDrawSource
.size
.height
= borderImageSplitGfx
[NS_SIDE_TOP
];
1687 DrawBorderImageSide(thebesCtx
, dc
, image
,
1688 rectToDraw
, rectToDraw
.size
, rectToDrawSource
,
1689 NS_STYLE_BORDER_IMAGE_STRETCH
, NS_STYLE_BORDER_IMAGE_STRETCH
);
1692 rectToDraw
= clipRect
;
1693 rectToDraw
.pos
.x
+= borderLeft
;
1694 rectToDraw
.size
.width
= middleSize
.width
;
1695 rectToDraw
.size
.height
= borderTop
;
1696 rectToDrawSource
.pos
.x
= borderImageSplitGfx
[NS_SIDE_LEFT
];
1697 rectToDrawSource
.pos
.y
= 0;
1698 rectToDrawSource
.size
.width
= middleSizeSource
.width
;
1699 rectToDrawSource
.size
.height
= borderImageSplitGfx
[NS_SIDE_TOP
];
1700 DrawBorderImageSide(thebesCtx
, dc
, image
,
1701 rectToDraw
, interSizeTop
, rectToDrawSource
,
1702 aBorderStyle
.mBorderImageHFill
, NS_STYLE_BORDER_IMAGE_STRETCH
);
1704 // draw top right corner
1705 rectToDraw
= clipRect
;
1706 rectToDraw
.pos
.x
+= clipRect
.size
.width
- borderRight
;
1707 rectToDraw
.size
.width
= borderRight
;
1708 rectToDraw
.size
.height
= borderTop
;
1709 rectToDrawSource
.pos
.x
= gfxImageSize
.width
- borderImageSplitGfx
[NS_SIDE_RIGHT
];
1710 rectToDrawSource
.pos
.y
= 0;
1711 rectToDrawSource
.size
.width
= borderImageSplitGfx
[NS_SIDE_RIGHT
];
1712 rectToDrawSource
.size
.height
= borderImageSplitGfx
[NS_SIDE_TOP
];
1713 DrawBorderImageSide(thebesCtx
, dc
, image
,
1714 rectToDraw
, rectToDraw
.size
, rectToDrawSource
,
1715 NS_STYLE_BORDER_IMAGE_STRETCH
, NS_STYLE_BORDER_IMAGE_STRETCH
);
1718 rectToDraw
= clipRect
;
1719 rectToDraw
.pos
.x
+= clipRect
.size
.width
- borderRight
;
1720 rectToDraw
.pos
.y
+= borderTop
;
1721 rectToDraw
.size
.width
= borderRight
;
1722 rectToDraw
.size
.height
= middleSize
.height
;
1723 rectToDrawSource
.pos
.x
= gfxImageSize
.width
- borderImageSplitGfx
[NS_SIDE_RIGHT
];
1724 rectToDrawSource
.pos
.y
= borderImageSplitGfx
[NS_SIDE_TOP
];
1725 rectToDrawSource
.size
.width
= borderImageSplitGfx
[NS_SIDE_RIGHT
];
1726 rectToDrawSource
.size
.height
= middleSizeSource
.height
;
1727 DrawBorderImageSide(thebesCtx
, dc
, image
,
1728 rectToDraw
, interSizeRight
, rectToDrawSource
,
1729 NS_STYLE_BORDER_IMAGE_STRETCH
, aBorderStyle
.mBorderImageVFill
);
1731 // draw bottom right corner
1732 rectToDraw
= clipRect
;
1733 rectToDraw
.pos
.x
+= clipRect
.size
.width
- borderRight
;
1734 rectToDraw
.pos
.y
+= clipRect
.size
.height
- borderBottom
;
1735 rectToDraw
.size
.width
= borderRight
;
1736 rectToDraw
.size
.height
= borderBottom
;
1737 rectToDrawSource
.pos
.x
= gfxImageSize
.width
- borderImageSplitGfx
[NS_SIDE_RIGHT
];
1738 rectToDrawSource
.pos
.y
= gfxImageSize
.height
- borderImageSplitGfx
[NS_SIDE_BOTTOM
];
1739 rectToDrawSource
.size
.width
= borderImageSplitGfx
[NS_SIDE_RIGHT
];
1740 rectToDrawSource
.size
.height
= borderImageSplitGfx
[NS_SIDE_BOTTOM
];
1741 DrawBorderImageSide(thebesCtx
, dc
, image
,
1742 rectToDraw
, rectToDraw
.size
, rectToDrawSource
,
1743 NS_STYLE_BORDER_IMAGE_STRETCH
, NS_STYLE_BORDER_IMAGE_STRETCH
);
1746 rectToDraw
= clipRect
;
1747 rectToDraw
.pos
.x
+= borderLeft
;
1748 rectToDraw
.pos
.y
+= clipRect
.size
.height
- borderBottom
;
1749 rectToDraw
.size
.width
= middleSize
.width
;
1750 rectToDraw
.size
.height
= borderBottom
;
1751 rectToDrawSource
.pos
.x
= borderImageSplitGfx
[NS_SIDE_LEFT
];
1752 rectToDrawSource
.pos
.y
= gfxImageSize
.height
- borderImageSplitGfx
[NS_SIDE_BOTTOM
];
1753 rectToDrawSource
.size
.width
= middleSizeSource
.width
;
1754 rectToDrawSource
.size
.height
= borderImageSplitGfx
[NS_SIDE_BOTTOM
];
1755 DrawBorderImageSide(thebesCtx
, dc
, image
,
1756 rectToDraw
, interSizeBottom
, rectToDrawSource
,
1757 aBorderStyle
.mBorderImageHFill
, NS_STYLE_BORDER_IMAGE_STRETCH
);
1759 // draw bottom left corner
1760 rectToDraw
= clipRect
;
1761 rectToDraw
.pos
.y
+= clipRect
.size
.height
- borderBottom
;
1762 rectToDraw
.size
.width
= borderLeft
;
1763 rectToDraw
.size
.height
= borderBottom
;
1764 rectToDrawSource
.pos
.x
= 0;
1765 rectToDrawSource
.pos
.y
= gfxImageSize
.height
- borderImageSplitGfx
[NS_SIDE_BOTTOM
];
1766 rectToDrawSource
.size
.width
= borderImageSplitGfx
[NS_SIDE_LEFT
];
1767 rectToDrawSource
.size
.height
= borderImageSplitGfx
[NS_SIDE_BOTTOM
];
1768 DrawBorderImageSide(thebesCtx
, dc
, image
,
1769 rectToDraw
, rectToDraw
.size
, rectToDrawSource
,
1770 NS_STYLE_BORDER_IMAGE_STRETCH
, NS_STYLE_BORDER_IMAGE_STRETCH
);
1773 rectToDraw
= clipRect
;
1774 rectToDraw
.pos
.y
+= borderTop
;
1775 rectToDraw
.size
.width
= borderLeft
;
1776 rectToDraw
.size
.height
= middleSize
.height
;
1777 rectToDrawSource
.pos
.x
= 0;
1778 rectToDrawSource
.pos
.y
= borderImageSplitGfx
[NS_SIDE_TOP
];
1779 rectToDrawSource
.size
.width
= borderImageSplitGfx
[NS_SIDE_LEFT
];
1780 rectToDrawSource
.size
.height
= middleSizeSource
.height
;
1781 DrawBorderImageSide(thebesCtx
, dc
, image
,
1782 rectToDraw
, interSizeLeft
, rectToDrawSource
,
1783 NS_STYLE_BORDER_IMAGE_STRETCH
, aBorderStyle
.mBorderImageVFill
);
1786 rectToDraw
= clipRect
;
1787 rectToDraw
.pos
.x
+= borderLeft
;
1788 rectToDraw
.pos
.y
+= borderTop
;
1789 rectToDraw
.size
.width
= middleSize
.width
;
1790 rectToDraw
.size
.height
= middleSize
.height
;
1791 rectToDrawSource
.pos
.x
= borderImageSplitGfx
[NS_SIDE_LEFT
];
1792 rectToDrawSource
.pos
.y
= borderImageSplitGfx
[NS_SIDE_TOP
];
1793 rectToDrawSource
.size
= middleSizeSource
;
1794 DrawBorderImageSide(thebesCtx
, dc
, image
,
1795 rectToDraw
, interSizeMiddle
, rectToDrawSource
,
1796 aBorderStyle
.mBorderImageHFill
, aBorderStyle
.mBorderImageVFill
);
1798 thebesCtx
->PopGroupToSource();
1799 thebesCtx
->SetOperator(gfxContext::OPERATOR_OVER
);
1801 thebesCtx
->Restore();
1805 DrawBorderImageSide(gfxContext
*aThebesContext
,
1806 nsIDeviceContext
* aDeviceContext
,
1807 imgIContainer
* aImage
,
1809 gfxSize aInterSize
, // non-ref to allow aliasing
1810 gfxRect
& aSourceRect
,
1814 if (aDestRect
.size
.width
< 1.0 || aDestRect
.size
.height
< 1.0 ||
1815 aSourceRect
.size
.width
< 1.0 || aSourceRect
.size
.height
< 1.0) {
1819 gfxIntSize
gfxSourceSize((PRInt32
)aSourceRect
.size
.width
,
1820 (PRInt32
)aSourceRect
.size
.height
);
1822 // where the actual border ends up being rendered
1823 if (aThebesContext
->UserToDevicePixelSnapped(aDestRect
))
1824 aDestRect
= aThebesContext
->DeviceToUser(aDestRect
);
1825 if (aThebesContext
->UserToDevicePixelSnapped(aSourceRect
))
1826 aSourceRect
= aThebesContext
->DeviceToUser(aSourceRect
);
1828 if (aDestRect
.size
.height
< 1.0 ||
1829 aDestRect
.size
.width
< 1.0)
1832 if (aInterSize
.width
< 1.0 ||
1833 aInterSize
.height
< 1.0)
1836 // Surface will hold just the part of the source image specified by the aSourceRect
1837 // but at a different size
1838 nsRefPtr
<gfxASurface
> interSurface
=
1839 gfxPlatform::GetPlatform()->CreateOffscreenSurface(
1840 gfxSourceSize
, gfxASurface::ImageFormatARGB32
);
1842 gfxMatrix srcMatrix
;
1843 // Adjust the matrix scale for Step 1 of the spec
1844 srcMatrix
.Scale(aSourceRect
.size
.width
/aInterSize
.width
,
1845 aSourceRect
.size
.height
/aInterSize
.height
);
1847 nsCOMPtr
<gfxIImageFrame
> frame
;
1848 nsresult rv
= aImage
->GetCurrentFrame(getter_AddRefs(frame
));
1851 nsCOMPtr
<nsIImage
> image
;
1852 image
= do_GetInterface(frame
);
1856 // surface for the whole image
1857 nsRefPtr
<gfxPattern
> imagePattern
;
1858 rv
= image
->GetPattern(getter_AddRefs(imagePattern
));
1859 if(NS_FAILED(rv
) || !imagePattern
)
1863 mat
.Translate(aSourceRect
.pos
);
1864 imagePattern
->SetMatrix(mat
);
1866 // Straightforward blit - no resizing
1867 nsRefPtr
<gfxContext
> srcCtx
= new gfxContext(interSurface
);
1868 srcCtx
->SetPattern(imagePattern
);
1869 srcCtx
->SetOperator(gfxContext::OPERATOR_SOURCE
);
1875 // offset to make the middle tile centered in the middle of the border
1876 gfxPoint
renderOffset(0, 0);
1877 gfxSize
rectSize(aDestRect
.size
);
1879 aThebesContext
->Save();
1880 aThebesContext
->Clip(aDestRect
);
1882 gfxFloat
hScale(1.0), vScale(1.0);
1884 nsRefPtr
<gfxPattern
> pattern
= new gfxPattern(interSurface
);
1885 pattern
->SetExtend(gfxPattern::EXTEND_PAD_EDGE
);
1886 switch (aHFillType
) {
1887 case NS_STYLE_BORDER_IMAGE_REPEAT
:
1888 renderOffset
.x
= (rectSize
.width
- aInterSize
.width
*NS_ceil(rectSize
.width
/aInterSize
.width
))*-0.5;
1889 aDestRect
.pos
.x
-= renderOffset
.x
;
1890 pattern
->SetExtend(gfxPattern::EXTEND_REPEAT
);
1892 case NS_STYLE_BORDER_IMAGE_ROUND
:
1893 hScale
= aInterSize
.width
*(NS_ceil(aDestRect
.size
.width
/aInterSize
.width
)/aDestRect
.size
.width
);
1894 pattern
->SetExtend(gfxPattern::EXTEND_REPEAT
);
1896 case NS_STYLE_BORDER_IMAGE_STRETCH
:
1898 hScale
= aInterSize
.width
/aDestRect
.size
.width
;
1902 switch (aVFillType
) {
1903 case NS_STYLE_BORDER_IMAGE_REPEAT
:
1904 renderOffset
.y
= (rectSize
.height
- aInterSize
.height
*NS_ceil(rectSize
.height
/aInterSize
.height
))*-0.5;
1905 aDestRect
.pos
.y
-= renderOffset
.y
;
1906 pattern
->SetExtend(gfxPattern::EXTEND_REPEAT
);
1908 case NS_STYLE_BORDER_IMAGE_ROUND
:
1909 vScale
= aInterSize
.height
*(NS_ceil(aDestRect
.size
.height
/aInterSize
.height
)/aDestRect
.size
.height
);
1910 pattern
->SetExtend(gfxPattern::EXTEND_REPEAT
);
1912 case NS_STYLE_BORDER_IMAGE_STRETCH
:
1914 vScale
= aInterSize
.height
/aDestRect
.size
.height
;
1918 // Adjust the matrix scale for Step 2 of the spec
1919 srcMatrix
.Scale(hScale
,vScale
);
1920 pattern
->SetMatrix(srcMatrix
);
1923 aThebesContext
->Translate(aDestRect
.pos
);
1924 aThebesContext
->SetPattern(pattern
);
1925 aThebesContext
->NewPath();
1926 aThebesContext
->Rectangle(gfxRect(renderOffset
, rectSize
));
1927 aThebesContext
->SetOperator(gfxContext::OPERATOR_ADD
);
1928 aThebesContext
->Fill();
1929 aThebesContext
->Restore();
1933 PaintBackgroundColor(nsPresContext
* aPresContext
,
1934 nsIRenderingContext
& aRenderingContext
,
1935 nsIFrame
* aForFrame
,
1936 const nsRect
& aBgClipArea
,
1937 const nsStyleBackground
& aColor
,
1938 const nsStyleBorder
& aBorder
,
1939 PRBool aCanPaintNonWhite
)
1941 // If we're only allowed to paint white, then don't bail out on transparent
1942 // color if we're not completely transparent. See the corresponding check
1943 // for whether we're allowed to paint background images in
1944 // PaintBackgroundWithSC before the first call to PaintBackgroundColor.
1945 if (NS_GET_A(aColor
.mBackgroundColor
) == 0 &&
1946 (aCanPaintNonWhite
|| aColor
.IsTransparent())) {
1951 nscolor color
= aColor
.mBackgroundColor
;
1952 if (!aCanPaintNonWhite
) {
1953 color
= NS_RGB(255, 255, 255);
1955 aRenderingContext
.SetColor(color
);
1957 if (!nsLayoutUtils::HasNonZeroCorner(aBorder
.mBorderRadius
)) {
1958 aRenderingContext
.FillRect(aBgClipArea
);
1962 gfxContext
*ctx
= aRenderingContext
.ThebesContext();
1964 // needed for our border thickness
1965 nscoord appUnitsPerPixel
= aPresContext
->AppUnitsPerDevPixel();
1967 nscoord borderRadii
[8];
1968 GetBorderRadiusTwips(aBorder
.mBorderRadius
, aForFrame
->GetSize().width
,
1971 // the bgClipArea is the outside
1972 gfxRect
oRect(RectToGfxRect(aBgClipArea
, appUnitsPerPixel
));
1975 if (oRect
.IsEmpty())
1978 // convert the radii
1979 gfxCornerSizes radii
;
1980 ComputePixelRadii(borderRadii
, aBgClipArea
,
1981 aForFrame
? aForFrame
->GetSkipSides() : 0,
1982 appUnitsPerPixel
, &radii
);
1984 // Add 1.0 to any border radii; if we don't, the border and background
1985 // curves will combine to have fringing at the rounded corners. Since
1986 // alpha is used for coverage, we have problems because the border and
1987 // background should have identical coverage, and the border should
1988 // overlay the background exactly. The way to avoid this is by using
1989 // a supersampling scheme, but we don't have the mechanism in place to do
1990 // this. So, this will do for now.
1991 for (int i
= 0; i
< 4; i
++) {
1992 if (radii
[i
].width
> 0.0)
1993 radii
[i
].width
+= 1.0;
1994 if (radii
[i
].height
> 0.0)
1995 radii
[i
].height
+= 1.0;
1999 ctx
->RoundedRectangle(oRect
, radii
);
2004 // Begin table border-collapsing section
2005 // These functions were written to not disrupt the normal ones and yet satisfy some additional requirements
2006 // At some point, all functions should be unified to include the additional functionality that these provide
2009 RoundIntToPixel(nscoord aValue
,
2010 nscoord aTwipsPerPixel
,
2011 PRBool aRoundDown
= PR_FALSE
)
2013 if (aTwipsPerPixel
<= 0)
2014 // We must be rendering to a device that has a resolution greater than Twips!
2015 // In that case, aValue is as accurate as it's going to get.
2018 nscoord halfPixel
= NSToCoordRound(aTwipsPerPixel
/ 2.0f
);
2019 nscoord extra
= aValue
% aTwipsPerPixel
;
2020 nscoord finalValue
= (!aRoundDown
&& (extra
>= halfPixel
)) ? aValue
+ (aTwipsPerPixel
- extra
) : aValue
- extra
;
2025 RoundFloatToPixel(float aValue
,
2026 nscoord aTwipsPerPixel
,
2027 PRBool aRoundDown
= PR_FALSE
)
2029 return RoundIntToPixel(NSToCoordRound(aValue
), aTwipsPerPixel
, aRoundDown
);
2033 SetPoly(const nsRect
& aRect
,
2036 poly
[0].x
= aRect
.x
;
2037 poly
[0].y
= aRect
.y
;
2038 poly
[1].x
= aRect
.x
+ aRect
.width
;
2039 poly
[1].y
= aRect
.y
;
2040 poly
[2].x
= aRect
.x
+ aRect
.width
;
2041 poly
[2].y
= aRect
.y
+ aRect
.height
;
2042 poly
[3].x
= aRect
.x
;
2043 poly
[3].y
= aRect
.y
+ aRect
.height
;
2044 poly
[4].x
= aRect
.x
;
2045 poly
[4].y
= aRect
.y
;
2049 DrawSolidBorderSegment(nsIRenderingContext
& aContext
,
2051 nscoord aTwipsPerPixel
,
2052 PRUint8 aStartBevelSide
= 0,
2053 nscoord aStartBevelOffset
= 0,
2054 PRUint8 aEndBevelSide
= 0,
2055 nscoord aEndBevelOffset
= 0)
2058 if ((aRect
.width
== aTwipsPerPixel
) || (aRect
.height
== aTwipsPerPixel
) ||
2059 ((0 == aStartBevelOffset
) && (0 == aEndBevelOffset
))) {
2060 // simple line or rectangle
2061 if ((NS_SIDE_TOP
== aStartBevelSide
) || (NS_SIDE_BOTTOM
== aStartBevelSide
)) {
2062 if (1 == aRect
.height
)
2063 aContext
.DrawLine(aRect
.x
, aRect
.y
, aRect
.x
, aRect
.y
+ aRect
.height
);
2065 aContext
.FillRect(aRect
);
2068 if (1 == aRect
.width
)
2069 aContext
.DrawLine(aRect
.x
, aRect
.y
, aRect
.x
+ aRect
.width
, aRect
.y
);
2071 aContext
.FillRect(aRect
);
2075 // polygon with beveling
2077 SetPoly(aRect
, poly
);
2078 switch(aStartBevelSide
) {
2080 poly
[0].x
+= aStartBevelOffset
;
2081 poly
[4].x
= poly
[0].x
;
2083 case NS_SIDE_BOTTOM
:
2084 poly
[3].x
+= aStartBevelOffset
;
2087 poly
[1].y
+= aStartBevelOffset
;
2090 poly
[0].y
+= aStartBevelOffset
;
2091 poly
[4].y
= poly
[0].y
;
2094 switch(aEndBevelSide
) {
2096 poly
[1].x
-= aEndBevelOffset
;
2098 case NS_SIDE_BOTTOM
:
2099 poly
[2].x
-= aEndBevelOffset
;
2102 poly
[2].y
-= aEndBevelOffset
;
2105 poly
[3].y
-= aEndBevelOffset
;
2108 aContext
.FillPolygon(poly
, 5);
2115 GetDashInfo(nscoord aBorderLength
,
2116 nscoord aDashLength
,
2117 nscoord aTwipsPerPixel
,
2118 PRInt32
& aNumDashSpaces
,
2119 nscoord
& aStartDashLength
,
2120 nscoord
& aEndDashLength
)
2123 if (aStartDashLength
+ aDashLength
+ aEndDashLength
>= aBorderLength
) {
2124 aStartDashLength
= aBorderLength
;
2128 aNumDashSpaces
= aBorderLength
/ (2 * aDashLength
); // round down
2129 nscoord extra
= aBorderLength
- aStartDashLength
- aEndDashLength
- (((2 * aNumDashSpaces
) - 1) * aDashLength
);
2131 nscoord half
= RoundIntToPixel(extra
/ 2, aTwipsPerPixel
);
2132 aStartDashLength
+= half
;
2133 aEndDashLength
+= (extra
- half
);
2139 nsCSSRendering::DrawTableBorderSegment(nsIRenderingContext
& aContext
,
2140 PRUint8 aBorderStyle
,
2141 nscolor aBorderColor
,
2142 const nsStyleBackground
* aBGColor
,
2143 const nsRect
& aBorder
,
2144 PRInt32 aAppUnitsPerCSSPixel
,
2145 PRUint8 aStartBevelSide
,
2146 nscoord aStartBevelOffset
,
2147 PRUint8 aEndBevelSide
,
2148 nscoord aEndBevelOffset
)
2150 aContext
.SetColor (aBorderColor
);
2152 PRBool horizontal
= ((NS_SIDE_TOP
== aStartBevelSide
) || (NS_SIDE_BOTTOM
== aStartBevelSide
));
2153 nscoord twipsPerPixel
= NSIntPixelsToAppUnits(1, aAppUnitsPerCSSPixel
);
2154 PRUint8 ridgeGroove
= NS_STYLE_BORDER_STYLE_RIDGE
;
2156 if ((twipsPerPixel
>= aBorder
.width
) || (twipsPerPixel
>= aBorder
.height
) ||
2157 (NS_STYLE_BORDER_STYLE_DASHED
== aBorderStyle
) || (NS_STYLE_BORDER_STYLE_DOTTED
== aBorderStyle
)) {
2158 // no beveling for 1 pixel border, dash or dot
2159 aStartBevelOffset
= 0;
2160 aEndBevelOffset
= 0;
2163 gfxContext
*ctx
= aContext
.ThebesContext();
2164 gfxContext::AntialiasMode oldMode
= ctx
->CurrentAntialiasMode();
2165 ctx
->SetAntialiasMode(gfxContext::MODE_ALIASED
);
2167 switch (aBorderStyle
) {
2168 case NS_STYLE_BORDER_STYLE_NONE
:
2169 case NS_STYLE_BORDER_STYLE_HIDDEN
:
2170 //NS_ASSERTION(PR_FALSE, "style of none or hidden");
2172 case NS_STYLE_BORDER_STYLE_DOTTED
:
2173 case NS_STYLE_BORDER_STYLE_DASHED
:
2175 nscoord dashLength
= (NS_STYLE_BORDER_STYLE_DASHED
== aBorderStyle
) ? DASH_LENGTH
: DOT_LENGTH
;
2176 // make the dash length proportional to the border thickness
2177 dashLength
*= (horizontal
) ? aBorder
.height
: aBorder
.width
;
2178 // make the min dash length for the ends 1/2 the dash length
2179 nscoord minDashLength
= (NS_STYLE_BORDER_STYLE_DASHED
== aBorderStyle
)
2180 ? RoundFloatToPixel(((float)dashLength
) / 2.0f
, twipsPerPixel
) : dashLength
;
2181 minDashLength
= PR_MAX(minDashLength
, twipsPerPixel
);
2182 nscoord numDashSpaces
= 0;
2183 nscoord startDashLength
= minDashLength
;
2184 nscoord endDashLength
= minDashLength
;
2186 GetDashInfo(aBorder
.width
, dashLength
, twipsPerPixel
, numDashSpaces
, startDashLength
, endDashLength
);
2187 nsRect
rect(aBorder
.x
, aBorder
.y
, startDashLength
, aBorder
.height
);
2188 DrawSolidBorderSegment(aContext
, rect
, twipsPerPixel
);
2189 for (PRInt32 spaceX
= 0; spaceX
< numDashSpaces
; spaceX
++) {
2190 rect
.x
+= rect
.width
+ dashLength
;
2191 rect
.width
= (spaceX
== (numDashSpaces
- 1)) ? endDashLength
: dashLength
;
2192 DrawSolidBorderSegment(aContext
, rect
, twipsPerPixel
);
2196 GetDashInfo(aBorder
.height
, dashLength
, twipsPerPixel
, numDashSpaces
, startDashLength
, endDashLength
);
2197 nsRect
rect(aBorder
.x
, aBorder
.y
, aBorder
.width
, startDashLength
);
2198 DrawSolidBorderSegment(aContext
, rect
, twipsPerPixel
);
2199 for (PRInt32 spaceY
= 0; spaceY
< numDashSpaces
; spaceY
++) {
2200 rect
.y
+= rect
.height
+ dashLength
;
2201 rect
.height
= (spaceY
== (numDashSpaces
- 1)) ? endDashLength
: dashLength
;
2202 DrawSolidBorderSegment(aContext
, rect
, twipsPerPixel
);
2207 case NS_STYLE_BORDER_STYLE_GROOVE
:
2208 ridgeGroove
= NS_STYLE_BORDER_STYLE_GROOVE
; // and fall through to ridge
2209 case NS_STYLE_BORDER_STYLE_RIDGE
:
2210 if ((horizontal
&& (twipsPerPixel
>= aBorder
.height
)) ||
2211 (!horizontal
&& (twipsPerPixel
>= aBorder
.width
))) {
2212 // a one pixel border
2213 DrawSolidBorderSegment(aContext
, aBorder
, twipsPerPixel
, aStartBevelSide
, aStartBevelOffset
,
2214 aEndBevelSide
, aEndBevelOffset
);
2217 nscoord startBevel
= (aStartBevelOffset
> 0)
2218 ? RoundFloatToPixel(0.5f
* (float)aStartBevelOffset
, twipsPerPixel
, PR_TRUE
) : 0;
2219 nscoord endBevel
= (aEndBevelOffset
> 0)
2220 ? RoundFloatToPixel(0.5f
* (float)aEndBevelOffset
, twipsPerPixel
, PR_TRUE
) : 0;
2221 PRUint8 ridgeGrooveSide
= (horizontal
) ? NS_SIDE_TOP
: NS_SIDE_LEFT
;
2223 MakeBevelColor(ridgeGrooveSide
, ridgeGroove
, aBGColor
->mBackgroundColor
, aBorderColor
));
2224 nsRect
rect(aBorder
);
2226 if (horizontal
) { // top, bottom
2227 half
= RoundFloatToPixel(0.5f
* (float)aBorder
.height
, twipsPerPixel
);
2229 if (NS_SIDE_TOP
== aStartBevelSide
) {
2230 rect
.x
+= startBevel
;
2231 rect
.width
-= startBevel
;
2233 if (NS_SIDE_TOP
== aEndBevelSide
) {
2234 rect
.width
-= endBevel
;
2236 DrawSolidBorderSegment(aContext
, rect
, twipsPerPixel
, aStartBevelSide
,
2237 startBevel
, aEndBevelSide
, endBevel
);
2239 else { // left, right
2240 half
= RoundFloatToPixel(0.5f
* (float)aBorder
.width
, twipsPerPixel
);
2242 if (NS_SIDE_LEFT
== aStartBevelSide
) {
2243 rect
.y
+= startBevel
;
2244 rect
.height
-= startBevel
;
2246 if (NS_SIDE_LEFT
== aEndBevelSide
) {
2247 rect
.height
-= endBevel
;
2249 DrawSolidBorderSegment(aContext
, rect
, twipsPerPixel
, aStartBevelSide
,
2250 startBevel
, aEndBevelSide
, endBevel
);
2254 ridgeGrooveSide
= (NS_SIDE_TOP
== ridgeGrooveSide
) ? NS_SIDE_BOTTOM
: NS_SIDE_RIGHT
;
2256 MakeBevelColor(ridgeGrooveSide
, ridgeGroove
, aBGColor
->mBackgroundColor
, aBorderColor
));
2258 rect
.y
= rect
.y
+ half
;
2259 rect
.height
= aBorder
.height
- half
;
2260 if (NS_SIDE_BOTTOM
== aStartBevelSide
) {
2261 rect
.x
+= startBevel
;
2262 rect
.width
-= startBevel
;
2264 if (NS_SIDE_BOTTOM
== aEndBevelSide
) {
2265 rect
.width
-= endBevel
;
2267 DrawSolidBorderSegment(aContext
, rect
, twipsPerPixel
, aStartBevelSide
,
2268 startBevel
, aEndBevelSide
, endBevel
);
2271 rect
.x
= rect
.x
+ half
;
2272 rect
.width
= aBorder
.width
- half
;
2273 if (NS_SIDE_RIGHT
== aStartBevelSide
) {
2274 rect
.y
+= aStartBevelOffset
- startBevel
;
2275 rect
.height
-= startBevel
;
2277 if (NS_SIDE_RIGHT
== aEndBevelSide
) {
2278 rect
.height
-= endBevel
;
2280 DrawSolidBorderSegment(aContext
, rect
, twipsPerPixel
, aStartBevelSide
,
2281 startBevel
, aEndBevelSide
, endBevel
);
2285 case NS_STYLE_BORDER_STYLE_DOUBLE
:
2286 if ((aBorder
.width
> 2) && (aBorder
.height
> 2)) {
2287 nscoord startBevel
= (aStartBevelOffset
> 0)
2288 ? RoundFloatToPixel(0.333333f
* (float)aStartBevelOffset
, twipsPerPixel
) : 0;
2289 nscoord endBevel
= (aEndBevelOffset
> 0)
2290 ? RoundFloatToPixel(0.333333f
* (float)aEndBevelOffset
, twipsPerPixel
) : 0;
2291 if (horizontal
) { // top, bottom
2292 nscoord thirdHeight
= RoundFloatToPixel(0.333333f
* (float)aBorder
.height
, twipsPerPixel
);
2294 // draw the top line or rect
2295 nsRect
topRect(aBorder
.x
, aBorder
.y
, aBorder
.width
, thirdHeight
);
2296 if (NS_SIDE_TOP
== aStartBevelSide
) {
2297 topRect
.x
+= aStartBevelOffset
- startBevel
;
2298 topRect
.width
-= aStartBevelOffset
- startBevel
;
2300 if (NS_SIDE_TOP
== aEndBevelSide
) {
2301 topRect
.width
-= aEndBevelOffset
- endBevel
;
2303 DrawSolidBorderSegment(aContext
, topRect
, twipsPerPixel
, aStartBevelSide
,
2304 startBevel
, aEndBevelSide
, endBevel
);
2306 // draw the botom line or rect
2307 nscoord heightOffset
= aBorder
.height
- thirdHeight
;
2308 nsRect
bottomRect(aBorder
.x
, aBorder
.y
+ heightOffset
, aBorder
.width
, aBorder
.height
- heightOffset
);
2309 if (NS_SIDE_BOTTOM
== aStartBevelSide
) {
2310 bottomRect
.x
+= aStartBevelOffset
- startBevel
;
2311 bottomRect
.width
-= aStartBevelOffset
- startBevel
;
2313 if (NS_SIDE_BOTTOM
== aEndBevelSide
) {
2314 bottomRect
.width
-= aEndBevelOffset
- endBevel
;
2316 DrawSolidBorderSegment(aContext
, bottomRect
, twipsPerPixel
, aStartBevelSide
,
2317 startBevel
, aEndBevelSide
, endBevel
);
2319 else { // left, right
2320 nscoord thirdWidth
= RoundFloatToPixel(0.333333f
* (float)aBorder
.width
, twipsPerPixel
);
2322 nsRect
leftRect(aBorder
.x
, aBorder
.y
, thirdWidth
, aBorder
.height
);
2323 if (NS_SIDE_LEFT
== aStartBevelSide
) {
2324 leftRect
.y
+= aStartBevelOffset
- startBevel
;
2325 leftRect
.height
-= aStartBevelOffset
- startBevel
;
2327 if (NS_SIDE_LEFT
== aEndBevelSide
) {
2328 leftRect
.height
-= aEndBevelOffset
- endBevel
;
2330 DrawSolidBorderSegment(aContext
, leftRect
, twipsPerPixel
, aStartBevelSide
,
2331 startBevel
, aEndBevelSide
, endBevel
);
2333 nscoord widthOffset
= aBorder
.width
- thirdWidth
;
2334 nsRect
rightRect(aBorder
.x
+ widthOffset
, aBorder
.y
, aBorder
.width
- widthOffset
, aBorder
.height
);
2335 if (NS_SIDE_RIGHT
== aStartBevelSide
) {
2336 rightRect
.y
+= aStartBevelOffset
- startBevel
;
2337 rightRect
.height
-= aStartBevelOffset
- startBevel
;
2339 if (NS_SIDE_RIGHT
== aEndBevelSide
) {
2340 rightRect
.height
-= aEndBevelOffset
- endBevel
;
2342 DrawSolidBorderSegment(aContext
, rightRect
, twipsPerPixel
, aStartBevelSide
,
2343 startBevel
, aEndBevelSide
, endBevel
);
2347 // else fall through to solid
2348 case NS_STYLE_BORDER_STYLE_SOLID
:
2349 DrawSolidBorderSegment(aContext
, aBorder
, twipsPerPixel
, aStartBevelSide
,
2350 aStartBevelOffset
, aEndBevelSide
, aEndBevelOffset
);
2352 case NS_STYLE_BORDER_STYLE_OUTSET
:
2353 case NS_STYLE_BORDER_STYLE_INSET
:
2354 NS_ASSERTION(PR_FALSE
, "inset, outset should have been converted to groove, ridge");
2356 case NS_STYLE_BORDER_STYLE_AUTO
:
2357 NS_ASSERTION(PR_FALSE
, "Unexpected 'auto' table border");
2361 ctx
->SetAntialiasMode(oldMode
);
2364 // End table border-collapsing section
2367 nsCSSRendering::PaintDecorationLine(gfxContext
* aGfxContext
,
2368 const nscolor aColor
,
2369 const gfxPoint
& aPt
,
2370 const gfxSize
& aLineSize
,
2371 const gfxFloat aAscent
,
2372 const gfxFloat aOffset
,
2373 const PRUint8 aDecoration
,
2374 const PRUint8 aStyle
)
2377 GetTextDecorationRectInternal(aPt
, aLineSize
, aAscent
, aOffset
,
2378 aDecoration
, aStyle
);
2382 if (aDecoration
!= NS_STYLE_TEXT_DECORATION_UNDERLINE
&&
2383 aDecoration
!= NS_STYLE_TEXT_DECORATION_OVERLINE
&&
2384 aDecoration
!= NS_STYLE_TEXT_DECORATION_LINE_THROUGH
)
2386 NS_ERROR("Invalid decoration value!");
2390 gfxFloat lineHeight
= PR_MAX(NS_round(aLineSize
.height
), 1.0);
2391 PRBool contextIsSaved
= PR_FALSE
;
2393 gfxFloat oldLineWidth
;
2394 nsRefPtr
<gfxPattern
> oldPattern
;
2397 case NS_STYLE_BORDER_STYLE_SOLID
:
2398 case NS_STYLE_BORDER_STYLE_DOUBLE
:
2399 oldLineWidth
= aGfxContext
->CurrentLineWidth();
2400 oldPattern
= aGfxContext
->GetPattern();
2402 case NS_STYLE_BORDER_STYLE_DASHED
: {
2403 aGfxContext
->Save();
2404 contextIsSaved
= PR_TRUE
;
2405 gfxFloat dashWidth
= lineHeight
* DOT_LENGTH
* DASH_LENGTH
;
2406 gfxFloat dash
[2] = { dashWidth
, dashWidth
};
2407 aGfxContext
->SetLineCap(gfxContext::LINE_CAP_BUTT
);
2408 aGfxContext
->SetDash(dash
, 2, 0.0);
2411 case NS_STYLE_BORDER_STYLE_DOTTED
: {
2412 aGfxContext
->Save();
2413 contextIsSaved
= PR_TRUE
;
2414 gfxFloat dashWidth
= lineHeight
* DOT_LENGTH
;
2416 if (lineHeight
> 2.0) {
2418 dash
[1] = dashWidth
* 2.0;
2419 aGfxContext
->SetLineCap(gfxContext::LINE_CAP_ROUND
);
2421 dash
[0] = dashWidth
;
2422 dash
[1] = dashWidth
;
2424 aGfxContext
->SetDash(dash
, 2, 0.0);
2428 NS_ERROR("Invalid style value!");
2432 // The y position should be set to the middle of the line.
2433 rect
.pos
.y
+= lineHeight
/ 2;
2435 aGfxContext
->SetColor(gfxRGBA(aColor
));
2436 aGfxContext
->SetLineWidth(lineHeight
);
2438 case NS_STYLE_BORDER_STYLE_SOLID
:
2439 aGfxContext
->NewPath();
2440 aGfxContext
->MoveTo(rect
.TopLeft());
2441 aGfxContext
->LineTo(rect
.TopRight());
2442 aGfxContext
->Stroke();
2444 case NS_STYLE_BORDER_STYLE_DOUBLE
:
2445 aGfxContext
->NewPath();
2446 aGfxContext
->MoveTo(rect
.TopLeft());
2447 aGfxContext
->LineTo(rect
.TopRight());
2448 rect
.size
.height
-= lineHeight
;
2449 aGfxContext
->MoveTo(rect
.BottomLeft());
2450 aGfxContext
->LineTo(rect
.BottomRight());
2451 aGfxContext
->Stroke();
2453 case NS_STYLE_BORDER_STYLE_DOTTED
:
2454 case NS_STYLE_BORDER_STYLE_DASHED
:
2455 aGfxContext
->NewPath();
2456 aGfxContext
->MoveTo(rect
.TopLeft());
2457 aGfxContext
->LineTo(rect
.TopRight());
2458 aGfxContext
->Stroke();
2461 NS_ERROR("Invalid style value!");
2465 if (contextIsSaved
) {
2466 aGfxContext
->Restore();
2468 aGfxContext
->SetPattern(oldPattern
);
2469 aGfxContext
->SetLineWidth(oldLineWidth
);
2474 nsCSSRendering::GetTextDecorationRect(nsPresContext
* aPresContext
,
2475 const gfxSize
& aLineSize
,
2476 const gfxFloat aAscent
,
2477 const gfxFloat aOffset
,
2478 const PRUint8 aDecoration
,
2479 const PRUint8 aStyle
)
2481 NS_ASSERTION(aPresContext
, "aPresContext is null");
2484 GetTextDecorationRectInternal(gfxPoint(0, 0), aLineSize
, aAscent
, aOffset
,
2485 aDecoration
, aStyle
);
2486 // The rect values are already rounded to nearest device pixels.
2488 r
.x
= aPresContext
->GfxUnitsToAppUnits(rect
.X());
2489 r
.y
= aPresContext
->GfxUnitsToAppUnits(rect
.Y());
2490 r
.width
= aPresContext
->GfxUnitsToAppUnits(rect
.Width());
2491 r
.height
= aPresContext
->GfxUnitsToAppUnits(rect
.Height());
2496 GetTextDecorationRectInternal(const gfxPoint
& aPt
,
2497 const gfxSize
& aLineSize
,
2498 const gfxFloat aAscent
,
2499 const gfxFloat aOffset
,
2500 const PRUint8 aDecoration
,
2501 const PRUint8 aStyle
)
2504 r
.pos
.x
= NS_floor(aPt
.x
+ 0.5);
2505 r
.size
.width
= NS_round(aLineSize
.width
);
2507 gfxFloat basesize
= NS_round(aLineSize
.height
);
2508 basesize
= PR_MAX(basesize
, 1.0);
2509 r
.size
.height
= basesize
;
2510 if (aStyle
== NS_STYLE_BORDER_STYLE_DOUBLE
) {
2511 gfxFloat gap
= NS_round(basesize
/ 2.0);
2512 gap
= PR_MAX(gap
, 1.0);
2513 r
.size
.height
= basesize
* 2.0 + gap
;
2515 r
.size
.height
= basesize
;
2518 gfxFloat baseline
= NS_floor(aPt
.y
+ aAscent
+ 0.5);
2519 gfxFloat offset
= 0;
2520 switch (aDecoration
) {
2521 case NS_STYLE_TEXT_DECORATION_UNDERLINE
:
2524 case NS_STYLE_TEXT_DECORATION_OVERLINE
:
2525 offset
= aOffset
- basesize
+ r
.Height();
2527 case NS_STYLE_TEXT_DECORATION_LINE_THROUGH
: {
2528 gfxFloat extra
= NS_floor(r
.Height() / 2.0 + 0.5);
2529 extra
= PR_MAX(extra
, basesize
);
2530 offset
= aOffset
- basesize
+ extra
;
2534 NS_ERROR("Invalid decoration value!");
2536 r
.pos
.y
= baseline
- NS_floor(offset
+ 0.5);
2544 nsContextBoxBlur::Init(const gfxRect
& aRect
, nscoord aBlurRadius
,
2545 PRInt32 aAppUnitsPerDevPixel
,
2546 gfxContext
* aDestinationCtx
,
2547 const gfxRect
& aDirtyRect
)
2549 mDestinationCtx
= aDestinationCtx
;
2551 PRInt32 blurRadius
= static_cast<PRInt32
>(aBlurRadius
/ aAppUnitsPerDevPixel
);
2553 // if not blurring, draw directly onto the destination device
2554 if (blurRadius
<= 0) {
2555 mContext
= aDestinationCtx
;
2559 // Convert from app units to device pixels
2560 gfxRect rect
= aRect
;
2561 rect
.ScaleInverse(aAppUnitsPerDevPixel
);
2563 if (rect
.IsEmpty()) {
2564 mContext
= aDestinationCtx
;
2568 gfxRect dirtyRect
= aDirtyRect
;
2569 dirtyRect
.ScaleInverse(aAppUnitsPerDevPixel
);
2571 mDestinationCtx
= aDestinationCtx
;
2573 // Create the temporary surface for blurring
2574 mContext
= blur
.Init(rect
, gfxIntSize(blurRadius
, blurRadius
), &dirtyRect
);
2579 nsContextBoxBlur::DoPaint()
2581 if (mContext
== mDestinationCtx
)
2584 blur
.Paint(mDestinationCtx
);
2588 nsContextBoxBlur::GetContext()