1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef GFX_BLUR_H
7 #define GFX_BLUR_H
8 
9 #include "gfxTypes.h"
10 #include "nsSize.h"
11 #include "gfxPoint.h"
12 #include "mozilla/RefPtr.h"
13 #include "mozilla/UniquePtr.h"
14 
15 class gfxContext;
16 struct gfxRect;
17 
18 namespace mozilla {
19   namespace gfx {
20     class AlphaBoxBlur;
21     struct Color;
22     struct RectCornerRadii;
23     class SourceSurface;
24     class DrawTarget;
25   } // namespace gfx
26 } // namespace mozilla
27 
28 /**
29  * Implementation of a triple box blur approximation of a Gaussian blur.
30  *
31  * A Gaussian blur is good for blurring because, when done independently
32  * in the horizontal and vertical directions, it matches the result that
33  * would be obtained using a different (rotated) set of axes.  A triple
34  * box blur is a very close approximation of a Gaussian.
35  *
36  * Creates an 8-bit alpha channel context for callers to draw in,
37  * spreads the contents of that context, blurs the contents, and applies
38  * it as an alpha mask on a different existing context.
39  *
40  * A spread N makes each output pixel the maximum value of all source
41  * pixels within a square of side length 2N+1 centered on the output pixel.
42  *
43  * A temporary surface is created in the Init function. The caller then draws
44  * any desired content onto the context acquired through GetContext, and lastly
45  * calls Paint to apply the blurred content as an alpha mask.
46  */
47 class gfxAlphaBoxBlur
48 {
49     typedef mozilla::gfx::Color Color;
50     typedef mozilla::gfx::DrawTarget DrawTarget;
51     typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
52 
53 public:
54     gfxAlphaBoxBlur();
55 
56     ~gfxAlphaBoxBlur();
57 
58     /**
59      * Constructs a box blur and initializes the temporary surface.
60      * @param aRect The coordinates of the surface to create in device units.
61      *
62      * @param aBlurRadius The blur radius in pixels.  This is the radius of
63      *   the entire (triple) kernel function.  Each individual box blur has
64      *   radius approximately 1/3 this value, or diameter approximately 2/3
65      *   this value.  This parameter should nearly always be computed using
66      *   CalculateBlurRadius, below.
67      *
68      * @param aDirtyRect A pointer to a dirty rect, measured in device units,
69      *  if available. This will be used for optimizing the blur operation. It
70      *  is safe to pass nullptr here.
71      *
72      * @param aSkipRect A pointer to a rect, measured in device units, that
73      *  represents an area where blurring is unnecessary and shouldn't be done
74      *  for speed reasons. It is safe to pass nullptr here.
75      */
76     gfxContext* Init(const gfxRect& aRect,
77                      const mozilla::gfx::IntSize& aSpreadRadius,
78                      const mozilla::gfx::IntSize& aBlurRadius,
79                      const gfxRect* aDirtyRect,
80                      const gfxRect* aSkipRect);
81 
82     /**
83      * Returns the context that should be drawn to supply the alpha mask to be
84      * blurred. If the returned surface is null, then there was an error in
85      * its creation.
86      */
GetContext()87     gfxContext* GetContext()
88     {
89         return mContext;
90     }
91 
92     already_AddRefed<mozilla::gfx::SourceSurface>
93     DoBlur(DrawTarget* aDT, mozilla::gfx::IntPoint* aTopLeft);
94 
95     /**
96      * Does the actual blurring/spreading and mask applying. Users of this
97      * object must have drawn whatever they want to be blurred onto the internal
98      * gfxContext returned by GetContext before calling this.
99      *
100      * @param aDestinationCtx The graphics context on which to apply the
101      *  blurred mask.
102      */
103     void Paint(gfxContext* aDestinationCtx);
104 
105     /**
106      * Calculates a blur radius that, when used with box blur, approximates
107      * a Gaussian blur with the given standard deviation.  The result of
108      * this function should be used as the aBlurRadius parameter to Init,
109      * above.
110      */
111     static mozilla::gfx::IntSize CalculateBlurRadius(const gfxPoint& aStandardDeviation);
112 
113     /**
114      * Blurs a coloured rectangle onto aDestinationCtx. This is equivalent
115      * to calling Init(), drawing a rectangle onto the returned surface
116      * and then calling Paint, but may let us optimize better in the
117      * backend.
118      *
119      * @param aDestinationCtx      The destination to blur to.
120      * @param aRect                The rectangle to blur in device pixels.
121      * @param aCornerRadii         Corner radii for aRect, if it is a rounded
122      *                             rectangle.
123      * @param aBlurRadius          The standard deviation of the blur.
124      * @param aShadowColor         The color to draw the blurred shadow.
125      * @param aDirtyRect           An area in device pixels that is dirty and needs
126      *                             to be redrawn.
127      * @param aSkipRect            An area in device pixels to avoid blurring over,
128      *                             to prevent unnecessary work.
129      */
130     static void BlurRectangle(gfxContext *aDestinationCtx,
131                               const gfxRect& aRect,
132                               RectCornerRadii* aCornerRadii,
133                               const gfxPoint& aBlurStdDev,
134                               const Color& aShadowColor,
135                               const gfxRect& aDirtyRect,
136                               const gfxRect& aSkipRect);
137 
138     static void ShutdownBlurCache();
139 
140     /***
141      * Blurs an inset box shadow according to a given path.
142      * This is equivalent to calling Init(), drawing the inset path,
143      * and calling paint. Do not call Init() if using this method.
144      *
145      * @param aDestinationCtx     The destination to blur to.
146      * @param aDestinationRect    The destination rect in device pixels
147      * @param aShadowClipRect     The destiniation inner rect of the
148      *                            inset path in device pixels.
149      * @param aBlurRadius         The standard deviation of the blur.
150      * @param aSpreadRadius       The spread radius in device pixels.
151      * @param aShadowColor        The color of the blur.
152      * @param aHasBorderRadius    If this element also has a border radius
153      * @param aInnerClipRadii     Corner radii for the inside rect if it is a rounded rect.
154      * @param aSKipRect           An area in device pixels we don't have to paint in.
155      */
156     void BlurInsetBox(gfxContext* aDestinationCtx,
157                       const mozilla::gfx::Rect aDestinationRect,
158                       const mozilla::gfx::Rect aShadowClipRect,
159                       const mozilla::gfx::IntSize aBlurRadius,
160                       const mozilla::gfx::IntSize aSpreadRadius,
161                       const mozilla::gfx::Color& aShadowColor,
162                       const bool aHasBorderRadius,
163                       const RectCornerRadii& aInnerClipRadii,
164                       const mozilla::gfx::Rect aSkipRect,
165                       const mozilla::gfx::Point aShadowOffset);
166 
167 protected:
168     already_AddRefed<mozilla::gfx::SourceSurface>
169     GetInsetBlur(const mozilla::gfx::Rect aOuterRect,
170                  const mozilla::gfx::Rect aWhitespaceRect,
171                  const bool aIsDestRect,
172                  const mozilla::gfx::Color& aShadowColor,
173                  const mozilla::gfx::IntSize& aBlurRadius,
174                  const bool aHasBorderRadius,
175                  const RectCornerRadii& aInnerClipRadii,
176                  DrawTarget* aDestDrawTarget);
177 
178     /**
179      * The context of the temporary alpha surface.
180      */
181     RefPtr<gfxContext> mContext;
182 
183     /**
184      * The temporary alpha surface.
185      */
186     mozilla::UniquePtr<unsigned char[]> mData;
187 
188      /**
189       * The object that actually does the blurring for us.
190       */
191     mozilla::UniquePtr<mozilla::gfx::AlphaBoxBlur> mBlur;
192 };
193 
194 #endif /* GFX_BLUR_H */
195