epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2006 The Android Open Source Project |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 8 | |
| 9 | #include "SkBlurMask.h" |
Mike Reed | e602f39 | 2018-02-06 10:17:08 -0500 | [diff] [blame^] | 10 | #include "SkColorPriv.h" |
Mike Reed | 771ae96 | 2017-07-13 17:16:34 +0000 | [diff] [blame] | 11 | #include "SkMaskBlurFilter.h" |
tomhudson@google.com | 889bd8b | 2011-09-27 17:38:17 +0000 | [diff] [blame] | 12 | #include "SkMath.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 13 | #include "SkTemplates.h" |
tomhudson@google.com | 01224d5 | 2011-11-28 18:22:01 +0000 | [diff] [blame] | 14 | #include "SkEndian.h" |
| 15 | |
robertphillips@google.com | 7ce661d | 2013-08-27 16:14:03 +0000 | [diff] [blame] | 16 | |
reed@google.com | daaafa6 | 2014-04-29 15:20:16 +0000 | [diff] [blame] | 17 | // This constant approximates the scaling done in the software path's |
| 18 | // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). |
| 19 | // IMHO, it actually should be 1: we blur "less" than we should do |
| 20 | // according to the CSS and canvas specs, simply because Safari does the same. |
| 21 | // Firefox used to do the same too, until 4.0 where they fixed it. So at some |
| 22 | // point we should probably get rid of these scaling constants and rebaseline |
| 23 | // all the blur tests. |
| 24 | static const SkScalar kBLUR_SIGMA_SCALE = 0.57735f; |
robertphillips@google.com | 7ce661d | 2013-08-27 16:14:03 +0000 | [diff] [blame] | 25 | |
reed@google.com | daaafa6 | 2014-04-29 15:20:16 +0000 | [diff] [blame] | 26 | SkScalar SkBlurMask::ConvertRadiusToSigma(SkScalar radius) { |
| 27 | return radius > 0 ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f; |
| 28 | } |
| 29 | |
| 30 | SkScalar SkBlurMask::ConvertSigmaToRadius(SkScalar sigma) { |
| 31 | return sigma > 0.5f ? (sigma - 0.5f) / kBLUR_SIGMA_SCALE : 0.0f; |
robertphillips@google.com | 7ce661d | 2013-08-27 16:14:03 +0000 | [diff] [blame] | 32 | } |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 33 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 34 | |
reed@android.com | 0e3c664 | 2009-09-18 13:41:56 +0000 | [diff] [blame] | 35 | static void merge_src_with_blur(uint8_t dst[], int dstRB, |
| 36 | const uint8_t src[], int srcRB, |
| 37 | const uint8_t blur[], int blurRB, |
| 38 | int sw, int sh) { |
| 39 | dstRB -= sw; |
| 40 | srcRB -= sw; |
| 41 | blurRB -= sw; |
| 42 | while (--sh >= 0) { |
| 43 | for (int x = sw - 1; x >= 0; --x) { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 44 | *dst = SkToU8(SkAlphaMul(*blur, SkAlpha255To256(*src))); |
| 45 | dst += 1; |
| 46 | src += 1; |
| 47 | blur += 1; |
| 48 | } |
reed@android.com | 0e3c664 | 2009-09-18 13:41:56 +0000 | [diff] [blame] | 49 | dst += dstRB; |
| 50 | src += srcRB; |
| 51 | blur += blurRB; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 52 | } |
| 53 | } |
| 54 | |
| 55 | static void clamp_with_orig(uint8_t dst[], int dstRowBytes, |
reed@android.com | 0e3c664 | 2009-09-18 13:41:56 +0000 | [diff] [blame] | 56 | const uint8_t src[], int srcRowBytes, |
| 57 | int sw, int sh, |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 58 | SkBlurStyle style) { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 59 | int x; |
reed@android.com | 0e3c664 | 2009-09-18 13:41:56 +0000 | [diff] [blame] | 60 | while (--sh >= 0) { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 61 | switch (style) { |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 62 | case kSolid_SkBlurStyle: |
reed@android.com | 0e3c664 | 2009-09-18 13:41:56 +0000 | [diff] [blame] | 63 | for (x = sw - 1; x >= 0; --x) { |
| 64 | int s = *src; |
| 65 | int d = *dst; |
| 66 | *dst = SkToU8(s + d - SkMulDiv255Round(s, d)); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 67 | dst += 1; |
| 68 | src += 1; |
| 69 | } |
| 70 | break; |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 71 | case kOuter_SkBlurStyle: |
reed@android.com | 0e3c664 | 2009-09-18 13:41:56 +0000 | [diff] [blame] | 72 | for (x = sw - 1; x >= 0; --x) { |
| 73 | if (*src) { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 74 | *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src))); |
reed@android.com | 0e3c664 | 2009-09-18 13:41:56 +0000 | [diff] [blame] | 75 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 76 | dst += 1; |
| 77 | src += 1; |
| 78 | } |
| 79 | break; |
| 80 | default: |
tomhudson@google.com | 0c00f21 | 2011-12-28 14:59:50 +0000 | [diff] [blame] | 81 | SkDEBUGFAIL("Unexpected blur style here"); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 82 | break; |
| 83 | } |
| 84 | dst += dstRowBytes - sw; |
reed@android.com | 0e3c664 | 2009-09-18 13:41:56 +0000 | [diff] [blame] | 85 | src += srcRowBytes - sw; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 86 | } |
| 87 | } |
| 88 | |
reed@google.com | 03016a3 | 2011-08-12 14:59:59 +0000 | [diff] [blame] | 89 | /////////////////////////////////////////////////////////////////////////////// |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 90 | |
bsalomon@google.com | 33cdbde | 2013-01-11 20:54:44 +0000 | [diff] [blame] | 91 | // we use a local function to wrap the class static method to work around |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 92 | // a bug in gcc98 |
| 93 | void SkMask_FreeImage(uint8_t* image); |
reed@google.com | 03016a3 | 2011-08-12 14:59:59 +0000 | [diff] [blame] | 94 | void SkMask_FreeImage(uint8_t* image) { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 95 | SkMask::FreeImage(image); |
| 96 | } |
| 97 | |
commit-bot@chromium.org | 3d8bf23 | 2014-04-28 19:49:24 +0000 | [diff] [blame] | 98 | bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, |
| 99 | SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, |
| 100 | SkIPoint* margin, bool force_quality) { |
| 101 | |
reed@google.com | 03016a3 | 2011-08-12 14:59:59 +0000 | [diff] [blame] | 102 | if (src.fFormat != SkMask::kA8_Format) { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 103 | return false; |
reed@google.com | 03016a3 | 2011-08-12 14:59:59 +0000 | [diff] [blame] | 104 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 105 | |
Mike Reed | 771ae96 | 2017-07-13 17:16:34 +0000 | [diff] [blame] | 106 | SkIPoint border; |
| 107 | |
Mike Reed | 771ae96 | 2017-07-13 17:16:34 +0000 | [diff] [blame] | 108 | SkMaskBlurFilter blurFilter{sigma, sigma}; |
Mike Reed | a7ba6e7 | 2017-07-21 12:23:12 -0400 | [diff] [blame] | 109 | if (blurFilter.hasNoBlur()) { |
| 110 | return false; |
| 111 | } |
Mike Reed | 771ae96 | 2017-07-13 17:16:34 +0000 | [diff] [blame] | 112 | border = blurFilter.blur(src, dst); |
Herb Derby | 82e3145 | 2017-08-22 16:59:28 -0400 | [diff] [blame] | 113 | // If src.fImage is null, then this call is only to calculate the border. |
| 114 | if (src.fImage != nullptr && dst->fImage == nullptr) { |
| 115 | return false; |
| 116 | } |
Mike Reed | 771ae96 | 2017-07-13 17:16:34 +0000 | [diff] [blame] | 117 | |
| 118 | if (src.fImage != nullptr) { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 119 | // if need be, alloc the "real" dst (same size as src) and copy/merge |
| 120 | // the blur into it (applying the src) |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 121 | if (style == kInner_SkBlurStyle) { |
reed@android.com | 0e3c664 | 2009-09-18 13:41:56 +0000 | [diff] [blame] | 122 | // now we allocate the "real" dst, mirror the size of src |
reed@android.com | 543ed93 | 2009-04-24 12:43:40 +0000 | [diff] [blame] | 123 | size_t srcSize = src.computeImageSize(); |
| 124 | if (0 == srcSize) { |
| 125 | return false; // too big to allocate, abort |
| 126 | } |
Mike Reed | 771ae96 | 2017-07-13 17:16:34 +0000 | [diff] [blame] | 127 | auto blur = dst->fImage; |
reed@android.com | 543ed93 | 2009-04-24 12:43:40 +0000 | [diff] [blame] | 128 | dst->fImage = SkMask::AllocImage(srcSize); |
Mike Reed | 771ae96 | 2017-07-13 17:16:34 +0000 | [diff] [blame] | 129 | auto blurStart = &blur[border.x() + border.y() * dst->fRowBytes]; |
reed@android.com | 0e3c664 | 2009-09-18 13:41:56 +0000 | [diff] [blame] | 130 | merge_src_with_blur(dst->fImage, src.fRowBytes, |
Mike Reed | 771ae96 | 2017-07-13 17:16:34 +0000 | [diff] [blame] | 131 | src.fImage, src.fRowBytes, |
| 132 | blurStart, |
| 133 | dst->fRowBytes, |
| 134 | src.fBounds.width(), src.fBounds.height()); |
| 135 | SkMask::FreeImage(blur); |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 136 | } else if (style != kNormal_SkBlurStyle) { |
Mike Reed | 771ae96 | 2017-07-13 17:16:34 +0000 | [diff] [blame] | 137 | auto dstStart = &dst->fImage[border.x() + border.y() * dst->fRowBytes]; |
| 138 | clamp_with_orig(dstStart, |
| 139 | dst->fRowBytes, src.fImage, src.fRowBytes, |
| 140 | src.fBounds.width(), src.fBounds.height(), style); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 141 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 142 | } |
| 143 | |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 144 | if (style == kInner_SkBlurStyle) { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 145 | dst->fBounds = src.fBounds; // restore trimmed bounds |
reed@android.com | 0e3c664 | 2009-09-18 13:41:56 +0000 | [diff] [blame] | 146 | dst->fRowBytes = src.fRowBytes; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 147 | } |
| 148 | |
Mike Reed | 771ae96 | 2017-07-13 17:16:34 +0000 | [diff] [blame] | 149 | if (margin != nullptr) { |
| 150 | *margin = border; |
| 151 | } |
| 152 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 153 | return true; |
| 154 | } |
| 155 | |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 156 | /* Convolving a box with itself three times results in a piecewise |
| 157 | quadratic function: |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 158 | |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 159 | 0 x <= -1.5 |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 160 | 9/8 + 3/2 x + 1/2 x^2 -1.5 < x <= -.5 |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 161 | 3/4 - x^2 -.5 < x <= .5 |
| 162 | 9/8 - 3/2 x + 1/2 x^2 0.5 < x <= 1.5 |
| 163 | 0 1.5 < x |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 164 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 165 | Mathematica: |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 166 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 167 | g[x_] := Piecewise [ { |
| 168 | {9/8 + 3/2 x + 1/2 x^2 , -1.5 < x <= -.5}, |
| 169 | {3/4 - x^2 , -.5 < x <= .5}, |
| 170 | {9/8 - 3/2 x + 1/2 x^2 , 0.5 < x <= 1.5} |
| 171 | }, 0] |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 172 | |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 173 | To get the profile curve of the blurred step function at the rectangle |
| 174 | edge, we evaluate the indefinite integral, which is piecewise cubic: |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 175 | |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 176 | 0 x <= -1.5 |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 177 | 9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3 -1.5 < x <= -0.5 |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 178 | 1/2 + 3/4 x - 1/3 x^3 -.5 < x <= .5 |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 179 | 7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3 .5 < x <= 1.5 |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 180 | 1 1.5 < x |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 181 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 182 | in Mathematica code: |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 183 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 184 | gi[x_] := Piecewise[ { |
| 185 | { 0 , x <= -1.5 }, |
| 186 | { 9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3, -1.5 < x <= -0.5 }, |
| 187 | { 1/2 + 3/4 x - 1/3 x^3 , -.5 < x <= .5}, |
| 188 | { 7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3, .5 < x <= 1.5} |
| 189 | },1] |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 190 | */ |
| 191 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 192 | static float gaussianIntegral(float x) { |
| 193 | if (x > 1.5f) { |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 194 | return 0.0f; |
| 195 | } |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 196 | if (x < -1.5f) { |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 197 | return 1.0f; |
| 198 | } |
| 199 | |
| 200 | float x2 = x*x; |
| 201 | float x3 = x2*x; |
| 202 | |
jvanverth@google.com | 9c4e5ac | 2013-01-07 18:41:28 +0000 | [diff] [blame] | 203 | if ( x > 0.5f ) { |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 204 | return 0.5625f - (x3 / 6.0f - 3.0f * x2 * 0.25f + 1.125f * x); |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 205 | } |
jvanverth@google.com | 9c4e5ac | 2013-01-07 18:41:28 +0000 | [diff] [blame] | 206 | if ( x > -0.5f ) { |
| 207 | return 0.5f - (0.75f * x - x3 / 3.0f); |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 208 | } |
jvanverth@google.com | 9c4e5ac | 2013-01-07 18:41:28 +0000 | [diff] [blame] | 209 | return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x); |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 210 | } |
| 211 | |
commit-bot@chromium.org | cf34bc0 | 2014-01-30 15:34:43 +0000 | [diff] [blame] | 212 | /* ComputeBlurProfile allocates and fills in an array of floating |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 213 | point values between 0 and 255 for the profile signature of |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 214 | a blurred half-plane with the given blur radius. Since we're |
| 215 | going to be doing screened multiplications (i.e., 1 - (1-x)(1-y)) |
| 216 | all the time, we actually fill in the profile pre-inverted |
| 217 | (already done 255-x). |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 218 | |
humper@google.com | 7c5d7b7 | 2013-03-11 20:16:28 +0000 | [diff] [blame] | 219 | It's the responsibility of the caller to delete the |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 220 | memory returned in profile_out. |
| 221 | */ |
| 222 | |
robertphillips | 30c4cae | 2015-09-15 10:20:55 -0700 | [diff] [blame] | 223 | uint8_t* SkBlurMask::ComputeBlurProfile(SkScalar sigma) { |
robertphillips@google.com | 7ce661d | 2013-08-27 16:14:03 +0000 | [diff] [blame] | 224 | int size = SkScalarCeilToInt(6*sigma); |
skia.committer@gmail.com | 2e71f16 | 2013-03-12 07:12:32 +0000 | [diff] [blame] | 225 | |
robertphillips | d8982d7 | 2015-10-04 12:21:33 -0700 | [diff] [blame] | 226 | int center = size >> 1; |
halcanary | 385fe4d | 2015-08-26 13:07:48 -0700 | [diff] [blame] | 227 | uint8_t* profile = new uint8_t[size]; |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 228 | |
robertphillips@google.com | 7ce661d | 2013-08-27 16:14:03 +0000 | [diff] [blame] | 229 | float invr = 1.f/(2*sigma); |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 230 | |
| 231 | profile[0] = 255; |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 232 | for (int x = 1 ; x < size ; ++x) { |
jvanverth@google.com | d98df1a | 2013-02-20 19:02:34 +0000 | [diff] [blame] | 233 | float scaled_x = (center - x - .5f) * invr; |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 234 | float gi = gaussianIntegral(scaled_x); |
| 235 | profile[x] = 255 - (uint8_t) (255.f * gi); |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 236 | } |
| 237 | |
robertphillips | 30c4cae | 2015-09-15 10:20:55 -0700 | [diff] [blame] | 238 | return profile; |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 239 | } |
| 240 | |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 241 | // TODO MAYBE: Maintain a profile cache to avoid recomputing this for |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 242 | // commonly used radii. Consider baking some of the most common blur radii |
| 243 | // directly in as static data? |
| 244 | |
| 245 | // Implementation adapted from Michael Herf's approach: |
| 246 | // http://stereopsis.com/shadowrect/ |
| 247 | |
commit-bot@chromium.org | cf34bc0 | 2014-01-30 15:34:43 +0000 | [diff] [blame] | 248 | uint8_t SkBlurMask::ProfileLookup(const uint8_t *profile, int loc, int blurred_width, int sharp_width) { |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 249 | int dx = SkAbs32(((loc << 1) + 1) - blurred_width) - sharp_width; // how far are we from the original edge? |
| 250 | int ox = dx >> 1; |
| 251 | if (ox < 0) { |
| 252 | ox = 0; |
| 253 | } |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 254 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 255 | return profile[ox]; |
| 256 | } |
| 257 | |
skia.committer@gmail.com | 4c18e9f | 2014-01-31 03:01:59 +0000 | [diff] [blame] | 258 | void SkBlurMask::ComputeBlurredScanline(uint8_t *pixels, const uint8_t *profile, |
commit-bot@chromium.org | cf34bc0 | 2014-01-30 15:34:43 +0000 | [diff] [blame] | 259 | unsigned int width, SkScalar sigma) { |
| 260 | |
| 261 | unsigned int profile_size = SkScalarCeilToInt(6*sigma); |
| 262 | SkAutoTMalloc<uint8_t> horizontalScanline(width); |
| 263 | |
| 264 | unsigned int sw = width - profile_size; |
| 265 | // nearest odd number less than the profile size represents the center |
| 266 | // of the (2x scaled) profile |
| 267 | int center = ( profile_size & ~1 ) - 1; |
| 268 | |
| 269 | int w = sw - center; |
| 270 | |
| 271 | for (unsigned int x = 0 ; x < width ; ++x) { |
| 272 | if (profile_size <= sw) { |
| 273 | pixels[x] = ProfileLookup(profile, x, width, w); |
| 274 | } else { |
| 275 | float span = float(sw)/(2*sigma); |
| 276 | float giX = 1.5f - (x+.5f)/(2*sigma); |
| 277 | pixels[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span))); |
| 278 | } |
skia.committer@gmail.com | 4c18e9f | 2014-01-31 03:01:59 +0000 | [diff] [blame] | 279 | } |
commit-bot@chromium.org | cf34bc0 | 2014-01-30 15:34:43 +0000 | [diff] [blame] | 280 | } |
| 281 | |
skia.committer@gmail.com | 7bd141d | 2013-08-28 07:01:18 +0000 | [diff] [blame] | 282 | bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 283 | const SkRect &src, SkBlurStyle style, |
robertphillips@google.com | 7ce661d | 2013-08-27 16:14:03 +0000 | [diff] [blame] | 284 | SkIPoint *margin, SkMask::CreateMode createMode) { |
| 285 | int profile_size = SkScalarCeilToInt(6*sigma); |
skia.committer@gmail.com | 2e71f16 | 2013-03-12 07:12:32 +0000 | [diff] [blame] | 286 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 287 | int pad = profile_size/2; |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 288 | if (margin) { |
| 289 | margin->set( pad, pad ); |
| 290 | } |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 291 | |
skia.committer@gmail.com | 2e71f16 | 2013-03-12 07:12:32 +0000 | [diff] [blame] | 292 | dst->fBounds.set(SkScalarRoundToInt(src.fLeft - pad), |
| 293 | SkScalarRoundToInt(src.fTop - pad), |
| 294 | SkScalarRoundToInt(src.fRight + pad), |
humper@google.com | 68a690c | 2013-03-11 21:16:20 +0000 | [diff] [blame] | 295 | SkScalarRoundToInt(src.fBottom + pad)); |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 296 | |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 297 | dst->fRowBytes = dst->fBounds.width(); |
| 298 | dst->fFormat = SkMask::kA8_Format; |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 299 | dst->fImage = nullptr; |
skia.committer@gmail.com | 2e71f16 | 2013-03-12 07:12:32 +0000 | [diff] [blame] | 300 | |
humper@google.com | 7c5d7b7 | 2013-03-11 20:16:28 +0000 | [diff] [blame] | 301 | int sw = SkScalarFloorToInt(src.width()); |
| 302 | int sh = SkScalarFloorToInt(src.height()); |
skia.committer@gmail.com | 2e71f16 | 2013-03-12 07:12:32 +0000 | [diff] [blame] | 303 | |
humper@google.com | 7c5d7b7 | 2013-03-11 20:16:28 +0000 | [diff] [blame] | 304 | if (createMode == SkMask::kJustComputeBounds_CreateMode) { |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 305 | if (style == kInner_SkBlurStyle) { |
skia.committer@gmail.com | 2e71f16 | 2013-03-12 07:12:32 +0000 | [diff] [blame] | 306 | dst->fBounds.set(SkScalarRoundToInt(src.fLeft), |
| 307 | SkScalarRoundToInt(src.fTop), |
| 308 | SkScalarRoundToInt(src.fRight), |
humper@google.com | 68a690c | 2013-03-11 21:16:20 +0000 | [diff] [blame] | 309 | SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds |
humper@google.com | 7c5d7b7 | 2013-03-11 20:16:28 +0000 | [diff] [blame] | 310 | dst->fRowBytes = sw; |
| 311 | } |
| 312 | return true; |
| 313 | } |
skia.committer@gmail.com | 2e71f16 | 2013-03-12 07:12:32 +0000 | [diff] [blame] | 314 | |
Ben Wagner | 7ecc596 | 2016-11-02 17:07:33 -0400 | [diff] [blame] | 315 | std::unique_ptr<uint8_t[]> profile(ComputeBlurProfile(sigma)); |
skia.committer@gmail.com | 2e71f16 | 2013-03-12 07:12:32 +0000 | [diff] [blame] | 316 | |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 317 | size_t dstSize = dst->computeImageSize(); |
| 318 | if (0 == dstSize) { |
| 319 | return false; // too big to allocate, abort |
| 320 | } |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 321 | |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 322 | uint8_t* dp = SkMask::AllocImage(dstSize); |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 323 | |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 324 | dst->fImage = dp; |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 325 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 326 | int dstHeight = dst->fBounds.height(); |
| 327 | int dstWidth = dst->fBounds.width(); |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 328 | |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 329 | uint8_t *outptr = dp; |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 330 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 331 | SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); |
commit-bot@chromium.org | cf34bc0 | 2014-01-30 15:34:43 +0000 | [diff] [blame] | 332 | SkAutoTMalloc<uint8_t> verticalScanline(dstHeight); |
skia.committer@gmail.com | 4c18e9f | 2014-01-31 03:01:59 +0000 | [diff] [blame] | 333 | |
robertphillips | 30c4cae | 2015-09-15 10:20:55 -0700 | [diff] [blame] | 334 | ComputeBlurredScanline(horizontalScanline, profile.get(), dstWidth, sigma); |
| 335 | ComputeBlurredScanline(verticalScanline, profile.get(), dstHeight, sigma); |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 336 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 337 | for (int y = 0 ; y < dstHeight ; ++y) { |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 338 | for (int x = 0 ; x < dstWidth ; x++) { |
commit-bot@chromium.org | cf34bc0 | 2014-01-30 15:34:43 +0000 | [diff] [blame] | 339 | unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], verticalScanline[y]); |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 340 | *(outptr++) = maskval; |
| 341 | } |
| 342 | } |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 343 | |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 344 | if (style == kInner_SkBlurStyle) { |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 345 | // now we allocate the "real" dst, mirror the size of src |
jvanverth@google.com | d98df1a | 2013-02-20 19:02:34 +0000 | [diff] [blame] | 346 | size_t srcSize = (size_t)(src.width() * src.height()); |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 347 | if (0 == srcSize) { |
| 348 | return false; // too big to allocate, abort |
| 349 | } |
| 350 | dst->fImage = SkMask::AllocImage(srcSize); |
| 351 | for (int y = 0 ; y < sh ; y++) { |
| 352 | uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad; |
| 353 | uint8_t *inner_scanline = dst->fImage + y*sw; |
| 354 | memcpy(inner_scanline, blur_scanline, sw); |
| 355 | } |
| 356 | SkMask::FreeImage(dp); |
| 357 | |
skia.committer@gmail.com | 2e71f16 | 2013-03-12 07:12:32 +0000 | [diff] [blame] | 358 | dst->fBounds.set(SkScalarRoundToInt(src.fLeft), |
| 359 | SkScalarRoundToInt(src.fTop), |
| 360 | SkScalarRoundToInt(src.fRight), |
humper@google.com | 68a690c | 2013-03-11 21:16:20 +0000 | [diff] [blame] | 361 | SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 362 | dst->fRowBytes = sw; |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 363 | |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 364 | } else if (style == kOuter_SkBlurStyle) { |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 365 | for (int y = pad ; y < dstHeight-pad ; y++) { |
| 366 | uint8_t *dst_scanline = dp + y*dstWidth + pad; |
| 367 | memset(dst_scanline, 0, sw); |
| 368 | } |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 369 | } else if (style == kSolid_SkBlurStyle) { |
humper@google.com | d4d5730 | 2013-03-11 22:18:54 +0000 | [diff] [blame] | 370 | for (int y = pad ; y < dstHeight-pad ; y++) { |
| 371 | uint8_t *dst_scanline = dp + y*dstWidth + pad; |
| 372 | memset(dst_scanline, 0xff, sw); |
skia.committer@gmail.com | 2e71f16 | 2013-03-12 07:12:32 +0000 | [diff] [blame] | 373 | } |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 374 | } |
| 375 | // normal and solid styles are the same for analytic rect blurs, so don't |
| 376 | // need to handle solid specially. |
| 377 | |
| 378 | return true; |
| 379 | } |
| 380 | |
commit-bot@chromium.org | a477154 | 2014-03-10 21:42:06 +0000 | [diff] [blame] | 381 | bool SkBlurMask::BlurRRect(SkScalar sigma, SkMask *dst, |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 382 | const SkRRect &src, SkBlurStyle style, |
commit-bot@chromium.org | a477154 | 2014-03-10 21:42:06 +0000 | [diff] [blame] | 383 | SkIPoint *margin, SkMask::CreateMode createMode) { |
| 384 | // Temporary for now -- always fail, should cause caller to fall back |
| 385 | // to old path. Plumbing just to land API and parallelize effort. |
| 386 | |
| 387 | return false; |
robertphillips@google.com | 7ce661d | 2013-08-27 16:14:03 +0000 | [diff] [blame] | 388 | } |
commit-bot@chromium.org | a477154 | 2014-03-10 21:42:06 +0000 | [diff] [blame] | 389 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 390 | // The "simple" blur is a direct implementation of separable convolution with a discrete |
| 391 | // gaussian kernel. It's "ground truth" in a sense; too slow to be used, but very |
| 392 | // useful for correctness comparisons. |
| 393 | |
robertphillips@google.com | 7ce661d | 2013-08-27 16:14:03 +0000 | [diff] [blame] | 394 | bool SkBlurMask::BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src, |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 395 | SkBlurStyle style, SkIPoint* margin) { |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 396 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 397 | if (src.fFormat != SkMask::kA8_Format) { |
| 398 | return false; |
| 399 | } |
| 400 | |
robertphillips@google.com | 7ce661d | 2013-08-27 16:14:03 +0000 | [diff] [blame] | 401 | float variance = sigma * sigma; |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 402 | |
reed@google.com | e1ca705 | 2013-12-17 19:22:07 +0000 | [diff] [blame] | 403 | int windowSize = SkScalarCeilToInt(sigma*6); |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 404 | // round window size up to nearest odd number |
| 405 | windowSize |= 1; |
| 406 | |
| 407 | SkAutoTMalloc<float> gaussWindow(windowSize); |
| 408 | |
| 409 | int halfWindow = windowSize >> 1; |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 410 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 411 | gaussWindow[halfWindow] = 1; |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 412 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 413 | float windowSum = 1; |
| 414 | for (int x = 1 ; x <= halfWindow ; ++x) { |
robertphillips@google.com | 3dfa4cc | 2013-09-05 16:39:03 +0000 | [diff] [blame] | 415 | float gaussian = expf(-x*x / (2*variance)); |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 416 | gaussWindow[halfWindow + x] = gaussWindow[halfWindow-x] = gaussian; |
| 417 | windowSum += 2*gaussian; |
| 418 | } |
| 419 | |
| 420 | // leave the filter un-normalized for now; we will divide by the normalization |
| 421 | // sum later; |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 422 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 423 | int pad = halfWindow; |
| 424 | if (margin) { |
| 425 | margin->set( pad, pad ); |
| 426 | } |
| 427 | |
| 428 | dst->fBounds = src.fBounds; |
| 429 | dst->fBounds.outset(pad, pad); |
| 430 | |
| 431 | dst->fRowBytes = dst->fBounds.width(); |
| 432 | dst->fFormat = SkMask::kA8_Format; |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 433 | dst->fImage = nullptr; |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 434 | |
| 435 | if (src.fImage) { |
| 436 | |
| 437 | size_t dstSize = dst->computeImageSize(); |
| 438 | if (0 == dstSize) { |
| 439 | return false; // too big to allocate, abort |
| 440 | } |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 441 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 442 | int srcWidth = src.fBounds.width(); |
| 443 | int srcHeight = src.fBounds.height(); |
| 444 | int dstWidth = dst->fBounds.width(); |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 445 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 446 | const uint8_t* srcPixels = src.fImage; |
| 447 | uint8_t* dstPixels = SkMask::AllocImage(dstSize); |
| 448 | SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dstPixels); |
| 449 | |
| 450 | // do the actual blur. First, make a padded copy of the source. |
| 451 | // use double pad so we never have to check if we're outside anything |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 452 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 453 | int padWidth = srcWidth + 4*pad; |
| 454 | int padHeight = srcHeight; |
| 455 | int padSize = padWidth * padHeight; |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 456 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 457 | SkAutoTMalloc<uint8_t> padPixels(padSize); |
| 458 | memset(padPixels, 0, padSize); |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 459 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 460 | for (int y = 0 ; y < srcHeight; ++y) { |
| 461 | uint8_t* padptr = padPixels + y * padWidth + 2*pad; |
| 462 | const uint8_t* srcptr = srcPixels + y * srcWidth; |
| 463 | memcpy(padptr, srcptr, srcWidth); |
| 464 | } |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 465 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 466 | // blur in X, transposing the result into a temporary floating point buffer. |
| 467 | // also double-pad the intermediate result so that the second blur doesn't |
| 468 | // have to do extra conditionals. |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 469 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 470 | int tmpWidth = padHeight + 4*pad; |
| 471 | int tmpHeight = padWidth - 2*pad; |
| 472 | int tmpSize = tmpWidth * tmpHeight; |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 473 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 474 | SkAutoTMalloc<float> tmpImage(tmpSize); |
| 475 | memset(tmpImage, 0, tmpSize*sizeof(tmpImage[0])); |
| 476 | |
| 477 | for (int y = 0 ; y < padHeight ; ++y) { |
| 478 | uint8_t *srcScanline = padPixels + y*padWidth; |
| 479 | for (int x = pad ; x < padWidth - pad ; ++x) { |
| 480 | float *outPixel = tmpImage + (x-pad)*tmpWidth + y + 2*pad; // transposed output |
| 481 | uint8_t *windowCenter = srcScanline + x; |
| 482 | for (int i = -pad ; i <= pad ; ++i) { |
| 483 | *outPixel += gaussWindow[pad+i]*windowCenter[i]; |
| 484 | } |
| 485 | *outPixel /= windowSum; |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 486 | } |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 487 | } |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 488 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 489 | // blur in Y; now filling in the actual desired destination. We have to do |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 490 | // the transpose again; these transposes guarantee that we read memory in |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 491 | // linear order. |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 492 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 493 | for (int y = 0 ; y < tmpHeight ; ++y) { |
| 494 | float *srcScanline = tmpImage + y*tmpWidth; |
| 495 | for (int x = pad ; x < tmpWidth - pad ; ++x) { |
| 496 | float *windowCenter = srcScanline + x; |
| 497 | float finalValue = 0; |
| 498 | for (int i = -pad ; i <= pad ; ++i) { |
| 499 | finalValue += gaussWindow[pad+i]*windowCenter[i]; |
| 500 | } |
| 501 | finalValue /= windowSum; |
| 502 | uint8_t *outPixel = dstPixels + (x-pad)*dstWidth + y; // transposed output |
| 503 | int integerPixel = int(finalValue + 0.5f); |
| 504 | *outPixel = SkClampMax( SkClampPos(integerPixel), 255 ); |
| 505 | } |
| 506 | } |
skia.committer@gmail.com | d454ec1 | 2013-02-21 07:15:03 +0000 | [diff] [blame] | 507 | |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 508 | dst->fImage = dstPixels; |
| 509 | // if need be, alloc the "real" dst (same size as src) and copy/merge |
| 510 | // the blur into it (applying the src) |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 511 | if (style == kInner_SkBlurStyle) { |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 512 | // now we allocate the "real" dst, mirror the size of src |
| 513 | size_t srcSize = src.computeImageSize(); |
| 514 | if (0 == srcSize) { |
| 515 | return false; // too big to allocate, abort |
| 516 | } |
| 517 | dst->fImage = SkMask::AllocImage(srcSize); |
| 518 | merge_src_with_blur(dst->fImage, src.fRowBytes, |
| 519 | srcPixels, src.fRowBytes, |
| 520 | dstPixels + pad*dst->fRowBytes + pad, |
| 521 | dst->fRowBytes, srcWidth, srcHeight); |
| 522 | SkMask::FreeImage(dstPixels); |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 523 | } else if (style != kNormal_SkBlurStyle) { |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 524 | clamp_with_orig(dstPixels + pad*dst->fRowBytes + pad, |
| 525 | dst->fRowBytes, srcPixels, src.fRowBytes, srcWidth, srcHeight, style); |
| 526 | } |
mtklein | 18300a3 | 2016-03-16 13:53:35 -0700 | [diff] [blame] | 527 | (void)autoCall.release(); |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 528 | } |
| 529 | |
commit-bot@chromium.org | e396455 | 2014-04-28 16:25:35 +0000 | [diff] [blame] | 530 | if (style == kInner_SkBlurStyle) { |
humper@google.com | a99a92c | 2013-02-20 16:42:06 +0000 | [diff] [blame] | 531 | dst->fBounds = src.fBounds; // restore trimmed bounds |
| 532 | dst->fRowBytes = src.fRowBytes; |
| 533 | } |
skia.committer@gmail.com | 8ae714b | 2013-01-05 02:02:05 +0000 | [diff] [blame] | 534 | |
humper@google.com | 7c7292c | 2013-01-04 20:29:03 +0000 | [diff] [blame] | 535 | return true; |
| 536 | } |