summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/gfxBlur.h
blob: da6ccae9a7010a384bc941b8f83af14edfcdc54a (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
199
200
201
202
203
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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 GFX_BLUR_H
#define GFX_BLUR_H

#include "gfxTypes.h"
#include "gfxRect.h"
#include "nsSize.h"
#include "gfxPoint.h"
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/Blur.h"

class gfxContext;

namespace mozilla {
namespace gfx {
struct sRGBColor;
struct RectCornerRadii;
class SourceSurface;
class DrawTarget;
}  // namespace gfx
}  // namespace mozilla

/**
 * 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.
 *
 * Creates an 8-bit alpha channel context for callers to draw in,
 * spreads the contents of that context, blurs the contents, and applies
 * it as an alpha mask on a different existing context.
 *
 * 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.
 *
 * A temporary surface is created in the Init function. The caller then draws
 * any desired content onto the context acquired through GetContext, and lastly
 * calls Paint to apply the blurred content as an alpha mask.
 */
class gfxAlphaBoxBlur final {
  typedef mozilla::gfx::sRGBColor sRGBColor;
  typedef mozilla::gfx::DrawTarget DrawTarget;
  typedef mozilla::gfx::RectCornerRadii RectCornerRadii;

 public:
  gfxAlphaBoxBlur() = default;

  ~gfxAlphaBoxBlur();

  /**
   * Constructs a box blur and initializes the temporary surface.
   *
   * @param aDestinationCtx The destination to blur to.
   *
   * @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.
   *
   * @param aUseHardwareAccel Flag to state whether or not we can use hardware
   *  acceleration to speed up this blur.
   */
  mozilla::UniquePtr<gfxContext> Init(
      gfxContext* aDestinationCtx, const gfxRect& aRect,
      const mozilla::gfx::IntSize& aSpreadRadius,
      const mozilla::gfx::IntSize& aBlurRadius, const gfxRect* aDirtyRect,
      const gfxRect* aSkipRect, bool aUseHardwareAccel = true);

  already_AddRefed<DrawTarget> InitDrawTarget(
      const mozilla::gfx::DrawTarget* aReferenceDT,
      const mozilla::gfx::Rect& aRect,
      const mozilla::gfx::IntSize& aSpreadRadius,
      const mozilla::gfx::IntSize& aBlurRadius,
      const mozilla::gfx::Rect* aDirtyRect = nullptr,
      const mozilla::gfx::Rect* aSkipRect = nullptr,
      bool aUseHardwareAccel = true);

  /**
   * Performs the blur and optionally colors the result if aShadowColor is not
   * null.
   */
  already_AddRefed<mozilla::gfx::SourceSurface> DoBlur(
      const mozilla::gfx::sRGBColor* aShadowColor = nullptr,
      mozilla::gfx::IntPoint* aOutTopLeft = nullptr);

  /**
   * Does the actual blurring/spreading and mask applying. Users of this
   * object must have drawn whatever they want to be blurred onto the internal
   * gfxContext returned by GetContext before calling this.
   *
   * @param aDestinationCtx The graphics context on which to apply the
   *  blurred mask.
   */
  void Paint(gfxContext* aDestinationCtx);

  /**
   * 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 Init,
   * above.
   */
  static mozilla::gfx::IntSize CalculateBlurRadius(
      const gfxPoint& aStandardDeviation);

  /**
   * Blurs a coloured rectangle onto aDestinationCtx. This is equivalent
   * to calling Init(), drawing a rectangle onto the returned surface
   * and then calling Paint, but may let us optimize better in the
   * backend.
   *
   * @param aDestinationCtx      The destination to blur to.
   * @param aRect                The rectangle to blur in device pixels.
   * @param aCornerRadii         Corner radii for aRect, if it is a rounded
   *                             rectangle.
   * @param aBlurRadius          The standard deviation of the blur.
   * @param aShadowColor         The color to draw the blurred shadow.
   * @param aDirtyRect           An area in device pixels that is dirty and
   * needs to be redrawn.
   * @param aSkipRect            An area in device pixels to avoid blurring
   * over, to prevent unnecessary work.
   */
  static void BlurRectangle(gfxContext* aDestinationCtx, const gfxRect& aRect,
                            const RectCornerRadii* aCornerRadii,
                            const gfxPoint& aBlurStdDev,
                            const sRGBColor& aShadowColor,
                            const gfxRect& aDirtyRect,
                            const gfxRect& aSkipRect);

  static void ShutdownBlurCache();

  /***
   * Blurs an inset box shadow according to a given path.
   * This is equivalent to calling Init(), drawing the inset path,
   * and calling paint. Do not call Init() if using this method.
   *
   * @param aDestinationCtx     The destination to blur to.
   * @param aDestinationRect    The destination rect in device pixels
   * @param aShadowClipRect     The destiniation inner rect of the
   *                            inset path in device pixels.
   * @param aBlurRadius         The standard deviation of the blur.
   * @param aShadowColor        The color of the blur.
   * @param aInnerClipRadii     Corner radii for the inside rect if it is a
   *                            rounded rect.
   * @param aSkipRect           An area in device pixels we don't have to
   *                            paint in.
   */
  void BlurInsetBox(gfxContext* aDestinationCtx,
                    const mozilla::gfx::Rect& aDestinationRect,
                    const mozilla::gfx::Rect& aShadowClipRect,
                    const mozilla::gfx::IntSize& aBlurRadius,
                    const mozilla::gfx::sRGBColor& aShadowColor,
                    const RectCornerRadii* aInnerClipRadii,
                    const mozilla::gfx::Rect& aSkipRect,
                    const mozilla::gfx::Point& aShadowOffset);

 protected:
  already_AddRefed<mozilla::gfx::SourceSurface> GetInsetBlur(
      const mozilla::gfx::Rect& aOuterRect,
      const mozilla::gfx::Rect& aWhitespaceRect, bool aIsDestRect,
      const mozilla::gfx::sRGBColor& aShadowColor,
      const mozilla::gfx::IntSize& aBlurRadius,
      const RectCornerRadii* aInnerClipRadii, DrawTarget* aDestDrawTarget,
      bool aMirrorCorners);

  /**
   * The DrawTarget of the temporary alpha surface.
   */
  RefPtr<DrawTarget> mDrawTarget;

  /**
   * The temporary alpha surface.
   */
  uint8_t* mData = nullptr;

  /**
   * The object that actually does the blurring for us.
   */
  mozilla::gfx::AlphaBoxBlur mBlur;

  /**
   * Indicates using DrawTarget-accelerated blurs.
   */
  bool mAccelerated = false;
};

#endif /* GFX_BLUR_H */