bool SkBlurImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const SkMatrix& ctm, SkBitmap* dst, SkIPoint* offset) { SkBitmap src = this->getInputResult(proxy, source, ctm, offset); if (src.config() != SkBitmap::kARGB_8888_Config) { return false; } SkAutoLockPixels alp(src); if (!src.getPixels()) { return false; } dst->setConfig(src.config(), src.width(), src.height()); dst->allocPixels(); int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; getBox3Params(fSigma.width(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX); getBox3Params(fSigma.height(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY); if (kernelSizeX < 0 || kernelSizeY < 0) { return false; } if (kernelSizeX == 0 && kernelSizeY == 0) { src.copyTo(dst, dst->config()); return true; } SkBitmap temp; temp.setConfig(dst->config(), dst->width(), dst->height()); if (!temp.allocPixels()) { return false; } if (kernelSizeX > 0 && kernelSizeY > 0) { boxBlurX(src, &temp, kernelSizeX, lowOffsetX, highOffsetX); boxBlurY(temp, dst, kernelSizeY, lowOffsetY, highOffsetY); boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX); boxBlurY(temp, dst, kernelSizeY, highOffsetY, lowOffsetY); boxBlurX(*dst, &temp, kernelSizeX3, highOffsetX, highOffsetX); boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY); } else if (kernelSizeX > 0) { boxBlurX(src, dst, kernelSizeX, lowOffsetX, highOffsetX); boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX); boxBlurX(temp, dst, kernelSizeX3, highOffsetX, highOffsetX); } else if (kernelSizeY > 0) { boxBlurY(src, dst, kernelSizeY, lowOffsetY, highOffsetY); boxBlurY(*dst, &temp, kernelSizeY, highOffsetY, lowOffsetY); boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY); } return true; }
bool SkBlurImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const Context& ctx, SkBitmap* dst, SkIPoint* offset) const { SkBitmap src = source; SkIPoint srcOffset = SkIPoint::Make(0, 0); if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) { return false; } if (src.colorType() != kN32_SkColorType) { return false; } SkIRect srcBounds, dstBounds; if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &srcBounds, &src)) { return false; } SkAutoLockPixels alp(src); if (!src.getPixels()) { return false; } if (!dst->allocPixels(src.info().makeWH(srcBounds.width(), srcBounds.height()))) { return false; } dst->getBounds(&dstBounds); SkVector sigma = SkVector::Make(fSigma.width(), fSigma.height()); ctx.ctm().mapVectors(&sigma, 1); sigma.fX = SkMinScalar(sigma.fX, MAX_SIGMA); sigma.fY = SkMinScalar(sigma.fY, MAX_SIGMA); int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; getBox3Params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX); getBox3Params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY); if (kernelSizeX < 0 || kernelSizeY < 0) { return false; } if (kernelSizeX == 0 && kernelSizeY == 0) { src.copyTo(dst, dst->colorType()); offset->fX = srcBounds.fLeft; offset->fY = srcBounds.fTop; return true; } SkBitmap temp; if (!temp.allocPixels(dst->info())) { return false; } offset->fX = srcBounds.fLeft; offset->fY = srcBounds.fTop; srcBounds.offset(-srcOffset); const SkPMColor* s = src.getAddr32(srcBounds.left(), srcBounds.top()); SkPMColor* t = temp.getAddr32(0, 0); SkPMColor* d = dst->getAddr32(0, 0); int w = dstBounds.width(), h = dstBounds.height(); int sw = src.rowBytesAsPixels(); SkBoxBlurProc boxBlurX, boxBlurY, boxBlurXY, boxBlurYX; if (!SkBoxBlurGetPlatformProcs(&boxBlurX, &boxBlurY, &boxBlurXY, &boxBlurYX)) { boxBlurX = boxBlur<kX, kX>; boxBlurY = boxBlur<kY, kY>; boxBlurXY = boxBlur<kX, kY>; boxBlurYX = boxBlur<kY, kX>; } if (kernelSizeX > 0 && kernelSizeY > 0) { boxBlurX(s, sw, t, kernelSizeX, lowOffsetX, highOffsetX, w, h); boxBlurX(t, w, d, kernelSizeX, highOffsetX, lowOffsetX, w, h); boxBlurXY(d, w, t, kernelSizeX3, highOffsetX, highOffsetX, w, h); boxBlurX(t, h, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); boxBlurX(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); boxBlurXY(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); } else if (kernelSizeX > 0) { boxBlurX(s, sw, d, kernelSizeX, lowOffsetX, highOffsetX, w, h); boxBlurX(d, w, t, kernelSizeX, highOffsetX, lowOffsetX, w, h); boxBlurX(t, w, d, kernelSizeX3, highOffsetX, highOffsetX, w, h); } else if (kernelSizeY > 0) { boxBlurYX(s, sw, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); boxBlurX(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); boxBlurXY(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); } return true; }
bool SkBlurImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const Context& ctx, SkBitmap* dst, SkIPoint* offset) const { SkBitmap src = source; SkIPoint srcOffset = SkIPoint::Make(0, 0); if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) { return false; } if (src.colorType() != kN32_SkColorType) { return false; } SkIRect srcBounds, dstBounds; if (!this->applyCropRect(this->mapContext(ctx), src, srcOffset, &dstBounds, &srcBounds)) { return false; } if (!srcBounds.intersect(dstBounds)) { return false; } SkAutoLockPixels alp(src); if (!src.getPixels()) { return false; } SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dstBounds.height())); if (!device) { return false; } *dst = device->accessBitmap(false); SkAutoLockPixels alp_dst(*dst); SkVector sigma = mapSigma(fSigma, ctx.ctm()); int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; getBox3Params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX); getBox3Params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY); if (kernelSizeX < 0 || kernelSizeY < 0) { return false; } if (kernelSizeX == 0 && kernelSizeY == 0) { src.copyTo(dst, dst->colorType()); offset->fX = dstBounds.x() + srcOffset.x(); offset->fY = dstBounds.y() + srcOffset.y(); return true; } SkAutoTUnref<SkBaseDevice> tempDevice(proxy->createDevice(dst->width(), dst->height())); if (!tempDevice) { return false; } SkBitmap temp = tempDevice->accessBitmap(false); SkAutoLockPixels alpTemp(temp); offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; SkPMColor* t = temp.getAddr32(0, 0); SkPMColor* d = dst->getAddr32(0, 0); int w = dstBounds.width(), h = dstBounds.height(); const SkPMColor* s = src.getAddr32(srcBounds.x() - srcOffset.x(), srcBounds.y() - srcOffset.y()); srcBounds.offset(-dstBounds.x(), -dstBounds.y()); dstBounds.offset(-dstBounds.x(), -dstBounds.y()); SkIRect srcBoundsT = SkIRect::MakeLTRB(srcBounds.top(), srcBounds.left(), srcBounds.bottom(), srcBounds.right()); SkIRect dstBoundsT = SkIRect::MakeWH(dstBounds.height(), dstBounds.width()); int sw = src.rowBytesAsPixels(); /** * * In order to make memory accesses cache-friendly, we reorder the passes to * use contiguous memory reads wherever possible. * * For example, the 6 passes of the X-and-Y blur case are rewritten as * follows. Instead of 3 passes in X and 3 passes in Y, we perform * 2 passes in X, 1 pass in X transposed to Y on write, 2 passes in X, * then 1 pass in X transposed to Y on write. * * +----+ +----+ +----+ +---+ +---+ +---+ +----+ * + AB + ----> | AB | ----> | AB | -----> | A | ----> | A | ----> | A | -----> | AB | * +----+ blurX +----+ blurX +----+ blurXY | B | blurX | B | blurX | B | blurXY +----+ * +---+ +---+ +---+ * * In this way, two of the y-blurs become x-blurs applied to transposed * images, and all memory reads are contiguous. */ if (kernelSizeX > 0 && kernelSizeY > 0) { SkOpts::box_blur_xx(s, sw, srcBounds, t, kernelSizeX, lowOffsetX, highOffsetX, w, h); SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX, highOffsetX, lowOffsetX, w, h); SkOpts::box_blur_xy(d, w, dstBounds, t, kernelSizeX3, highOffsetX, highOffsetX, w, h); SkOpts::box_blur_xx(t, h, dstBoundsT, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); } else if (kernelSizeX > 0) { SkOpts::box_blur_xx(s, sw, srcBounds, d, kernelSizeX, lowOffsetX, highOffsetX, w, h); SkOpts::box_blur_xx(d, w, dstBounds, t, kernelSizeX, highOffsetX, lowOffsetX, w, h); SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX3, highOffsetX, highOffsetX, w, h); } else if (kernelSizeY > 0) { SkOpts::box_blur_yx(s, sw, srcBoundsT, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); } return true; }
bool SkBlurImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const SkMatrix& ctm, SkBitmap* dst, SkIPoint* offset) { SkBitmap src = source; if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctm, &src, offset)) { return false; } if (src.config() != SkBitmap::kARGB_8888_Config) { return false; } SkAutoLockPixels alp(src); if (!src.getPixels()) { return false; } SkIRect srcBounds, dstBounds; src.getBounds(&srcBounds); if (!this->applyCropRect(&srcBounds, ctm)) { return false; } dst->setConfig(src.config(), srcBounds.width(), srcBounds.height()); dst->getBounds(&dstBounds); dst->allocPixels(); int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; getBox3Params(fSigma.width(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX); getBox3Params(fSigma.height(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY); if (kernelSizeX < 0 || kernelSizeY < 0) { return false; } if (kernelSizeX == 0 && kernelSizeY == 0) { src.copyTo(dst, dst->config()); return true; } SkBitmap temp; temp.setConfig(dst->config(), dst->width(), dst->height()); if (!temp.allocPixels()) { return false; } if (kernelSizeX > 0 && kernelSizeY > 0) { boxBlurX(src, &temp, kernelSizeX, lowOffsetX, highOffsetX, srcBounds); boxBlurY(temp, dst, kernelSizeY, lowOffsetY, highOffsetY, dstBounds); boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX, dstBounds); boxBlurY(temp, dst, kernelSizeY, highOffsetY, lowOffsetY, dstBounds); boxBlurX(*dst, &temp, kernelSizeX3, highOffsetX, highOffsetX, dstBounds); boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY, dstBounds); } else if (kernelSizeX > 0) { boxBlurX(src, dst, kernelSizeX, lowOffsetX, highOffsetX, srcBounds); boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX, dstBounds); boxBlurX(temp, dst, kernelSizeX3, highOffsetX, highOffsetX, dstBounds); } else if (kernelSizeY > 0) { boxBlurY(src, dst, kernelSizeY, lowOffsetY, highOffsetY, srcBounds); boxBlurY(*dst, &temp, kernelSizeY, highOffsetY, lowOffsetY, dstBounds); boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY, dstBounds); } offset->fX += srcBounds.fLeft; offset->fY += srcBounds.fTop; return true; }