• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkBitmap.h"
9 #include "SkBlurImageFilter.h"
10 #include "SkColorPriv.h"
11 #include "SkFlattenableBuffers.h"
12 #if SK_SUPPORT_GPU
13 #include "GrContext.h"
14 #include "SkImageFilterUtils.h"
15 #endif
16 
SkBlurImageFilter(SkFlattenableReadBuffer & buffer)17 SkBlurImageFilter::SkBlurImageFilter(SkFlattenableReadBuffer& buffer)
18   : INHERITED(buffer) {
19     fSigma.fWidth = buffer.readScalar();
20     fSigma.fHeight = buffer.readScalar();
21 }
22 
SkBlurImageFilter(SkScalar sigmaX,SkScalar sigmaY,SkImageFilter * input)23 SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX, SkScalar sigmaY, SkImageFilter* input)
24     : INHERITED(input), fSigma(SkSize::Make(sigmaX, sigmaY)) {
25     SkASSERT(sigmaX >= 0 && sigmaY >= 0);
26 }
27 
flatten(SkFlattenableWriteBuffer & buffer) const28 void SkBlurImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
29     this->INHERITED::flatten(buffer);
30     buffer.writeScalar(fSigma.fWidth);
31     buffer.writeScalar(fSigma.fHeight);
32 }
33 
boxBlurX(const SkBitmap & src,SkBitmap * dst,int kernelSize,int leftOffset,int rightOffset)34 static void boxBlurX(const SkBitmap& src, SkBitmap* dst, int kernelSize,
35                      int leftOffset, int rightOffset)
36 {
37     int width = src.width(), height = src.height();
38     int rightBorder = SkMin32(rightOffset + 1, width);
39     for (int y = 0; y < height; ++y) {
40         int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
41         SkPMColor* p = src.getAddr32(0, y);
42         for (int i = 0; i < rightBorder; ++i) {
43             sumA += SkGetPackedA32(*p);
44             sumR += SkGetPackedR32(*p);
45             sumG += SkGetPackedG32(*p);
46             sumB += SkGetPackedB32(*p);
47             p++;
48         }
49 
50         const SkColor* sptr = src.getAddr32(0, y);
51         SkColor* dptr = dst->getAddr32(0, y);
52         for (int x = 0; x < width; ++x) {
53             *dptr = SkPackARGB32(sumA / kernelSize,
54                                  sumR / kernelSize,
55                                  sumG / kernelSize,
56                                  sumB / kernelSize);
57             if (x >= leftOffset) {
58                 SkColor l = *(sptr - leftOffset);
59                 sumA -= SkGetPackedA32(l);
60                 sumR -= SkGetPackedR32(l);
61                 sumG -= SkGetPackedG32(l);
62                 sumB -= SkGetPackedB32(l);
63             }
64             if (x + rightOffset + 1 < width) {
65                 SkColor r = *(sptr + rightOffset + 1);
66                 sumA += SkGetPackedA32(r);
67                 sumR += SkGetPackedR32(r);
68                 sumG += SkGetPackedG32(r);
69                 sumB += SkGetPackedB32(r);
70             }
71             sptr++;
72             dptr++;
73         }
74     }
75 }
76 
boxBlurY(const SkBitmap & src,SkBitmap * dst,int kernelSize,int topOffset,int bottomOffset)77 static void boxBlurY(const SkBitmap& src, SkBitmap* dst, int kernelSize,
78                      int topOffset, int bottomOffset)
79 {
80     int width = src.width(), height = src.height();
81     int bottomBorder = SkMin32(bottomOffset + 1, height);
82     int srcStride = src.rowBytesAsPixels();
83     int dstStride = dst->rowBytesAsPixels();
84     for (int x = 0; x < width; ++x) {
85         int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
86         SkColor* p = src.getAddr32(x, 0);
87         for (int i = 0; i < bottomBorder; ++i) {
88             sumA += SkGetPackedA32(*p);
89             sumR += SkGetPackedR32(*p);
90             sumG += SkGetPackedG32(*p);
91             sumB += SkGetPackedB32(*p);
92             p += srcStride;
93         }
94 
95         const SkColor* sptr = src.getAddr32(x, 0);
96         SkColor* dptr = dst->getAddr32(x, 0);
97         for (int y = 0; y < height; ++y) {
98             *dptr = SkPackARGB32(sumA / kernelSize,
99                                  sumR / kernelSize,
100                                  sumG / kernelSize,
101                                  sumB / kernelSize);
102             if (y >= topOffset) {
103                 SkColor l = *(sptr - topOffset * srcStride);
104                 sumA -= SkGetPackedA32(l);
105                 sumR -= SkGetPackedR32(l);
106                 sumG -= SkGetPackedG32(l);
107                 sumB -= SkGetPackedB32(l);
108             }
109             if (y + bottomOffset + 1 < height) {
110                 SkColor r = *(sptr + (bottomOffset + 1) * srcStride);
111                 sumA += SkGetPackedA32(r);
112                 sumR += SkGetPackedR32(r);
113                 sumG += SkGetPackedG32(r);
114                 sumB += SkGetPackedB32(r);
115             }
116             sptr += srcStride;
117             dptr += dstStride;
118         }
119     }
120 }
121 
getBox3Params(SkScalar s,int * kernelSize,int * kernelSize3,int * lowOffset,int * highOffset)122 static void getBox3Params(SkScalar s, int *kernelSize, int* kernelSize3, int *lowOffset, int *highOffset)
123 {
124     float pi = SkScalarToFloat(SK_ScalarPI);
125     int d = static_cast<int>(floorf(SkScalarToFloat(s) * 3.0f * sqrtf(2.0f * pi) / 4.0f + 0.5f));
126     *kernelSize = d;
127     if (d % 2 == 1) {
128         *lowOffset = *highOffset = (d - 1) / 2;
129         *kernelSize3 = d;
130     } else {
131         *highOffset = d / 2;
132         *lowOffset = *highOffset - 1;
133         *kernelSize3 = d + 1;
134     }
135 }
136 
onFilterImage(Proxy * proxy,const SkBitmap & source,const SkMatrix & ctm,SkBitmap * dst,SkIPoint * offset)137 bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
138                                       const SkBitmap& source, const SkMatrix& ctm,
139                                       SkBitmap* dst, SkIPoint* offset) {
140     SkBitmap src = this->getInputResult(proxy, source, ctm, offset);
141     if (src.config() != SkBitmap::kARGB_8888_Config) {
142         return false;
143     }
144 
145     SkAutoLockPixels alp(src);
146     if (!src.getPixels()) {
147         return false;
148     }
149 
150     dst->setConfig(src.config(), src.width(), src.height());
151     dst->allocPixels();
152     int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX;
153     int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY;
154     getBox3Params(fSigma.width(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX);
155     getBox3Params(fSigma.height(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY);
156 
157     if (kernelSizeX < 0 || kernelSizeY < 0) {
158         return false;
159     }
160 
161     if (kernelSizeX == 0 && kernelSizeY == 0) {
162         src.copyTo(dst, dst->config());
163         return true;
164     }
165 
166     SkBitmap temp;
167     temp.setConfig(dst->config(), dst->width(), dst->height());
168     if (!temp.allocPixels()) {
169         return false;
170     }
171 
172     if (kernelSizeX > 0 && kernelSizeY > 0) {
173         boxBlurX(src,  &temp, kernelSizeX,  lowOffsetX, highOffsetX);
174         boxBlurY(temp, dst,   kernelSizeY,  lowOffsetY, highOffsetY);
175         boxBlurX(*dst, &temp, kernelSizeX,  highOffsetX,  lowOffsetX);
176         boxBlurY(temp, dst,   kernelSizeY,  highOffsetY,  lowOffsetY);
177         boxBlurX(*dst, &temp, kernelSizeX3, highOffsetX, highOffsetX);
178         boxBlurY(temp, dst,   kernelSizeY3, highOffsetY, highOffsetY);
179     } else if (kernelSizeX > 0) {
180         boxBlurX(src,  dst,   kernelSizeX,  lowOffsetX, highOffsetX);
181         boxBlurX(*dst, &temp, kernelSizeX,  highOffsetX,  lowOffsetX);
182         boxBlurX(temp, dst,   kernelSizeX3, highOffsetX, highOffsetX);
183     } else if (kernelSizeY > 0) {
184         boxBlurY(src,  dst,   kernelSizeY,  lowOffsetY, highOffsetY);
185         boxBlurY(*dst, &temp, kernelSizeY,  highOffsetY, lowOffsetY);
186         boxBlurY(temp, dst,   kernelSizeY3, highOffsetY, highOffsetY);
187     }
188     return true;
189 }
190 
filterImageGPU(Proxy * proxy,const SkBitmap & src,SkBitmap * result)191 bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
192 #if SK_SUPPORT_GPU
193     SkBitmap input;
194     if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &input)) {
195         return false;
196     }
197     GrTexture* source = (GrTexture*) input.getTexture();
198     SkRect rect;
199     src.getBounds(&rect);
200     SkAutoTUnref<GrTexture> tex(source->getContext()->gaussianBlur(source, false, rect,
201         fSigma.width(), fSigma.height()));
202     return SkImageFilterUtils::WrapTexture(tex, src.width(), src.height(), result);
203 #else
204     SkDEBUGFAIL("Should not call in GPU-less build");
205     return false;
206 #endif
207 }
208