OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 The Android Open Source Project | 2 * Copyright 2011 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkBitmap.h" | 8 #include "SkBitmap.h" |
9 #include "SkBlurImageFilter.h" | 9 #include "SkBlurImageFilter.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| 11 #include "SkImage_Base.h" |
| 12 #include "SkImagePriv.h" |
11 #include "SkReadBuffer.h" | 13 #include "SkReadBuffer.h" |
12 #include "SkWriteBuffer.h" | 14 #include "SkWriteBuffer.h" |
13 #include "SkGpuBlurUtils.h" | 15 #include "SkGpuBlurUtils.h" |
14 #include "SkBlurImage_opts.h" | 16 #include "SkBlurImage_opts.h" |
15 #if SK_SUPPORT_GPU | 17 #if SK_SUPPORT_GPU |
16 #include "GrContext.h" | 18 #include "GrContext.h" |
17 #endif | 19 #endif |
18 | 20 |
19 // This rather arbitrary-looking value results in a maximum box blur kernel size | 21 // This rather arbitrary-looking value results in a maximum box blur kernel size |
20 // of 1000 pixels on the raster path, which matches the WebKit and Firefox | 22 // of 1000 pixels on the raster path, which matches the WebKit and Firefox |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 *lowOffset = *highOffset = (d - 1) / 2; | 140 *lowOffset = *highOffset = (d - 1) / 2; |
139 *kernelSize3 = d; | 141 *kernelSize3 = d; |
140 } else { | 142 } else { |
141 *highOffset = d / 2; | 143 *highOffset = d / 2; |
142 *lowOffset = *highOffset - 1; | 144 *lowOffset = *highOffset - 1; |
143 *kernelSize3 = d + 1; | 145 *kernelSize3 = d + 1; |
144 } | 146 } |
145 } | 147 } |
146 | 148 |
147 bool SkBlurImageFilter::onFilterImage(Proxy* proxy, | 149 bool SkBlurImageFilter::onFilterImage(Proxy* proxy, |
148 const SkBitmap& source, const Context& ctx
, | 150 const SkImage* source, const Context& ctx, |
149 SkBitmap* dst, SkIPoint* offset) const { | 151 SkAutoTUnref<const SkImage>& dst, SkIPoint
* offset) const { |
150 SkBitmap src = source; | 152 SkAutoTUnref<const SkImage> src(SkRef(source)); |
151 SkIPoint srcOffset = SkIPoint::Make(0, 0); | 153 SkIPoint srcOffset = SkIPoint::Make(0, 0); |
152 if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcO
ffset)) { | 154 if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, src, &srcOf
fset)) { |
153 return false; | |
154 } | |
155 | |
156 if (src.colorType() != kN32_SkColorType) { | |
157 return false; | 155 return false; |
158 } | 156 } |
159 | 157 |
160 SkIRect srcBounds, dstBounds; | 158 SkIRect srcBounds, dstBounds; |
161 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &srcBounds, &src)) { | 159 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &srcBounds, src)) { |
162 return false; | 160 return false; |
163 } | 161 } |
164 | 162 |
165 SkAutoLockPixels alp(src); | 163 SkBitmap srcBitmap; |
166 if (!src.getPixels()) { | 164 SkAutoAdoptImageAsN32Bitmap aai(src, &srcBitmap); |
| 165 if (NULL == srcBitmap.getPixels()) { |
167 return false; | 166 return false; |
168 } | 167 } |
169 | 168 |
170 if (!dst->tryAllocPixels(src.info().makeWH(srcBounds.width(), srcBounds.heig
ht()))) { | 169 SkBitmap dstBitmap; |
| 170 if (!dstBitmap.tryAllocPixels( |
| 171 srcBitmap.info().makeWH(srcBounds.width(), srcBounds.height()))) { |
171 return false; | 172 return false; |
172 } | 173 } |
173 dst->getBounds(&dstBounds); | 174 dstBitmap.getBounds(&dstBounds); |
174 | 175 |
175 SkVector sigma = mapSigma(fSigma, ctx.ctm()); | 176 SkVector sigma = mapSigma(fSigma, ctx.ctm()); |
176 | 177 |
177 int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; | 178 int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; |
178 int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; | 179 int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; |
179 getBox3Params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffs
etX); | 180 getBox3Params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffs
etX); |
180 getBox3Params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffs
etY); | 181 getBox3Params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffs
etY); |
181 | 182 |
182 if (kernelSizeX < 0 || kernelSizeY < 0) { | 183 if (kernelSizeX < 0 || kernelSizeY < 0) { |
183 return false; | 184 return false; |
184 } | 185 } |
185 | 186 |
186 if (kernelSizeX == 0 && kernelSizeY == 0) { | 187 if (kernelSizeX == 0 && kernelSizeY == 0) { |
187 src.copyTo(dst, dst->colorType()); | 188 srcBitmap.copyTo(&dstBitmap, dstBitmap.colorType()); |
| 189 srcBitmap = SkBitmap(); |
| 190 SkImage* image = SkNewImageFromBitmap(dstBitmap, NULL); |
| 191 if (NULL == image) { |
| 192 return false; |
| 193 } |
| 194 dst.reset(image); |
188 offset->fX = srcBounds.fLeft; | 195 offset->fX = srcBounds.fLeft; |
189 offset->fY = srcBounds.fTop; | 196 offset->fY = srcBounds.fTop; |
190 return true; | 197 return true; |
191 } | 198 } |
192 | 199 |
193 SkBitmap temp; | 200 SkBitmap temp; |
194 if (!temp.tryAllocPixels(dst->info())) { | 201 if (!temp.tryAllocPixels(dstBitmap.info())) { |
195 return false; | 202 return false; |
196 } | 203 } |
197 | 204 |
198 offset->fX = srcBounds.fLeft; | 205 int32_t resultX = srcBounds.fLeft; |
199 offset->fY = srcBounds.fTop; | 206 int32_t resultY = srcBounds.fTop; |
200 srcBounds.offset(-srcOffset); | 207 srcBounds.offset(-srcOffset); |
201 const SkPMColor* s = src.getAddr32(srcBounds.left(), srcBounds.top()); | 208 const SkPMColor* s = srcBitmap.getAddr32(srcBounds.left(), srcBounds.top()); |
202 SkPMColor* t = temp.getAddr32(0, 0); | 209 SkPMColor* t = temp.getAddr32(0, 0); |
203 SkPMColor* d = dst->getAddr32(0, 0); | 210 SkPMColor* d = dstBitmap.getAddr32(0, 0); |
204 int w = dstBounds.width(), h = dstBounds.height(); | 211 int w = dstBounds.width(), h = dstBounds.height(); |
205 int sw = src.rowBytesAsPixels(); | 212 int sw = srcBitmap.rowBytesAsPixels(); |
206 SkBoxBlurProc boxBlurX, boxBlurY, boxBlurXY, boxBlurYX; | 213 SkBoxBlurProc boxBlurX, boxBlurY, boxBlurXY, boxBlurYX; |
207 if (!SkBoxBlurGetPlatformProcs(&boxBlurX, &boxBlurY, &boxBlurXY, &boxBlurYX)
) { | 214 if (!SkBoxBlurGetPlatformProcs(&boxBlurX, &boxBlurY, &boxBlurXY, &boxBlurYX)
) { |
208 boxBlurX = boxBlur<kX, kX>; | 215 boxBlurX = boxBlur<kX, kX>; |
209 boxBlurY = boxBlur<kY, kY>; | 216 boxBlurY = boxBlur<kY, kY>; |
210 boxBlurXY = boxBlur<kX, kY>; | 217 boxBlurXY = boxBlur<kX, kY>; |
211 boxBlurYX = boxBlur<kY, kX>; | 218 boxBlurYX = boxBlur<kY, kX>; |
212 } | 219 } |
213 | 220 |
214 if (kernelSizeX > 0 && kernelSizeY > 0) { | 221 if (kernelSizeX > 0 && kernelSizeY > 0) { |
215 boxBlurX(s, sw, t, kernelSizeX, lowOffsetX, highOffsetX, w, h); | 222 boxBlurX(s, sw, t, kernelSizeX, lowOffsetX, highOffsetX, w, h); |
216 boxBlurX(t, w, d, kernelSizeX, highOffsetX, lowOffsetX, w, h); | 223 boxBlurX(t, w, d, kernelSizeX, highOffsetX, lowOffsetX, w, h); |
217 boxBlurXY(d, w, t, kernelSizeX3, highOffsetX, highOffsetX, w, h); | 224 boxBlurXY(d, w, t, kernelSizeX3, highOffsetX, highOffsetX, w, h); |
218 boxBlurX(t, h, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); | 225 boxBlurX(t, h, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); |
219 boxBlurX(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); | 226 boxBlurX(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); |
220 boxBlurXY(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); | 227 boxBlurXY(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); |
221 } else if (kernelSizeX > 0) { | 228 } else if (kernelSizeX > 0) { |
222 boxBlurX(s, sw, d, kernelSizeX, lowOffsetX, highOffsetX, w, h); | 229 boxBlurX(s, sw, d, kernelSizeX, lowOffsetX, highOffsetX, w, h); |
223 boxBlurX(d, w, t, kernelSizeX, highOffsetX, lowOffsetX, w, h); | 230 boxBlurX(d, w, t, kernelSizeX, highOffsetX, lowOffsetX, w, h); |
224 boxBlurX(t, w, d, kernelSizeX3, highOffsetX, highOffsetX, w, h); | 231 boxBlurX(t, w, d, kernelSizeX3, highOffsetX, highOffsetX, w, h); |
225 } else if (kernelSizeY > 0) { | 232 } else if (kernelSizeY > 0) { |
226 boxBlurYX(s, sw, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); | 233 boxBlurYX(s, sw, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); |
227 boxBlurX(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); | 234 boxBlurX(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); |
228 boxBlurXY(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); | 235 boxBlurXY(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); |
229 } | 236 } |
| 237 temp = SkBitmap(); |
| 238 SkImage* image = SkNewImageFromBitmap(dstBitmap, NULL); |
| 239 if (NULL == image) { |
| 240 return false; |
| 241 } |
| 242 dst.reset(image); |
| 243 offset->fX = resultX; |
| 244 offset->fY = resultY; |
230 return true; | 245 return true; |
231 } | 246 } |
232 | 247 |
233 | 248 |
234 void SkBlurImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const
{ | 249 void SkBlurImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const
{ |
235 if (getInput(0)) { | 250 if (getInput(0)) { |
236 getInput(0)->computeFastBounds(src, dst); | 251 getInput(0)->computeFastBounds(src, dst); |
237 } else { | 252 } else { |
238 *dst = src; | 253 *dst = src; |
239 } | 254 } |
240 | 255 |
241 dst->outset(SkScalarMul(fSigma.width(), SkIntToScalar(3)), | 256 dst->outset(SkScalarMul(fSigma.width(), SkIntToScalar(3)), |
242 SkScalarMul(fSigma.height(), SkIntToScalar(3))); | 257 SkScalarMul(fSigma.height(), SkIntToScalar(3))); |
243 } | 258 } |
244 | 259 |
245 bool SkBlurImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, | 260 bool SkBlurImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, |
246 SkIRect* dst) const { | 261 SkIRect* dst) const { |
247 SkIRect bounds = src; | 262 SkIRect bounds = src; |
248 SkVector sigma = mapSigma(fSigma, ctm); | 263 SkVector sigma = mapSigma(fSigma, ctm); |
249 bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), | 264 bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), |
250 SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); | 265 SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); |
251 if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { | 266 if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { |
252 return false; | 267 return false; |
253 } | 268 } |
254 *dst = bounds; | 269 *dst = bounds; |
255 return true; | 270 return true; |
256 } | 271 } |
257 | 272 |
258 bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const
Context& ctx, | 273 bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkImage* src, const C
ontext& ctx, |
259 SkBitmap* result, SkIPoint* offset) const
{ | 274 SkAutoTUnref<const SkImage>& result, SkIP
oint* offset) const { |
260 #if SK_SUPPORT_GPU | 275 #if SK_SUPPORT_GPU |
261 SkBitmap input = src; | 276 SkAutoTUnref<const SkImage> input(SkRef(src)); |
262 SkIPoint srcOffset = SkIPoint::Make(0, 0); | 277 SkIPoint srcOffset = SkIPoint::Make(0, 0); |
263 if (getInput(0) && !getInput(0)->getInputResultGPU(proxy, src, ctx, &input,
&srcOffset)) { | 278 if (getInput(0) && !getInput(0)->getInputResultGPU(proxy, src, ctx, input, &
srcOffset)) { |
264 return false; | 279 return false; |
265 } | 280 } |
266 SkIRect rect; | 281 SkIRect rect; |
267 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &rect, &input)) { | 282 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &rect, input)) { |
268 return false; | 283 return false; |
269 } | 284 } |
270 GrTexture* source = input.getTexture(); | 285 GrTexture* source = input->getTexture(); |
271 SkVector sigma = mapSigma(fSigma, ctx.ctm()); | 286 SkVector sigma = mapSigma(fSigma, ctx.ctm()); |
272 offset->fX = rect.fLeft; | 287 offset->fX = rect.fLeft; |
273 offset->fY = rect.fTop; | 288 offset->fY = rect.fTop; |
274 rect.offset(-srcOffset); | 289 rect.offset(-srcOffset); |
275 SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(source->getContext(
), | 290 SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(source->getContext(
), |
276 source, | 291 source, |
277 false, | 292 false, |
278 SkRect::Make(rect), | 293 SkRect::Make(rect), |
279 true, | 294 true, |
280 sigma.x(), | 295 sigma.x(), |
281 sigma.y())); | 296 sigma.y())); |
282 if (!tex) { | 297 if (!tex) { |
283 return false; | 298 return false; |
284 } | 299 } |
285 WrapTexture(tex, rect.width(), rect.height(), result); | 300 if (!WrapTexture(tex, rect.width(), rect.height(), result)) { |
| 301 return false; |
| 302 } |
286 return true; | 303 return true; |
287 #else | 304 #else |
288 SkDEBUGFAIL("Should not call in GPU-less build"); | 305 SkDEBUGFAIL("Should not call in GPU-less build"); |
289 return false; | 306 return false; |
290 #endif | 307 #endif |
291 } | 308 } |
292 | 309 |
293 #ifndef SK_IGNORE_TO_STRING | 310 #ifndef SK_IGNORE_TO_STRING |
294 void SkBlurImageFilter::toString(SkString* str) const { | 311 void SkBlurImageFilter::toString(SkString* str) const { |
295 str->appendf("SkBlurImageFilter: ("); | 312 str->appendf("SkBlurImageFilter: ("); |
296 str->appendf("sigma: (%f, %f) input (", fSigma.fWidth, fSigma.fHeight); | 313 str->appendf("sigma: (%f, %f) input (", fSigma.fWidth, fSigma.fHeight); |
297 | 314 |
298 if (this->getInput(0)) { | 315 if (this->getInput(0)) { |
299 this->getInput(0)->toString(str); | 316 this->getInput(0)->toString(str); |
300 } | 317 } |
301 | 318 |
302 str->append("))"); | 319 str->append("))"); |
303 } | 320 } |
304 #endif | 321 #endif |
OLD | NEW |