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 // Copyright (c) 2011-2016 Google Inc.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the gfx/skia/LICENSE file.
7 #ifndef MOZILLA_GFX_SKCONVOLVER_H_
8 #define MOZILLA_GFX_SKCONVOLVER_H_
10 #include "mozilla/Assertions.h"
17 class SkBitmapFilter
{
19 explicit SkBitmapFilter(float width
) : fWidth(width
) {}
20 virtual ~SkBitmapFilter() = default;
22 float width() const { return fWidth
; }
23 virtual float evaluate(float x
) const = 0;
29 class SkBoxFilter final
: public SkBitmapFilter
{
31 explicit SkBoxFilter(float width
= 0.5f
) : SkBitmapFilter(width
) {}
33 float evaluate(float x
) const override
{
34 return (x
>= -fWidth
&& x
< fWidth
) ? 1.0f
: 0.0f
;
38 class SkLanczosFilter final
: public SkBitmapFilter
{
40 explicit SkLanczosFilter(float width
= 3.0f
) : SkBitmapFilter(width
) {}
42 float evaluate(float x
) const override
{
43 if (x
<= -fWidth
|| x
>= fWidth
) {
44 return 0.0f
; // Outside of the window.
46 if (x
> -FLT_EPSILON
&& x
< FLT_EPSILON
) {
47 return 1.0f
; // Special case the discontinuity at the origin.
49 float xpi
= x
* float(M_PI
);
50 return (sinf(xpi
) / xpi
) * // sinc(x)
51 sinf(xpi
/ fWidth
) / (xpi
/ fWidth
); // sinc(x/fWidth)
55 // Represents a filter in one dimension. Each output pixel has one entry in this
56 // object for the filter values contributing to it. You build up the filter
57 // list by calling AddFilter for each output pixel (in order).
59 // We do 2-dimensional convolution by first convolving each row by one
60 // SkConvolutionFilter1D, then convolving each column by another one.
62 // Entries are stored in ConvolutionFixed point, shifted left by kShiftBits.
63 class SkConvolutionFilter1D
{
65 using ConvolutionFixed
= short;
67 // The number of bits that ConvolutionFixed point values are shifted by.
68 enum { kShiftBits
= 14 };
70 SkConvolutionFilter1D();
71 ~SkConvolutionFilter1D();
73 // Convert between floating point and our ConvolutionFixed point
75 static ConvolutionFixed
ToFixed(float f
) {
76 return static_cast<ConvolutionFixed
>(f
* (1 << kShiftBits
));
79 // Returns the maximum pixel span of a filter.
80 int maxFilter() const { return fMaxFilter
; }
82 // Returns the number of filters in this filter. This is the dimension of the
84 int numValues() const { return static_cast<int>(fFilters
.size()); }
86 void reserveAdditional(int filterCount
, int filterValueCount
) {
87 fFilters
.reserve(fFilters
.size() + filterCount
);
88 fFilterValues
.reserve(fFilterValues
.size() + filterValueCount
);
91 // Appends the given list of scaling values for generating a given output
92 // pixel. |filterOffset| is the distance from the edge of the image to where
93 // the scaling factors start. The scaling factors apply to the source pixels
94 // starting from this position, and going for the next |filterLength| pixels.
96 // You will probably want to make sure your input is normalized (that is,
97 // all entries in |filterValuesg| sub to one) to prevent affecting the overall
98 // brighness of the image.
100 // The filterLength must be > 0.
101 void AddFilter(int filterOffset
, const ConvolutionFixed
* filterValues
,
104 // Retrieves a filter for the given |valueOffset|, a position in the output
105 // image in the direction we're convolving. The offset and length of the
106 // filter values are put into the corresponding out arguments (see AddFilter
107 // above for what these mean), and a pointer to the first scaling factor is
108 // returned. There will be |filterLength| values in this array.
109 inline const ConvolutionFixed
* FilterForValue(int valueOffset
,
111 int* filterLength
) const {
112 const FilterInstance
& filter
= fFilters
[valueOffset
];
113 *filterOffset
= filter
.fOffset
;
114 *filterLength
= filter
.fTrimmedLength
;
115 if (filter
.fTrimmedLength
== 0) {
118 return &fFilterValues
[filter
.fDataLocation
];
121 bool ComputeFilterValues(const SkBitmapFilter
& aBitmapFilter
,
122 int32_t aSrcSize
, int32_t aDstSize
);
125 struct FilterInstance
{
126 // Offset within filterValues for this instance of the filter.
129 // Distance from the left of the filter to the center. IN PIXELS
132 // Number of values in this filter instance.
135 // Filter length as specified. Note that this may be different from
136 // 'trimmed_length' if leading/trailing zeros of the original floating
137 // point form were clipped differently on each tail.
141 // Stores the information for each filter added to this class.
142 std::vector
<FilterInstance
> fFilters
;
144 // We store all the filter values in this flat list, indexed by
145 // |FilterInstance.data_location| to avoid the mallocs required for storing
146 // each one separately.
147 std::vector
<ConvolutionFixed
> fFilterValues
;
149 // The maximum size of any filter we've added.
153 void convolve_horizontally(const unsigned char* srcData
,
154 const SkConvolutionFilter1D
& filter
,
155 unsigned char* outRow
, bool hasAlpha
);
157 void convolve_vertically(
158 const SkConvolutionFilter1D::ConvolutionFixed
* filterValues
,
159 int filterLength
, unsigned char* const* sourceDataRows
, int pixelWidth
,
160 unsigned char* outRow
, bool hasAlpha
);
162 bool BGRAConvolve2D(const unsigned char* sourceData
, int sourceByteRowStride
,
163 bool sourceHasAlpha
, const SkConvolutionFilter1D
& filterX
,
164 const SkConvolutionFilter1D
& filterY
,
165 int outputByteRowStride
, unsigned char* output
);
169 #endif /* MOZILLA_GFX_SKCONVOLVER_H_ */