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