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 MOZILLA_GFX_BLUR_H_
8 #define MOZILLA_GFX_BLUR_H_
9 
10 #include "mozilla/gfx/Rect.h"
11 #include "mozilla/gfx/Point.h"
12 #include "mozilla/CheckedInt.h"
13 
14 namespace mozilla {
15 namespace gfx {
16 
17 #ifdef _MSC_VER
18 #  pragma warning(disable : 4251)
19 #endif
20 
21 /**
22  * Implementation of a triple box blur approximation of a Gaussian blur.
23  *
24  * A Gaussian blur is good for blurring because, when done independently
25  * in the horizontal and vertical directions, it matches the result that
26  * would be obtained using a different (rotated) set of axes.  A triple
27  * box blur is a very close approximation of a Gaussian.
28  *
29  * This is a "service" class; the constructors set up all the information
30  * based on the values and compute the minimum size for an 8-bit alpha
31  * channel context.
32  * The callers are responsible for creating and managing the backing surface
33  * and passing the pointer to the data to the Blur() method.  This class does
34  * not retain the pointer to the data outside of the Blur() call.
35  *
36  * A spread N makes each output pixel the maximum value of all source
37  * pixels within a square of side length 2N+1 centered on the output pixel.
38  */
39 class GFX2D_API AlphaBoxBlur final {
40  public:
41   /** Constructs a box blur and computes the backing surface size.
42    *
43    * @param aRect The coordinates of the surface to create in device units.
44    *
45    * @param aBlurRadius The blur radius in pixels.  This is the radius of the
46    *   entire (triple) kernel function.  Each individual box blur has radius
47    *   approximately 1/3 this value, or diameter approximately 2/3 this value.
48    *   This parameter should nearly always be computed using
49    * CalculateBlurRadius, below.
50    *
51    * @param aDirtyRect A pointer to a dirty rect, measured in device units, if
52    *   available.  This will be used for optimizing the blur operation. It is
53    *   safe to pass nullptr here.
54    *
55    * @param aSkipRect A pointer to a rect, measured in device units, that
56    *   represents an area where blurring is unnecessary and shouldn't be done
57    * for speed reasons. It is safe to pass nullptr here.
58    */
59   AlphaBoxBlur(const Rect& aRect, const IntSize& aSpreadRadius,
60                const IntSize& aBlurRadius, const Rect* aDirtyRect,
61                const Rect* aSkipRect);
62 
63   AlphaBoxBlur(const Rect& aRect, int32_t aStride, float aSigmaX,
64                float aSigmaY);
65 
66   AlphaBoxBlur();
67 
68   void Init(const Rect& aRect, const IntSize& aSpreadRadius,
69             const IntSize& aBlurRadius, const Rect* aDirtyRect,
70             const Rect* aSkipRect);
71 
72   ~AlphaBoxBlur();
73 
74   /**
75    * Return the size, in pixels, of the 8-bit alpha surface we'd use.
76    */
77   IntSize GetSize() const;
78 
79   /**
80    * Return the stride, in bytes, of the 8-bit alpha surface we'd use.
81    */
82   int32_t GetStride() const;
83 
84   /**
85    * Returns the device-space rectangle the 8-bit alpha surface covers.
86    */
87   IntRect GetRect() const;
88 
89   /**
90    * Return a pointer to a dirty rect, as passed in to the constructor, or
91    * nullptr if none was passed in.
92    */
93   Rect* GetDirtyRect();
94 
95   /**
96    * Return the spread radius, in pixels.
97    */
GetSpreadRadius()98   IntSize GetSpreadRadius() const { return mSpreadRadius; }
99 
100   /**
101    * Return the blur radius, in pixels.
102    */
GetBlurRadius()103   IntSize GetBlurRadius() const { return mBlurRadius; }
104 
105   /**
106    * Return the minimum buffer size that should be given to Blur() method.  If
107    * zero, the class is not properly setup for blurring.  Note that this
108    * includes the extra three bytes on top of the stride*width, where something
109    * like gfxImageSurface::GetDataSize() would report without it, even if it
110    * happens to have the extra bytes.
111    */
112   size_t GetSurfaceAllocationSize() const;
113 
114   /**
115    * Perform the blur in-place on the surface backed by specified 8-bit
116    * alpha surface data. The size must be at least that returned by
117    * GetSurfaceAllocationSize() or bad things will happen.
118    */
119   void Blur(uint8_t* aData) const;
120 
121   /**
122    * Calculates a blur radius that, when used with box blur, approximates a
123    * Gaussian blur with the given standard deviation.  The result of this
124    * function should be used as the aBlurRadius parameter to AlphaBoxBlur's
125    * constructor, above.
126    */
127   static IntSize CalculateBlurRadius(const Point& aStandardDeviation);
128   static Float CalculateBlurSigma(int32_t aBlurRadius);
129 
130  private:
131   void BoxBlur_C(uint8_t* aData, int32_t aLeftLobe, int32_t aRightLobe,
132                  int32_t aTopLobe, int32_t aBottomLobe,
133                  uint32_t* aIntegralImage, size_t aIntegralImageStride) const;
134   void BoxBlur_SSE2(uint8_t* aData, int32_t aLeftLobe, int32_t aRightLobe,
135                     int32_t aTopLobe, int32_t aBottomLobe,
136                     uint32_t* aIntegralImage,
137                     size_t aIntegralImageStride) const;
138   void BoxBlur_NEON(uint8_t* aData, int32_t aLeftLobe, int32_t aRightLobe,
139                     int32_t aTopLobe, int32_t aBottomLobe,
140                     uint32_t* aIntegralImage,
141                     size_t aIntegralImageStride) const;
142 #ifdef _MIPS_ARCH_LOONGSON3A
143   void BoxBlur_LS3(uint8_t* aData, int32_t aLeftLobe, int32_t aRightLobe,
144                    int32_t aTopLobe, int32_t aBottomLobe,
145                    uint32_t* aIntegralImage, size_t aIntegralImageStride) const;
146 #endif
147 
148   static CheckedInt<int32_t> RoundUpToMultipleOf4(int32_t aVal);
149 
150   /**
151    * A rect indicating the area where blurring is unnecessary, and the blur
152    * algorithm should skip over it.
153    *
154    * This is guaranteed to be 4-pixel aligned in the x axis.
155    */
156   IntRect mSkipRect;
157 
158   /**
159    * The device-space rectangle the the backing 8-bit alpha surface covers.
160    */
161   IntRect mRect;
162 
163   /**
164    * A copy of the dirty rect passed to the constructor. This will only be valid
165    * if mHasDirtyRect is true.
166    */
167   Rect mDirtyRect;
168 
169   /**
170    * The spread radius, in pixels.
171    */
172   IntSize mSpreadRadius;
173 
174   /**
175    * The blur radius, in pixels.
176    */
177   IntSize mBlurRadius;
178 
179   /**
180    * The stride of the data passed to Blur()
181    */
182   int32_t mStride;
183 
184   /**
185    * The minimum size of the buffer needed for the Blur() operation.
186    */
187   size_t mSurfaceAllocationSize;
188 
189   /**
190    * Whether mDirtyRect contains valid data.
191    */
192   bool mHasDirtyRect;
193 };
194 
195 }  // namespace gfx
196 }  // namespace mozilla
197 
198 #endif /* MOZILLA_GFX_BLUR_H_ */
199