Line data Source code
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 "gfxRect.h"
11 : #include "mozilla/Attributes.h"
12 : #include "mozilla/gfx/2D.h"
13 : #include "mozilla/gfx/BezierUtils.h"
14 : #include "mozilla/gfx/PathHelpers.h"
15 : #include "mozilla/RefPtr.h"
16 : #include "nsColor.h"
17 : #include "nsCOMPtr.h"
18 : #include "nsIFrame.h"
19 : #include "nsImageRenderer.h"
20 : #include "nsStyleConsts.h"
21 : #include "nsStyleStruct.h"
22 : #include "nsPresContext.h"
23 : #include "gfxUtils.h"
24 :
25 : struct nsBorderColors;
26 : class nsDisplayBorder;
27 :
28 : namespace mozilla {
29 : namespace gfx {
30 : class GradientStops;
31 : } // namespace gfx
32 : namespace layers {
33 : class StackingContextHelper;
34 : class WebRenderDisplayItemLayer;
35 : } // namespace layers
36 : } // namespace mozilla
37 :
38 : // define this to enable a bunch of debug dump info
39 : #undef DEBUG_NEW_BORDERS
40 :
41 : /*
42 : * Helper class that handles border rendering.
43 : *
44 : * aDrawTarget -- the DrawTarget to which the border should be rendered
45 : * outsideRect -- the rectangle on the outer edge of the border
46 : *
47 : * For any parameter where an array of side values is passed in,
48 : * they are in top, right, bottom, left order.
49 : *
50 : * borderStyles -- one border style enum per side
51 : * borderWidths -- one border width per side
52 : * borderRadii -- a RectCornerRadii struct describing the w/h for each rounded corner.
53 : * If the corner doesn't have a border radius, 0,0 should be given for it.
54 : * borderColors -- one nscolor per side
55 : * compositeColors -- a pointer to an array of composite color structs, or
56 : * nullptr if none.
57 : *
58 : * skipSides -- a bit mask specifying which sides, if any, to skip
59 : * backgroundColor -- the background color of the element.
60 : * Used in calculating colors for 2-tone borders, such as inset and outset
61 : * gapRect - a rectangle that should be clipped out to leave a gap in a border,
62 : * or nullptr if none.
63 : */
64 :
65 : typedef enum {
66 : BorderColorStyleNone,
67 : BorderColorStyleSolid,
68 : BorderColorStyleLight,
69 : BorderColorStyleDark
70 : } BorderColorStyle;
71 :
72 : class nsIDocument;
73 : class nsPresContext;
74 :
75 : class nsCSSBorderRenderer final
76 : {
77 : typedef mozilla::gfx::Bezier Bezier;
78 : typedef mozilla::gfx::ColorPattern ColorPattern;
79 : typedef mozilla::gfx::DrawTarget DrawTarget;
80 : typedef mozilla::gfx::Float Float;
81 : typedef mozilla::gfx::Path Path;
82 : typedef mozilla::gfx::Point Point;
83 : typedef mozilla::gfx::Rect Rect;
84 : typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
85 : typedef mozilla::gfx::StrokeOptions StrokeOptions;
86 :
87 : friend class nsDisplayBorder;
88 : friend class nsDisplayOutline;
89 : friend class nsDisplayButtonBorder;
90 : friend class nsDisplayButtonForeground;
91 :
92 : public:
93 :
94 : nsCSSBorderRenderer(nsPresContext* aPresContext,
95 : const nsIDocument* aDocument,
96 : DrawTarget* aDrawTarget,
97 : const Rect& aDirtyRect,
98 : Rect& aOuterRect,
99 : const uint8_t* aBorderStyles,
100 : const Float* aBorderWidths,
101 : RectCornerRadii& aBorderRadii,
102 : const nscolor* aBorderColors,
103 : nsBorderColors* const* aCompositeColors,
104 : nscolor aBackgroundColor);
105 :
106 : // draw the entire border
107 : void DrawBorders();
108 :
109 : bool CanCreateWebRenderCommands();
110 : void CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
111 : const mozilla::layers::StackingContextHelper& aSc);
112 :
113 : // utility function used for background painting as well as borders
114 : static void ComputeInnerRadii(const RectCornerRadii& aRadii,
115 : const Float* aBorderSizes,
116 : RectCornerRadii* aInnerRadiiRet);
117 :
118 : // Given aRadii as the border radii for a rectangle, compute the
119 : // appropriate radii for another rectangle *outside* that rectangle
120 : // by increasing the radii, except keeping sharp corners sharp.
121 : // Used for spread box-shadows
122 : static void ComputeOuterRadii(const RectCornerRadii& aRadii,
123 : const Float* aBorderSizes,
124 : RectCornerRadii* aOuterRadiiRet);
125 :
126 : static bool AllCornersZeroSize(const RectCornerRadii& corners);
127 :
128 : private:
129 :
130 : RectCornerRadii mBorderCornerDimensions;
131 :
132 : // Target document to report warning
133 : nsPresContext* mPresContext;
134 : const nsIDocument* mDocument;
135 :
136 : // destination DrawTarget and dirty rect
137 : DrawTarget* mDrawTarget;
138 : Rect mDirtyRect;
139 :
140 : // the rectangle of the outside and the inside of the border
141 : Rect mOuterRect;
142 : Rect mInnerRect;
143 :
144 : // the style and size of the border
145 : uint8_t mBorderStyles[4];
146 : Float mBorderWidths[4];
147 : RectCornerRadii mBorderRadii;
148 :
149 : // colors
150 : nscolor mBorderColors[4];
151 : nsBorderColors* mCompositeColors[4];
152 :
153 : // the background color
154 : nscolor mBackgroundColor;
155 :
156 : // calculated values
157 : bool mOneUnitBorder;
158 : bool mNoBorderRadius;
159 : bool mAvoidStroke;
160 :
161 : // For all the sides in the bitmask, would they be rendered
162 : // in an identical color and style?
163 : bool AreBorderSideFinalStylesSame(uint8_t aSides);
164 :
165 : // For the given style, is the given corner a solid color?
166 : bool IsSolidCornerStyle(uint8_t aStyle, mozilla::Corner aCorner);
167 :
168 : // For the given corner, is the given corner mergeable into one dot?
169 : bool IsCornerMergeable(mozilla::Corner aCorner);
170 :
171 : // For the given solid corner, what color style should be used?
172 : BorderColorStyle BorderColorStyleForSolidCorner(uint8_t aStyle, mozilla::Corner aCorner);
173 :
174 : //
175 : // Path generation functions
176 : //
177 :
178 : // Get the Rect for drawing the given corner
179 : Rect GetCornerRect(mozilla::Corner aCorner);
180 : // add the path for drawing the given side without any adjacent corners to the context
181 : Rect GetSideClipWithoutCornersRect(mozilla::Side aSide);
182 :
183 : // Create a clip path for the wedge that this side of
184 : // the border should take up. This is only called
185 : // when we're drawing separate border sides, so we know
186 : // that ADD compositing is taking place.
187 : //
188 : // This code needs to make sure that the individual pieces
189 : // don't ever (mathematically) overlap; the pixel overlap
190 : // is taken care of by the ADD compositing.
191 : already_AddRefed<Path> GetSideClipSubPath(mozilla::Side aSide);
192 :
193 : // Return start or end point for dashed/dotted side
194 : Point GetStraightBorderPoint(mozilla::Side aSide,
195 : mozilla::Corner aCorner,
196 : bool* aIsUnfilled,
197 : Float aDotOffset = 0.0f);
198 :
199 : // Return bezier control points for the outer and the inner curve for given
200 : // corner
201 : void GetOuterAndInnerBezier(Bezier* aOuterBezier,
202 : Bezier* aInnerBezier,
203 : mozilla::Corner aCorner);
204 :
205 : // Given a set of sides to fill and a color, do so in the fastest way.
206 : //
207 : // Stroke tends to be faster for smaller borders because it doesn't go
208 : // through the tessellator, which has initialization overhead. If
209 : // we're rendering all sides, we can use stroke at any thickness; we
210 : // also do TL/BR pairs at 1px thickness using stroke.
211 : //
212 : // If we can't stroke, then if it's a TL/BR pair, we use the specific
213 : // TL/BR paths. Otherwise, we do the full path and fill.
214 : //
215 : // Calling code is expected to only set up a clip as necessary; no
216 : // clip is needed if we can render the entire border in 1 or 2 passes.
217 : void FillSolidBorder(const Rect& aOuterRect,
218 : const Rect& aInnerRect,
219 : const RectCornerRadii& aBorderRadii,
220 : const Float* aBorderSizes,
221 : int aSides,
222 : const ColorPattern& aColor);
223 :
224 : //
225 : // core rendering
226 : //
227 :
228 : // draw the border for the given sides, using the style of the first side
229 : // present in the bitmask
230 : void DrawBorderSides (int aSides);
231 :
232 : // function used by the above to handle -moz-border-colors
233 : void DrawBorderSidesCompositeColors(int aSides, const nsBorderColors *compositeColors);
234 :
235 : // Setup the stroke options for the given dashed/dotted side
236 : void SetupDashedOptions(StrokeOptions* aStrokeOptions,
237 : Float aDash[2], mozilla::Side aSide,
238 : Float aBorderLength, bool isCorner);
239 :
240 : // Draw the given dashed/dotte side
241 : void DrawDashedOrDottedSide(mozilla::Side aSide);
242 :
243 : // Draw the given dotted side, each dot separately
244 : void DrawDottedSideSlow(mozilla::Side aSide);
245 :
246 : // Draw the given dashed/dotted corner
247 : void DrawDashedOrDottedCorner(mozilla::Side aSide,
248 : mozilla::Corner aCorner);
249 :
250 : // Draw the given dotted corner, each segment separately
251 : void DrawDottedCornerSlow(mozilla::Side aSide,
252 : mozilla::Corner aCorner);
253 :
254 : // Draw the given dashed corner, each dot separately
255 : void DrawDashedCornerSlow(mozilla::Side aSide,
256 : mozilla::Corner aCorner);
257 :
258 : // Draw the given dashed/dotted corner with solid style
259 : void DrawFallbackSolidCorner(mozilla::Side aSide,
260 : mozilla::Corner aCorner);
261 :
262 : // Analyze if all border sides have the same width.
263 : bool AllBordersSameWidth();
264 :
265 : // Analyze if all borders are 'solid' this also considers hidden or 'none'
266 : // borders because they can be considered 'solid' borders of 0 width and
267 : // with no color effect.
268 : bool AllBordersSolid(bool *aHasCompositeColors);
269 :
270 : // Draw a solid color border that is uniformly the same width.
271 : void DrawSingleWidthSolidBorder();
272 :
273 : // Draw any border which is solid on all sides and does not use
274 : // CompositeColors.
275 : void DrawNoCompositeColorSolidBorder();
276 :
277 : // Draw a solid border that has no border radius (i.e. is rectangular) and
278 : // uses CompositeColors.
279 : void DrawRectangularCompositeColors();
280 : };
281 :
282 6 : class nsCSSBorderImageRenderer final
283 : {
284 : typedef mozilla::nsImageRenderer nsImageRenderer;
285 : public:
286 : static mozilla::Maybe<nsCSSBorderImageRenderer>
287 : CreateBorderImageRenderer(nsPresContext* aPresContext,
288 : nsIFrame* aForFrame,
289 : const nsRect& aBorderArea,
290 : const nsStyleBorder& aStyleBorder,
291 : const nsRect& aDirtyRect,
292 : nsIFrame::Sides aSkipSides,
293 : uint32_t aFlags,
294 : mozilla::image::DrawResult* aDrawResult);
295 :
296 : mozilla::image::DrawResult
297 : DrawBorderImage(nsPresContext* aPresContext,
298 : gfxContext& aRenderingContext,
299 : nsIFrame* aForFrame,
300 : const nsRect& aDirtyRect);
301 :
302 : nsCSSBorderImageRenderer(const nsCSSBorderImageRenderer& aRhs);
303 : nsCSSBorderImageRenderer& operator=(const nsCSSBorderImageRenderer& aRhs);
304 :
305 : private:
306 : nsCSSBorderImageRenderer(nsIFrame* aForFrame,
307 : const nsRect& aBorderArea,
308 : const nsStyleBorder& aStyleBorder,
309 : nsIFrame::Sides aSkipSides,
310 : const nsImageRenderer& aImageRenderer);
311 :
312 : nsImageRenderer mImageRenderer;
313 : nsSize mImageSize;
314 : nsMargin mSlice;
315 : nsMargin mWidths;
316 : nsMargin mImageOutset;
317 : nsRect mArea;
318 : nsRect mClip;
319 : uint8_t mRepeatModeHorizontal;
320 : uint8_t mRepeatModeVertical;
321 : uint8_t mFill;
322 :
323 : friend class nsDisplayBorder;
324 : };
325 :
326 : namespace mozilla {
327 : #ifdef DEBUG_NEW_BORDERS
328 : #include <stdarg.h>
329 :
330 : static inline void PrintAsString(const mozilla::gfx::Point& p) {
331 : fprintf (stderr, "[%f,%f]", p.x, p.y);
332 : }
333 :
334 : static inline void PrintAsString(const mozilla::gfx::Size& s) {
335 : fprintf (stderr, "[%f %f]", s.width, s.height);
336 : }
337 :
338 : static inline void PrintAsString(const mozilla::gfx::Rect& r) {
339 : fprintf (stderr, "[%f %f %f %f]", r.X(), r.Y(), r.Width(), r.Height());
340 : }
341 :
342 : static inline void PrintAsString(const mozilla::gfx::Float f) {
343 : fprintf (stderr, "%f", f);
344 : }
345 :
346 : static inline void PrintAsString(const char *s) {
347 : fprintf (stderr, "%s", s);
348 : }
349 :
350 : static inline void PrintAsStringNewline(const char *s = nullptr) {
351 : if (s)
352 : fprintf (stderr, "%s", s);
353 : fprintf (stderr, "\n");
354 : fflush (stderr);
355 : }
356 :
357 : static inline MOZ_FORMAT_PRINTF(1, 2) void PrintAsFormatString(const char *fmt, ...) {
358 : va_list vl;
359 : va_start(vl, fmt);
360 : vfprintf (stderr, fmt, vl);
361 : va_end(vl);
362 : }
363 :
364 : #else
365 : static inline void PrintAsString(const mozilla::gfx::Point& p) {}
366 : static inline void PrintAsString(const mozilla::gfx::Size& s) {}
367 0 : static inline void PrintAsString(const mozilla::gfx::Rect& r) {}
368 : static inline void PrintAsString(const mozilla::gfx::Float f) {}
369 0 : static inline void PrintAsString(const char *s) {}
370 71 : static inline void PrintAsStringNewline(const char *s = nullptr) {}
371 68 : static inline MOZ_FORMAT_PRINTF(1, 2) void PrintAsFormatString(const char *fmt, ...) {}
372 : #endif
373 :
374 : } // namespace mozilla
375 :
376 : #endif /* NS_CSS_RENDERING_BORDERS_H */
|