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