bool SkBlurMask::Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style style, Quality quality, SkIPoint* margin) { if (src.fFormat != SkMask::kA8_Format) { return false; } // Force high quality off for small radii (performance) if (radius < SkIntToScalar(3)) { quality = kLow_Quality; } // highQuality: use three box blur passes as a cheap way // to approximate a Gaussian blur int passCount = (kHigh_Quality == quality) ? 3 : 1; SkScalar passRadius = (kHigh_Quality == quality) ? SkScalarMul( radius, kBlurRadiusFudgeFactor): radius; int rx = SkScalarCeil(passRadius); int outerWeight = 255 - SkScalarRound((SkIntToScalar(rx) - passRadius) * 255); SkASSERT(rx >= 0); SkASSERT((unsigned)outerWeight <= 255); if (rx <= 0) { return false; } int ry = rx; // only do square blur for now int padx = passCount * rx; int pady = passCount * ry; if (margin) { margin->set(padx, pady); } dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady, src.fBounds.fRight + padx, src.fBounds.fBottom + pady); dst->fRowBytes = dst->fBounds.width(); dst->fFormat = SkMask::kA8_Format; dst->fImage = NULL; if (src.fImage) { size_t dstSize = dst->computeImageSize(); if (0 == dstSize) { return false; // too big to allocate, abort } int sw = src.fBounds.width(); int sh = src.fBounds.height(); const uint8_t* sp = src.fImage; uint8_t* dp = SkMask::AllocImage(dstSize); SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp); // build the blurry destination SkAutoTMalloc<uint8_t> tmpBuffer(dstSize); uint8_t* tp = tmpBuffer.get(); int w = sw, h = sh; if (outerWeight == 255) { int loRadius, hiRadius; get_adjusted_radii(passRadius, &loRadius, &hiRadius); if (kHigh_Quality == quality) { // Do three X blurs, with a transpose on the final one. w = boxBlur(sp, src.fRowBytes, tp, loRadius, hiRadius, w, h, false); w = boxBlur(tp, w, dp, hiRadius, loRadius, w, h, false); w = boxBlur(dp, w, tp, hiRadius, hiRadius, w, h, true); // Do three Y blurs, with a transpose on the final one. h = boxBlur(tp, h, dp, loRadius, hiRadius, h, w, false); h = boxBlur(dp, h, tp, hiRadius, loRadius, h, w, false); h = boxBlur(tp, h, dp, hiRadius, hiRadius, h, w, true); } else { w = boxBlur(sp, src.fRowBytes, tp, rx, rx, w, h, true); h = boxBlur(tp, h, dp, ry, ry, h, w, true); } } else { if (kHigh_Quality == quality) { // Do three X blurs, with a transpose on the final one. w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, false, outerWeight); w = boxBlurInterp(tp, w, dp, rx, w, h, false, outerWeight); w = boxBlurInterp(dp, w, tp, rx, w, h, true, outerWeight); // Do three Y blurs, with a transpose on the final one. h = boxBlurInterp(tp, h, dp, ry, h, w, false, outerWeight); h = boxBlurInterp(dp, h, tp, ry, h, w, false, outerWeight); h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWeight); } else { w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, true, outerWeight); h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWeight); } } dst->fImage = dp; // if need be, alloc the "real" dst (same size as src) and copy/merge // the blur into it (applying the src) if (style == kInner_Style) { // now we allocate the "real" dst, mirror the size of src size_t srcSize = src.computeImageSize(); if (0 == srcSize) { return false; // too big to allocate, abort } dst->fImage = SkMask::AllocImage(srcSize); merge_src_with_blur(dst->fImage, src.fRowBytes, sp, src.fRowBytes, dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes, sw, sh); SkMask::FreeImage(dp); } else if (style != kNormal_Style) { clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes, sp, src.fRowBytes, sw, sh, style); } (void)autoCall.detach(); } if (style == kInner_Style) { dst->fBounds = src.fBounds; // restore trimmed bounds dst->fRowBytes = src.fRowBytes; } return true; }
bool MCGBlurBox(const SkMask& p_src, SkScalar p_x_radius, SkScalar p_y_radius, SkScalar p_x_spread, SkScalar p_y_spread, SkMask& r_dst) { int t_pass_count; t_pass_count = 3; // Maximum amount of spread is 254 pixels. int x_spread, y_spread; x_spread = SkMin32(SkScalarFloor(p_x_radius * p_x_spread), 254); y_spread = SkMin32(SkScalarFloor(p_y_radius * p_y_spread), 254); p_x_radius -= x_spread; p_y_radius -= y_spread; int rx, ry; rx = SkScalarCeil(p_x_radius); ry = SkScalarCeil(p_y_radius); SkScalar px, py; px = rx; py = ry; int wx, wy; wx = 255 - SkScalarRound((SkIntToScalar(rx) - px) * 255); wy = 255 - SkScalarRound((SkIntToScalar(ry) - py) * 255); int t_pad_x, t_pad_y; t_pad_x = rx + x_spread; t_pad_y = ry + y_spread; r_dst . fBounds . set(p_src . fBounds . fLeft - t_pad_x, p_src . fBounds . fTop - t_pad_y, p_src . fBounds . fRight + t_pad_x, p_src . fBounds . fBottom + t_pad_y); r_dst . fRowBytes = r_dst . fBounds . width(); r_dst . fFormat = SkMask::kA8_Format; r_dst . fImage = NULL; if (p_src . fImage == NULL) return true; size_t t_dst_size; t_dst_size = r_dst . computeImageSize(); if (t_dst_size == 0) return false; int sw, sh; sw = p_src . fBounds . width(); sh = p_src . fBounds . height(); const uint8_t *sp; sp = p_src . fImage; uint8_t *dp; dp = SkMask::AllocImage(t_dst_size); if (dp == nil) return false; uint8_t *tp; tp = SkMask::AllocImage(t_dst_size); if (tp == nil) { SkMask::FreeImage(dp); return false; } int w, h; w = sw; h = sh; if (wx == 255) { if (t_pass_count == 3) { int r; r = rx; bool t_has_spread; t_has_spread = false; if (x_spread != 0 || y_spread != 0) { //w = dilateMask(sp, p_src . fRowBytes, tp, x_spread, w, h, true); //h = dilateMask(tp, h, dp, y_spread, h, w, true); dilateDistanceXY(sp, dp, x_spread, y_spread, w, h, w, h); t_has_spread = true; } int trx; trx = (r + 2) / 3; r -= trx; int rx_lo, rx_hi; rx_lo = rx_hi = trx; w = boxBlur(t_has_spread ? dp : sp, t_has_spread ? w : p_src . fRowBytes, tp, rx_lo, rx_hi, w, h, false); trx = (r + 1) / 2; r -= trx; rx_lo = rx_hi = trx; w = boxBlur(tp, w, dp, rx_hi, rx_lo, w, h, false); trx = r; rx_lo = rx_hi = trx; w = boxBlur(dp, w, tp, rx_hi, rx_hi, w, h, true); } else w = boxBlur(sp, p_src . fRowBytes, tp, rx, rx, w, h, true); } else { if (t_pass_count == 3) { int r; r = rx; bool t_has_spread; t_has_spread = false; if (x_spread != 0 || y_spread != 0) { //w = dilateMask(sp, p_src . fRowBytes, tp, x_spread, w, h, true); //h = dilateMask(tp, h, dp, y_spread, h, w, true); dilateDistanceXY(sp, dp, x_spread, y_spread, w, h, w, h); t_has_spread = true; } int trx; trx = (r + 2) / 3; r -= trx; w = boxBlurInterp(t_has_spread ? dp : sp, t_has_spread ? w : p_src . fRowBytes, tp, trx, w, h, false, wx); trx = (r + 1) / 2; r -= trx; w = boxBlurInterp(tp, w, dp, trx, w, h, false, wx); trx = r; w = boxBlurInterp(dp, w, tp, trx, w, h, true, wx); } else w = boxBlurInterp(sp, p_src . fRowBytes, tp, rx, w, h, true, wx); } if (wy == 255) { if (t_pass_count == 3) { int r; r = ry; int sry; sry = (r + 2) / 3; r -= sry; int ry_lo, ry_hi; ry_lo = ry_hi = sry; h = boxBlur(tp, h, dp, ry_lo, ry_hi, h, w, false); sry = (r + 1) / 2; r -= sry; ry_lo = ry_hi = sry; h = boxBlur(dp, h, tp, ry_hi, ry_lo, h, w, false); sry = r; ry_lo = ry_hi = sry; h = boxBlur(tp, h, dp, ry_hi, ry_hi, h, w, true); } else h = boxBlur(tp, h, dp, ry, ry, h, w, true); } else { if (t_pass_count == 3) { int r; r = ry; int sry; sry = (r + 2) / 3; r -= sry; h = boxBlurInterp(tp, h, dp, sry, h, w, false, wy); sry = (r + 1) / 2; r -= sry; h = boxBlurInterp(dp, h, tp, sry, h, w, false, wy); sry = r; h = boxBlurInterp(tp, h, dp, sry, h, w, true, wy); } else w = boxBlurInterp(tp, h, dp, rx, h, w, true, wy); } SkMask::FreeImage(tp); r_dst . fImage = dp; return true; }