/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ // vim:cindent:ts=2:et:sw=2: /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef NS_CSS_RENDERING_BORDERS_H #define NS_CSS_RENDERING_BORDERS_H #include "nsColor.h" class gfxContext; class gfxPattern; struct gfxRGBA; namespace mozilla { namespace gfx { class GradientStops; } } // define this to enable a bunch of debug dump info #undef DEBUG_NEW_BORDERS //thickness of dashed line relative to dotted line #define DOT_LENGTH 1 //square #define DASH_LENGTH 3 //3 times longer than dot //some shorthand for side bits #define SIDE_BIT_TOP (1 << NS_SIDE_TOP) #define SIDE_BIT_RIGHT (1 << NS_SIDE_RIGHT) #define SIDE_BIT_BOTTOM (1 << NS_SIDE_BOTTOM) #define SIDE_BIT_LEFT (1 << NS_SIDE_LEFT) #define SIDE_BITS_ALL (SIDE_BIT_TOP|SIDE_BIT_RIGHT|SIDE_BIT_BOTTOM|SIDE_BIT_LEFT) #define C_TL NS_CORNER_TOP_LEFT #define C_TR NS_CORNER_TOP_RIGHT #define C_BR NS_CORNER_BOTTOM_RIGHT #define C_BL NS_CORNER_BOTTOM_LEFT /* * Helper class that handles border rendering. * * appUnitsPerPixel -- current value of AUPP * destContext -- the gfxContext to which the border should be rendered * outsideRect -- the rectangle on the outer edge of the border * * For any parameter where an array of side values is passed in, * they are in top, right, bottom, left order. * * borderStyles -- one border style enum per side * borderWidths -- one border width per side * borderRadii -- a gfxCornerSizes struct describing the w/h for each rounded corner. * If the corner doesn't have a border radius, 0,0 should be given for it. * borderColors -- one nscolor per side * compositeColors -- a pointer to an array of composite color structs, or * nullptr if none. * * skipSides -- a bit mask specifying which sides, if any, to skip * backgroundColor -- the background color of the element. * Used in calculating colors for 2-tone borders, such as inset and outset * gapRect - a rectangle that should be clipped out to leave a gap in a border, * or nullptr if none. */ typedef enum { BorderColorStyleNone, BorderColorStyleSolid, BorderColorStyleLight, BorderColorStyleDark } BorderColorStyle; struct nsCSSBorderRenderer { nsCSSBorderRenderer(int32_t aAppUnitsPerPixel, gfxContext* aDestContext, gfxRect& aOuterRect, const uint8_t* aBorderStyles, const gfxFloat* aBorderWidths, gfxCornerSizes& aBorderRadii, const nscolor* aBorderColors, nsBorderColors* const* aCompositeColors, nscolor aBackgroundColor); gfxCornerSizes mBorderCornerDimensions; // destination context gfxContext* mContext; // the rectangle of the outside and the inside of the border gfxRect mOuterRect; gfxRect mInnerRect; // the style and size of the border const uint8_t* mBorderStyles; const gfxFloat* mBorderWidths; uint8_t* mSanitizedStyles; gfxFloat* mSanitizedWidths; gfxCornerSizes mBorderRadii; // colors const nscolor* mBorderColors; nsBorderColors* const* mCompositeColors; // core app units per pixel int32_t mAUPP; // the background color nscolor mBackgroundColor; // calculated values bool mOneUnitBorder; bool mNoBorderRadius; bool mAvoidStroke; // For all the sides in the bitmask, would they be rendered // in an identical color and style? bool AreBorderSideFinalStylesSame(uint8_t aSides); // For the given style, is the given corner a solid color? bool IsSolidCornerStyle(uint8_t aStyle, mozilla::css::Corner aCorner); // For the given solid corner, what color style should be used? BorderColorStyle BorderColorStyleForSolidCorner(uint8_t aStyle, mozilla::css::Corner aCorner); // // Path generation functions // // add the path for drawing the given corner to the context void DoCornerSubPath(mozilla::css::Corner aCorner); // add the path for drawing the given side without any adjacent corners to the context void DoSideClipWithoutCornersSubPath(mozilla::css::Side aSide); // Create a clip path for the wedge that this side of // the border should take up. This is only called // when we're drawing separate border sides, so we know // that ADD compositing is taking place. // // This code needs to make sure that the individual pieces // don't ever (mathematically) overlap; the pixel overlap // is taken care of by the ADD compositing. void DoSideClipSubPath(mozilla::css::Side aSide); // Given a set of sides to fill and a color, do so in the fastest way. // // Stroke tends to be faster for smaller borders because it doesn't go // through the tessellator, which has initialization overhead. If // we're rendering all sides, we can use stroke at any thickness; we // also do TL/BR pairs at 1px thickness using stroke. // // If we can't stroke, then if it's a TL/BR pair, we use the specific // TL/BR paths. Otherwise, we do the full path and fill. // // Calling code is expected to only set up a clip as necessary; no // clip is needed if we can render the entire border in 1 or 2 passes. void FillSolidBorder(const gfxRect& aOuterRect, const gfxRect& aInnerRect, const gfxCornerSizes& aBorderRadii, const gfxFloat *aBorderSizes, int aSides, const gfxRGBA& aColor); // // core rendering // // draw the border for the given sides, using the style of the first side // present in the bitmask void DrawBorderSides (int aSides); // function used by the above to handle -moz-border-colors void DrawBorderSidesCompositeColors(int aSides, const nsBorderColors *compositeColors); // draw the given dashed side void DrawDashedSide (mozilla::css::Side aSide); // Setup the stroke style for a given side void SetupStrokeStyle(mozilla::css::Side aSize); // Analyze if all border sides have the same width. bool AllBordersSameWidth(); // Analyze if all borders are 'solid' this also considers hidden or 'none' // borders because they can be considered 'solid' borders of 0 width and // with no color effect. bool AllBordersSolid(bool *aHasCompositeColors); // Create a gradient pattern that will handle the color transition for a // corner. already_AddRefed CreateCornerGradient(mozilla::css::Corner aCorner, const gfxRGBA &aFirstColor, const gfxRGBA &aSecondColor); // Azure variant of CreateCornerGradient. mozilla::TemporaryRef CreateCornerGradient(mozilla::css::Corner aCorner, const gfxRGBA &aFirstColor, const gfxRGBA &aSecondColor, mozilla::gfx::DrawTarget *aDT, mozilla::gfx::Point &aPoint1, mozilla::gfx::Point &aPoint2); // Draw a solid color border that is uniformly the same width. void DrawSingleWidthSolidBorder(); // Draw any border which is solid on all sides and does not use // CompositeColors. void DrawNoCompositeColorSolidBorder(); // Draw a solid border that has no border radius (i.e. is rectangular) and // uses CompositeColors. void DrawRectangularCompositeColors(); // draw the entire border void DrawBorders (); // utility function used for background painting as well as borders static void ComputeInnerRadii(const gfxCornerSizes& aRadii, const gfxFloat *aBorderSizes, gfxCornerSizes *aInnerRadiiRet); // Given aRadii as the border radii for a rectangle, compute the // appropriate radii for another rectangle *outside* that rectangle // by increasing the radii, except keeping sharp corners sharp. // Used for spread box-shadows static void ComputeOuterRadii(const gfxCornerSizes& aRadii, const gfxFloat *aBorderSizes, gfxCornerSizes *aOuterRadiiRet); }; namespace mozilla { #ifdef DEBUG_NEW_BORDERS #include static inline void S(const gfxPoint& p) { fprintf (stderr, "[%f,%f]", p.x, p.y); } static inline void S(const gfxSize& s) { fprintf (stderr, "[%f %f]", s.width, s.height); } static inline void S(const gfxRect& r) { fprintf (stderr, "[%f %f %f %f]", r.pos.x, r.pos.y, r.size.width, r.size.height); } static inline void S(const gfxFloat f) { fprintf (stderr, "%f", f); } static inline void S(const char *s) { fprintf (stderr, "%s", s); } static inline void SN(const char *s = nullptr) { if (s) fprintf (stderr, "%s", s); fprintf (stderr, "\n"); fflush (stderr); } static inline void SF(const char *fmt, ...) { va_list vl; va_start(vl, fmt); vfprintf (stderr, fmt, vl); va_end(vl); } static inline void SX(gfxContext *ctx) { gfxPoint p = ctx->CurrentPoint(); fprintf (stderr, "p: %f %f\n", p.x, p.y); return; ctx->MoveTo(p + gfxPoint(-2, -2)); ctx->LineTo(p + gfxPoint(2, 2)); ctx->MoveTo(p + gfxPoint(-2, 2)); ctx->LineTo(p + gfxPoint(2, -2)); ctx->MoveTo(p); } #else static inline void S(const gfxPoint& p) {} static inline void S(const gfxSize& s) {} static inline void S(const gfxRect& r) {} static inline void S(const gfxFloat f) {} static inline void S(const char *s) {} static inline void SN(const char *s = nullptr) {} static inline void SF(const char *fmt, ...) {} static inline void SX(gfxContext *ctx) {} #endif } #endif /* NS_CSS_RENDERING_BORDERS_H */