summaryrefslogtreecommitdiffstats
path: root/gfx/2d/Blur.h
blob: e0f18c4c39cd3a33a9cdf7275a00effb7b056565 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 MOZILLA_GFX_BLUR_H_
#define MOZILLA_GFX_BLUR_H_

#include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/CheckedInt.h"

namespace mozilla {
namespace gfx {

#ifdef _MSC_VER
#  pragma warning(disable : 4251)
#endif

/**
 * Implementation of a triple box blur approximation of a Gaussian blur.
 *
 * A Gaussian blur is good for blurring because, when done independently
 * in the horizontal and vertical directions, it matches the result that
 * would be obtained using a different (rotated) set of axes.  A triple
 * box blur is a very close approximation of a Gaussian.
 *
 * This is a "service" class; the constructors set up all the information
 * based on the values and compute the minimum size for an 8-bit alpha
 * channel context.
 * The callers are responsible for creating and managing the backing surface
 * and passing the pointer to the data to the Blur() method.  This class does
 * not retain the pointer to the data outside of the Blur() call.
 *
 * A spread N makes each output pixel the maximum value of all source
 * pixels within a square of side length 2N+1 centered on the output pixel.
 */
class GFX2D_API AlphaBoxBlur final {
 public:
  /** Constructs a box blur and computes the backing surface size.
   *
   * @param aRect The coordinates of the surface to create in device units.
   *
   * @param aBlurRadius The blur radius in pixels.  This is the radius of the
   *   entire (triple) kernel function.  Each individual box blur has radius
   *   approximately 1/3 this value, or diameter approximately 2/3 this value.
   *   This parameter should nearly always be computed using
   * CalculateBlurRadius, below.
   *
   * @param aDirtyRect A pointer to a dirty rect, measured in device units, if
   *   available.  This will be used for optimizing the blur operation. It is
   *   safe to pass nullptr here.
   *
   * @param aSkipRect A pointer to a rect, measured in device units, that
   *   represents an area where blurring is unnecessary and shouldn't be done
   * for speed reasons. It is safe to pass nullptr here.
   */
  AlphaBoxBlur(const Rect& aRect, const IntSize& aSpreadRadius,
               const IntSize& aBlurRadius, const Rect* aDirtyRect,
               const Rect* aSkipRect);

  AlphaBoxBlur(const Rect& aRect, int32_t aStride, float aSigmaX,
               float aSigmaY);

  AlphaBoxBlur();

  void Init(const Rect& aRect, const IntSize& aSpreadRadius,
            const IntSize& aBlurRadius, const Rect* aDirtyRect,
            const Rect* aSkipRect);

  ~AlphaBoxBlur();

  /**
   * Return the size, in pixels, of the 8-bit alpha surface we'd use.
   */
  IntSize GetSize() const;

  /**
   * Return the stride, in bytes, of the 8-bit alpha surface we'd use.
   */
  int32_t GetStride() const;

  /**
   * Returns the device-space rectangle the 8-bit alpha surface covers.
   */
  IntRect GetRect() const;

  /**
   * Return a pointer to a dirty rect, as passed in to the constructor, or
   * nullptr if none was passed in.
   */
  Rect* GetDirtyRect();

  /**
   * Return the spread radius, in pixels.
   */
  IntSize GetSpreadRadius() const { return mSpreadRadius; }

  /**
   * Return the blur radius, in pixels.
   */
  IntSize GetBlurRadius() const { return mBlurRadius; }

  /**
   * Return the minimum buffer size that should be given to Blur() method.  If
   * zero, the class is not properly setup for blurring.  Note that this
   * includes the extra three bytes on top of the stride*width, where something
   * like gfxImageSurface::GetDataSize() would report without it, even if it
   * happens to have the extra bytes.
   */
  size_t GetSurfaceAllocationSize() const;

  /**
   * Perform the blur in-place on the surface backed by specified 8-bit
   * alpha surface data. The size must be at least that returned by
   * GetSurfaceAllocationSize() or bad things will happen.
   */
  void Blur(uint8_t* aData) const;

  /**
   * Calculates a blur radius that, when used with box blur, approximates a
   * Gaussian blur with the given standard deviation.  The result of this
   * function should be used as the aBlurRadius parameter to AlphaBoxBlur's
   * constructor, above.
   */
  static IntSize CalculateBlurRadius(const Point& aStandardDeviation);
  static Float CalculateBlurSigma(int32_t aBlurRadius);

 private:
  void BoxBlur_C(uint8_t* aData, int32_t aLeftLobe, int32_t aRightLobe,
                 int32_t aTopLobe, int32_t aBottomLobe,
                 uint32_t* aIntegralImage, size_t aIntegralImageStride) const;
  void BoxBlur_SSE2(uint8_t* aData, int32_t aLeftLobe, int32_t aRightLobe,
                    int32_t aTopLobe, int32_t aBottomLobe,
                    uint32_t* aIntegralImage,
                    size_t aIntegralImageStride) const;
  void BoxBlur_NEON(uint8_t* aData, int32_t aLeftLobe, int32_t aRightLobe,
                    int32_t aTopLobe, int32_t aBottomLobe,
                    uint32_t* aIntegralImage,
                    size_t aIntegralImageStride) const;
#ifdef _MIPS_ARCH_LOONGSON3A
  void BoxBlur_LS3(uint8_t* aData, int32_t aLeftLobe, int32_t aRightLobe,
                   int32_t aTopLobe, int32_t aBottomLobe,
                   uint32_t* aIntegralImage, size_t aIntegralImageStride) const;
#endif

  static CheckedInt<int32_t> RoundUpToMultipleOf4(int32_t aVal);

  /**
   * A rect indicating the area where blurring is unnecessary, and the blur
   * algorithm should skip over it.
   *
   * This is guaranteed to be 4-pixel aligned in the x axis.
   */
  IntRect mSkipRect;

  /**
   * The device-space rectangle the the backing 8-bit alpha surface covers.
   */
  IntRect mRect;

  /**
   * A copy of the dirty rect passed to the constructor. This will only be valid
   * if mHasDirtyRect is true.
   */
  Rect mDirtyRect;

  /**
   * The spread radius, in pixels.
   */
  IntSize mSpreadRadius;

  /**
   * The blur radius, in pixels.
   */
  IntSize mBlurRadius;

  /**
   * The stride of the data passed to Blur()
   */
  int32_t mStride;

  /**
   * The minimum size of the buffer needed for the Blur() operation.
   */
  size_t mSurfaceAllocationSize;

  /**
   * Whether mDirtyRect contains valid data.
   */
  bool mHasDirtyRect;
};

}  // namespace gfx
}  // namespace mozilla

#endif /* MOZILLA_GFX_BLUR_H_ */