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
5 : *
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/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Mozilla Corporation
20 : * Portions created by the Initial Developer are Copyright (C) 2008
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Vladimir Vukicevic <vladimir@pobox.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef NS_CSS_RENDERING_BORDERS_H
41 : #define NS_CSS_RENDERING_BORDERS_H
42 :
43 : #include "nsColor.h"
44 : #include "nsStyleStruct.h"
45 :
46 : #include "gfxContext.h"
47 :
48 : // define this to enable a bunch of debug dump info
49 : #undef DEBUG_NEW_BORDERS
50 :
51 : //thickness of dashed line relative to dotted line
52 : #define DOT_LENGTH 1 //square
53 : #define DASH_LENGTH 3 //3 times longer than dot
54 :
55 : //some shorthand for side bits
56 : #define SIDE_BIT_TOP (1 << NS_SIDE_TOP)
57 : #define SIDE_BIT_RIGHT (1 << NS_SIDE_RIGHT)
58 : #define SIDE_BIT_BOTTOM (1 << NS_SIDE_BOTTOM)
59 : #define SIDE_BIT_LEFT (1 << NS_SIDE_LEFT)
60 : #define SIDE_BITS_ALL (SIDE_BIT_TOP|SIDE_BIT_RIGHT|SIDE_BIT_BOTTOM|SIDE_BIT_LEFT)
61 :
62 : #define C_TL NS_CORNER_TOP_LEFT
63 : #define C_TR NS_CORNER_TOP_RIGHT
64 : #define C_BR NS_CORNER_BOTTOM_RIGHT
65 : #define C_BL NS_CORNER_BOTTOM_LEFT
66 :
67 : /*
68 : * Helper class that handles border rendering.
69 : *
70 : * appUnitsPerPixel -- current value of AUPP
71 : * destContext -- the gfxContext to which the border should be rendered
72 : * outsideRect -- the rectangle on the outer edge of the border
73 : *
74 : * For any parameter where an array of side values is passed in,
75 : * they are in top, right, bottom, left order.
76 : *
77 : * borderStyles -- one border style enum per side
78 : * borderWidths -- one border width per side
79 : * borderRadii -- a gfxCornerSizes struct describing the w/h for each rounded corner.
80 : * If the corner doesn't have a border radius, 0,0 should be given for it.
81 : * borderColors -- one nscolor per side
82 : * compositeColors -- a pointer to an array of composite color structs, or NULL if none
83 : *
84 : * skipSides -- a bit mask specifying which sides, if any, to skip
85 : * backgroundColor -- the background color of the element.
86 : * Used in calculating colors for 2-tone borders, such as inset and outset
87 : * gapRect - a rectangle that should be clipped out to leave a gap in a border,
88 : * or nsnull if none.
89 : */
90 :
91 : typedef enum {
92 : BorderColorStyleNone,
93 : BorderColorStyleSolid,
94 : BorderColorStyleLight,
95 : BorderColorStyleDark
96 : } BorderColorStyle;
97 :
98 : struct nsCSSBorderRenderer {
99 : nsCSSBorderRenderer(PRInt32 aAppUnitsPerPixel,
100 : gfxContext* aDestContext,
101 : gfxRect& aOuterRect,
102 : const PRUint8* aBorderStyles,
103 : const gfxFloat* aBorderWidths,
104 : gfxCornerSizes& aBorderRadii,
105 : const nscolor* aBorderColors,
106 : nsBorderColors* const* aCompositeColors,
107 : PRIntn aSkipSides,
108 : nscolor aBackgroundColor);
109 :
110 : gfxCornerSizes mBorderCornerDimensions;
111 :
112 : // destination context
113 : gfxContext* mContext;
114 :
115 : // the rectangle of the outside and the inside of the border
116 : gfxRect mOuterRect;
117 : gfxRect mInnerRect;
118 :
119 : // the style and size of the border
120 : const PRUint8* mBorderStyles;
121 : const gfxFloat* mBorderWidths;
122 : PRUint8* mSanitizedStyles;
123 : gfxFloat* mSanitizedWidths;
124 : gfxCornerSizes mBorderRadii;
125 :
126 : // colors
127 : const nscolor* mBorderColors;
128 : nsBorderColors* const* mCompositeColors;
129 :
130 : // core app units per pixel
131 : PRInt32 mAUPP;
132 :
133 : // misc -- which sides to skip, the background color
134 : PRIntn mSkipSides;
135 : nscolor mBackgroundColor;
136 :
137 : // calculated values
138 : bool mOneUnitBorder;
139 : bool mNoBorderRadius;
140 : bool mAvoidStroke;
141 :
142 : // For all the sides in the bitmask, would they be rendered
143 : // in an identical color and style?
144 : bool AreBorderSideFinalStylesSame(PRUint8 aSides);
145 :
146 : // For the given style, is the given corner a solid color?
147 : bool IsSolidCornerStyle(PRUint8 aStyle, mozilla::css::Corner aCorner);
148 :
149 : // For the given solid corner, what color style should be used?
150 : BorderColorStyle BorderColorStyleForSolidCorner(PRUint8 aStyle, mozilla::css::Corner aCorner);
151 :
152 : //
153 : // Path generation functions
154 : //
155 :
156 : // add the path for drawing the given corner to the context
157 : void DoCornerSubPath(mozilla::css::Corner aCorner);
158 : // add the path for drawing the given side without any adjacent corners to the context
159 : void DoSideClipWithoutCornersSubPath(mozilla::css::Side aSide);
160 :
161 : // Create a clip path for the wedge that this side of
162 : // the border should take up. This is only called
163 : // when we're drawing separate border sides, so we know
164 : // that ADD compositing is taking place.
165 : //
166 : // This code needs to make sure that the individual pieces
167 : // don't ever (mathematically) overlap; the pixel overlap
168 : // is taken care of by the ADD compositing.
169 : void DoSideClipSubPath(mozilla::css::Side aSide);
170 :
171 : // Given a set of sides to fill and a color, do so in the fastest way.
172 : //
173 : // Stroke tends to be faster for smaller borders because it doesn't go
174 : // through the tessellator, which has initialization overhead. If
175 : // we're rendering all sides, we can use stroke at any thickness; we
176 : // also do TL/BR pairs at 1px thickness using stroke.
177 : //
178 : // If we can't stroke, then if it's a TL/BR pair, we use the specific
179 : // TL/BR paths. Otherwise, we do the full path and fill.
180 : //
181 : // Calling code is expected to only set up a clip as necessary; no
182 : // clip is needed if we can render the entire border in 1 or 2 passes.
183 : void FillSolidBorder(const gfxRect& aOuterRect,
184 : const gfxRect& aInnerRect,
185 : const gfxCornerSizes& aBorderRadii,
186 : const gfxFloat *aBorderSizes,
187 : PRIntn aSides,
188 : const gfxRGBA& aColor);
189 :
190 : //
191 : // core rendering
192 : //
193 :
194 : // draw the border for the given sides, using the style of the first side
195 : // present in the bitmask
196 : void DrawBorderSides (PRIntn aSides);
197 :
198 : // function used by the above to handle -moz-border-colors
199 : void DrawBorderSidesCompositeColors(PRIntn aSides, const nsBorderColors *compositeColors);
200 :
201 : // draw the given dashed side
202 : void DrawDashedSide (mozilla::css::Side aSide);
203 :
204 : // Setup the stroke style for a given side
205 : void SetupStrokeStyle(mozilla::css::Side aSize);
206 :
207 : // Analyze if all border sides have the same width.
208 : bool AllBordersSameWidth();
209 :
210 : // Analyze if all borders are 'solid' this also considers hidden or 'none'
211 : // borders because they can be considered 'solid' borders of 0 width and
212 : // with no color effect.
213 : bool AllBordersSolid(bool *aHasCompositeColors);
214 :
215 : // Create a gradient pattern that will handle the color transition for a
216 : // corner.
217 : already_AddRefed<gfxPattern> CreateCornerGradient(mozilla::css::Corner aCorner,
218 : const gfxRGBA &aFirstColor,
219 : const gfxRGBA &aSecondColor);
220 :
221 : // Draw a solid color border that is uniformly the same width.
222 : void DrawSingleWidthSolidBorder();
223 :
224 : // Draw any border which is solid on all sides and does not use
225 : // CompositeColors.
226 : void DrawNoCompositeColorSolidBorder();
227 :
228 : // Draw a solid border that has no border radius (i.e. is rectangular) and
229 : // uses CompositeColors.
230 : void DrawRectangularCompositeColors();
231 :
232 : // draw the entire border
233 : void DrawBorders ();
234 :
235 : // utility function used for background painting as well as borders
236 : static void ComputeInnerRadii(const gfxCornerSizes& aRadii,
237 : const gfxFloat *aBorderSizes,
238 : gfxCornerSizes *aInnerRadiiRet);
239 : };
240 :
241 : #ifdef DEBUG_NEW_BORDERS
242 : #include <stdarg.h>
243 :
244 : static inline void S(const gfxPoint& p) {
245 : fprintf (stderr, "[%f,%f]", p.x, p.y);
246 : }
247 :
248 : static inline void S(const gfxSize& s) {
249 : fprintf (stderr, "[%f %f]", s.width, s.height);
250 : }
251 :
252 : static inline void S(const gfxRect& r) {
253 : fprintf (stderr, "[%f %f %f %f]", r.pos.x, r.pos.y, r.size.width, r.size.height);
254 : }
255 :
256 : static inline void S(const gfxFloat f) {
257 : fprintf (stderr, "%f", f);
258 : }
259 :
260 : static inline void S(const char *s) {
261 : fprintf (stderr, "%s", s);
262 : }
263 :
264 : static inline void SN(const char *s = nsnull) {
265 : if (s)
266 : fprintf (stderr, "%s", s);
267 : fprintf (stderr, "\n");
268 : fflush (stderr);
269 : }
270 :
271 : static inline void SF(const char *fmt, ...) {
272 : va_list vl;
273 : va_start(vl, fmt);
274 : vfprintf (stderr, fmt, vl);
275 : va_end(vl);
276 : }
277 :
278 : static inline void SX(gfxContext *ctx) {
279 : gfxPoint p = ctx->CurrentPoint();
280 : fprintf (stderr, "p: %f %f\n", p.x, p.y);
281 : return;
282 : ctx->MoveTo(p + gfxPoint(-2, -2)); ctx->LineTo(p + gfxPoint(2, 2));
283 : ctx->MoveTo(p + gfxPoint(-2, 2)); ctx->LineTo(p + gfxPoint(2, -2));
284 : ctx->MoveTo(p);
285 : }
286 :
287 :
288 : #else
289 : static inline void S(const gfxPoint& p) {}
290 : static inline void S(const gfxSize& s) {}
291 0 : static inline void S(const gfxRect& r) {}
292 : static inline void S(const gfxFloat f) {}
293 0 : static inline void S(const char *s) {}
294 0 : static inline void SN(const char *s = nsnull) {}
295 0 : static inline void SF(const char *fmt, ...) {}
296 : static inline void SX(gfxContext *ctx) {}
297 : #endif
298 :
299 : #endif /* NS_CSS_RENDERING_BORDERS_H */
|