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