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;
}
Esempio n. 2
0
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;
}