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