| OLD | NEW |
| (Empty) |
| 1 /* libs/graphics/effects/SkBlurMask.cpp | |
| 2 ** | |
| 3 ** Copyright 2006, The Android Open Source Project | |
| 4 ** | |
| 5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
| 6 ** you may not use this file except in compliance with the License. | |
| 7 ** You may obtain a copy of the License at | |
| 8 ** | |
| 9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 ** | |
| 11 ** Unless required by applicable law or agreed to in writing, software | |
| 12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 ** See the License for the specific language governing permissions and | |
| 15 ** limitations under the License. | |
| 16 */ | |
| 17 | |
| 18 #include "SkBlurMask.h" | |
| 19 #include "SkTemplates.h" | |
| 20 | |
| 21 static void build_sum_buffer(uint32_t dst[], int w, int h, const uint8_t src[],
int srcRB) | |
| 22 { | |
| 23 SkASSERT(srcRB >= w); | |
| 24 // mod srcRB so we can apply it after each row | |
| 25 srcRB -= w; | |
| 26 | |
| 27 int x, y; | |
| 28 | |
| 29 // special case first row | |
| 30 uint32_t X = 0; | |
| 31 for (x = w - 1; x >= 0; --x) | |
| 32 { | |
| 33 X = *src++ + X; | |
| 34 *dst++ = X; | |
| 35 } | |
| 36 src += srcRB; | |
| 37 | |
| 38 // now do the rest of the rows | |
| 39 for (y = h - 1; y > 0; --y) | |
| 40 { | |
| 41 uint32_t L = 0; | |
| 42 uint32_t C = 0; | |
| 43 for (x = w - 1; x >= 0; --x) | |
| 44 { | |
| 45 uint32_t T = dst[-w]; | |
| 46 X = *src++ + L + T - C; | |
| 47 *dst++ = X; | |
| 48 L = X; | |
| 49 C = T; | |
| 50 } | |
| 51 src += srcRB; | |
| 52 } | |
| 53 } | |
| 54 | |
| 55 static void apply_kernel(uint8_t dst[], int rx, int ry, const uint32_t src[], in
t sw, int sh) | |
| 56 { | |
| 57 uint32_t scale = (1 << 24) / ((2*rx + 1)*(2*ry + 1)); | |
| 58 | |
| 59 int rowBytes = sw; | |
| 60 | |
| 61 int dw = sw + 2*rx; | |
| 62 int dh = sh + 2*ry; | |
| 63 | |
| 64 sw -= 1; // now it is max_x | |
| 65 sh -= 1; // now it is max_y | |
| 66 | |
| 67 int prev_y = -ry - 1 -ry; | |
| 68 int next_y = ry -ry; | |
| 69 | |
| 70 for (int y = 0; y < dh; y++) | |
| 71 { | |
| 72 int py = SkClampPos(prev_y) * rowBytes; | |
| 73 int ny = SkFastMin32(next_y, sh) * rowBytes; | |
| 74 | |
| 75 int prev_x = -rx - 1 -rx; | |
| 76 int next_x = rx -rx; | |
| 77 | |
| 78 for (int x = 0; x < dw; x++) | |
| 79 { | |
| 80 int px = SkClampPos(prev_x); | |
| 81 int nx = SkFastMin32(next_x, sw); | |
| 82 | |
| 83 uint32_t sum = src[px+py] + src[nx+ny] - src[nx+py] - src[px+ny]; | |
| 84 *dst++ = SkToU8(sum * scale >> 24); | |
| 85 | |
| 86 prev_x += 1; | |
| 87 next_x += 1; | |
| 88 } | |
| 89 prev_y += 1; | |
| 90 next_y += 1; | |
| 91 } | |
| 92 } | |
| 93 | |
| 94 static void apply_kernel_interp(uint8_t dst[], int rx, int ry, const uint32_t sr
c[], int sw, int sh, U8CPU outer_weight) | |
| 95 { | |
| 96 SkASSERT(rx > 0 && ry > 0); | |
| 97 SkASSERT(outer_weight <= 255); | |
| 98 | |
| 99 int inner_weight = 255 - outer_weight; | |
| 100 | |
| 101 // round these guys up if they're bigger than 127 | |
| 102 outer_weight += outer_weight >> 7; | |
| 103 inner_weight += inner_weight >> 7; | |
| 104 | |
| 105 uint32_t outer_scale = (outer_weight << 16) / ((2*rx + 1)*(2*ry + 1)); | |
| 106 uint32_t inner_scale = (inner_weight << 16) / ((2*rx - 1)*(2*ry - 1)); | |
| 107 | |
| 108 int rowBytes = sw; | |
| 109 | |
| 110 int dw = sw + 2*rx; | |
| 111 int dh = sh + 2*ry; | |
| 112 | |
| 113 sw -= 1; // now it is max_x | |
| 114 sh -= 1; // now it is max_y | |
| 115 | |
| 116 int prev_y = -ry - 1 -ry; | |
| 117 int next_y = ry -ry; | |
| 118 | |
| 119 for (int y = 0; y < dh; y++) | |
| 120 { | |
| 121 int py = SkClampPos(prev_y) * rowBytes; | |
| 122 int ny = SkFastMin32(next_y, sh) * rowBytes; | |
| 123 | |
| 124 int ipy = SkClampPos(prev_y + 1) * rowBytes; | |
| 125 int iny = SkClampMax(next_y - 1, sh) * rowBytes; | |
| 126 | |
| 127 int prev_x = -rx - 1 -rx; | |
| 128 int next_x = rx -rx; | |
| 129 | |
| 130 for (int x = 0; x < dw; x++) | |
| 131 { | |
| 132 int px = SkClampPos(prev_x); | |
| 133 int nx = SkFastMin32(next_x, sw); | |
| 134 | |
| 135 int ipx = SkClampPos(prev_x + 1); | |
| 136 int inx = SkClampMax(next_x - 1, sw); | |
| 137 | |
| 138 uint32_t outer_sum = src[px+py] + src[nx+ny] - src[nx+py] - src[px+n
y]; | |
| 139 uint32_t inner_sum = src[ipx+ipy] + src[inx+iny] - src[inx+ipy] - sr
c[ipx+iny]; | |
| 140 *dst++ = SkToU8((outer_sum * outer_scale + inner_sum * inner_scale)
>> 24); | |
| 141 | |
| 142 prev_x += 1; | |
| 143 next_x += 1; | |
| 144 } | |
| 145 prev_y += 1; | |
| 146 next_y += 1; | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 #include "SkColorPriv.h" | |
| 151 | |
| 152 static void merge_src_with_blur(uint8_t dst[], | |
| 153 const uint8_t src[], int sw, int sh, | |
| 154 const uint8_t blur[], int blurRowBytes) | |
| 155 { | |
| 156 while (--sh >= 0) | |
| 157 { | |
| 158 for (int x = sw - 1; x >= 0; --x) | |
| 159 { | |
| 160 *dst = SkToU8(SkAlphaMul(*blur, SkAlpha255To256(*src))); | |
| 161 dst += 1; | |
| 162 src += 1; | |
| 163 blur += 1; | |
| 164 } | |
| 165 blur += blurRowBytes - sw; | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 static void clamp_with_orig(uint8_t dst[], int dstRowBytes, | |
| 170 const uint8_t src[], int sw, int sh, | |
| 171 SkBlurMask::Style style) | |
| 172 { | |
| 173 int x; | |
| 174 while (--sh >= 0) | |
| 175 { | |
| 176 switch (style) { | |
| 177 case SkBlurMask::kSolid_Style: | |
| 178 for (x = sw - 1; x >= 0; --x) | |
| 179 { | |
| 180 *dst = SkToU8(*src + SkAlphaMul(*dst, SkAlpha255To256(255 - *src
))); | |
| 181 dst += 1; | |
| 182 src += 1; | |
| 183 } | |
| 184 break; | |
| 185 case SkBlurMask::kOuter_Style: | |
| 186 for (x = sw - 1; x >= 0; --x) | |
| 187 { | |
| 188 if (*src) | |
| 189 *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src)))
; | |
| 190 dst += 1; | |
| 191 src += 1; | |
| 192 } | |
| 193 break; | |
| 194 default: | |
| 195 SkASSERT(!"Unexpected blur style here"); | |
| 196 break; | |
| 197 } | |
| 198 dst += dstRowBytes - sw; | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 //////////////////////////////////////////////////////////////////////// | |
| 203 | |
| 204 // we use a local funciton to wrap the class static method to work around | |
| 205 // a bug in gcc98 | |
| 206 void SkMask_FreeImage(uint8_t* image); | |
| 207 void SkMask_FreeImage(uint8_t* image) | |
| 208 { | |
| 209 SkMask::FreeImage(image); | |
| 210 } | |
| 211 | |
| 212 bool SkBlurMask::Blur(SkMask* dst, const SkMask& src, | |
| 213 SkScalar radius, Style style) | |
| 214 { | |
| 215 if (src.fFormat != SkMask::kA8_Format) | |
| 216 return false; | |
| 217 | |
| 218 int rx = SkScalarCeil(radius); | |
| 219 int outer_weight = 255 - SkScalarRound((SkIntToScalar(rx) - radius) * 255); | |
| 220 | |
| 221 SkASSERT(rx >= 0); | |
| 222 SkASSERT((unsigned)outer_weight <= 255); | |
| 223 | |
| 224 if (rx == 0) | |
| 225 return false; | |
| 226 | |
| 227 int ry = rx; // only do square blur for now | |
| 228 | |
| 229 dst->fBounds.set(src.fBounds.fLeft - rx, src.fBounds.fTop - ry, | |
| 230 src.fBounds.fRight + rx, src.fBounds.fBottom + ry); | |
| 231 dst->fRowBytes = SkToU16(dst->fBounds.width()); | |
| 232 dst->fFormat = SkMask::kA8_Format; | |
| 233 dst->fImage = NULL; | |
| 234 | |
| 235 if (src.fImage) | |
| 236 { | |
| 237 size_t dstSize = dst->computeImageSize(); | |
| 238 if (0 == dstSize) { | |
| 239 return false; // too big to allocate, abort | |
| 240 } | |
| 241 | |
| 242 int sw = src.fBounds.width(); | |
| 243 int sh = src.fBounds.height(); | |
| 244 const uint8_t* sp = src.fImage; | |
| 245 uint8_t* dp = SkMask::AllocImage(dstSize); | |
| 246 | |
| 247 SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp); | |
| 248 | |
| 249 // build the blurry destination | |
| 250 { | |
| 251 SkAutoTMalloc<uint32_t> storage(sw * sh); | |
| 252 uint32_t* sumBuffer = storage.get(); | |
| 253 | |
| 254 build_sum_buffer(sumBuffer, sw, sh, sp, src.fRowBytes); | |
| 255 if (outer_weight == 255) | |
| 256 apply_kernel(dp, rx, ry, sumBuffer, sw, sh); | |
| 257 else | |
| 258 apply_kernel_interp(dp, rx, ry, sumBuffer, sw, sh, outer_weight)
; | |
| 259 } | |
| 260 | |
| 261 dst->fImage = dp; | |
| 262 // if need be, alloc the "real" dst (same size as src) and copy/merge | |
| 263 // the blur into it (applying the src) | |
| 264 if (style == kInner_Style) | |
| 265 { | |
| 266 size_t srcSize = src.computeImageSize(); | |
| 267 if (0 == srcSize) { | |
| 268 return false; // too big to allocate, abort | |
| 269 } | |
| 270 dst->fImage = SkMask::AllocImage(srcSize); | |
| 271 merge_src_with_blur(dst->fImage, sp, sw, sh, | |
| 272 dp + rx + ry*dst->fBounds.width(), | |
| 273 dst->fBounds.width()); | |
| 274 SkMask::FreeImage(dp); | |
| 275 } | |
| 276 else if (style != kNormal_Style) | |
| 277 { | |
| 278 clamp_with_orig(dp + rx + ry*dst->fBounds.width(), | |
| 279 dst->fBounds.width(), | |
| 280 sp, sw, sh, | |
| 281 style); | |
| 282 } | |
| 283 (void)autoCall.detach(); | |
| 284 } | |
| 285 | |
| 286 if (style == kInner_Style) | |
| 287 { | |
| 288 dst->fBounds = src.fBounds; // restore trimmed bounds | |
| 289 dst->fRowBytes = SkToU16(dst->fBounds.width()); | |
| 290 } | |
| 291 | |
| 292 #if 0 | |
| 293 if (gamma && dst->fImage) | |
| 294 { | |
| 295 uint8_t* image = dst->fImage; | |
| 296 uint8_t* stop = image + dst->computeImageSize(); | |
| 297 | |
| 298 for (; image < stop; image += 1) | |
| 299 *image = gamma[*image]; | |
| 300 } | |
| 301 #endif | |
| 302 return true; | |
| 303 } | |
| 304 | |
| 305 #if 0 | |
| 306 void SkBlurMask::BuildSqrtGamma(uint8_t gamma[256], SkScalar percent) | |
| 307 { | |
| 308 SkASSERT(gamma); | |
| 309 SkASSERT(percent >= 0 && percent <= SK_Scalar1); | |
| 310 | |
| 311 int scale = SkScalarRound(percent * 256); | |
| 312 | |
| 313 for (int i = 0; i < 256; i++) | |
| 314 { | |
| 315 SkFixed n = i * 257; | |
| 316 n += n >> 15; | |
| 317 SkASSERT(n >= 0 && n <= SK_Fixed1); | |
| 318 n = SkFixedSqrt(n); | |
| 319 n = n * 255 >> 16; | |
| 320 n = SkAlphaBlend(n, i, scale); | |
| 321 gamma[i] = SkToU8(n); | |
| 322 } | |
| 323 } | |
| 324 | |
| 325 void SkBlurMask::BuildSqrGamma(uint8_t gamma[256], SkScalar percent) | |
| 326 { | |
| 327 SkASSERT(gamma); | |
| 328 SkASSERT(percent >= 0 && percent <= SK_Scalar1); | |
| 329 | |
| 330 int scale = SkScalarRound(percent * 256); | |
| 331 SkFixed div255 = SK_Fixed1 / 255; | |
| 332 | |
| 333 for (int i = 0; i < 256; i++) | |
| 334 { | |
| 335 int square = i * i; | |
| 336 int linear = i * 255; | |
| 337 int n = SkAlphaBlend(square, linear, scale); | |
| 338 gamma[i] = SkToU8(n * div255 >> 16); | |
| 339 } | |
| 340 } | |
| 341 #endif | |
| OLD | NEW |