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