blob: 6e9261a9682cba250ab0ad85f08ecab00ce79ccb [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkBlurMask.h"
tomhudson@google.com889bd8b2011-09-27 17:38:17 +000011#include "SkMath.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkTemplates.h"
13
reed@android.com45607672009-09-21 00:27:08 +000014/** The sum buffer is an array of u32 to hold the accumulated sum of all of the
15 src values at their position, plus all values above and to the left.
16 When we sample into this buffer, we need an initial row and column of 0s,
17 so we have an index correspondence as follows:
18
19 src[i, j] == sum[i+1, j+1]
20 sum[0, j] == sum[i, 0] == 0
21
22 We assume that the sum buffer's stride == its width
23 */
reed@google.com03016a32011-08-12 14:59:59 +000024static void build_sum_buffer(uint32_t sum[], int srcW, int srcH,
25 const uint8_t src[], int srcRB) {
reed@android.com45607672009-09-21 00:27:08 +000026 int sumW = srcW + 1;
27
28 SkASSERT(srcRB >= srcW);
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 // mod srcRB so we can apply it after each row
reed@android.com45607672009-09-21 00:27:08 +000030 srcRB -= srcW;
reed@android.com8a1c16f2008-12-17 15:59:43 +000031
32 int x, y;
33
reed@android.com45607672009-09-21 00:27:08 +000034 // zero out the top row and column
35 memset(sum, 0, sumW * sizeof(sum[0]));
36 sum += sumW;
37
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 // special case first row
39 uint32_t X = 0;
reed@android.com45607672009-09-21 00:27:08 +000040 *sum++ = 0; // initialze the first column to 0
reed@google.com03016a32011-08-12 14:59:59 +000041 for (x = srcW - 1; x >= 0; --x) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000042 X = *src++ + X;
reed@android.com45607672009-09-21 00:27:08 +000043 *sum++ = X;
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 }
45 src += srcRB;
46
47 // now do the rest of the rows
reed@google.com03016a32011-08-12 14:59:59 +000048 for (y = srcH - 1; y > 0; --y) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000049 uint32_t L = 0;
50 uint32_t C = 0;
reed@android.com45607672009-09-21 00:27:08 +000051 *sum++ = 0; // initialze the first column to 0
reed@google.com03016a32011-08-12 14:59:59 +000052 for (x = srcW - 1; x >= 0; --x) {
reed@android.com45607672009-09-21 00:27:08 +000053 uint32_t T = sum[-sumW];
reed@android.com8a1c16f2008-12-17 15:59:43 +000054 X = *src++ + L + T - C;
reed@android.com45607672009-09-21 00:27:08 +000055 *sum++ = X;
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 L = X;
57 C = T;
58 }
59 src += srcRB;
60 }
61}
62
reed@google.com03016a32011-08-12 14:59:59 +000063/**
tomhudson@google.com8caac642011-11-22 15:58:06 +000064 * This is the path for apply_kernel() to be taken when the kernel
65 * is wider than the source image.
reed@android.com45607672009-09-21 00:27:08 +000066 */
tomhudson@google.com8caac642011-11-22 15:58:06 +000067static void kernel_clamped(uint8_t dst[], int rx, int ry, const uint32_t sum[],
68 int sw, int sh) {
69 SkASSERT(2*rx > sw);
70
reed@android.com8a1c16f2008-12-17 15:59:43 +000071 uint32_t scale = (1 << 24) / ((2*rx + 1)*(2*ry + 1));
72
reed@android.com45607672009-09-21 00:27:08 +000073 int sumStride = sw + 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +000074
75 int dw = sw + 2*rx;
76 int dh = sh + 2*ry;
77
reed@android.com45607672009-09-21 00:27:08 +000078 int prev_y = -2*ry;
79 int next_y = 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +000080
reed@android.com45607672009-09-21 00:27:08 +000081 for (int y = 0; y < dh; y++) {
82 int py = SkClampPos(prev_y) * sumStride;
83 int ny = SkFastMin32(next_y, sh) * sumStride;
reed@android.com8a1c16f2008-12-17 15:59:43 +000084
reed@android.com45607672009-09-21 00:27:08 +000085 int prev_x = -2*rx;
86 int next_x = 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +000087
reed@android.com45607672009-09-21 00:27:08 +000088 for (int x = 0; x < dw; x++) {
tomhudson@google.com8caac642011-11-22 15:58:06 +000089 //int px = SkClampPos(prev_x);
90 //int nx = SkFastMin32(next_x, sw);
reed@android.com8a1c16f2008-12-17 15:59:43 +000091 int px = SkClampPos(prev_x);
92 int nx = SkFastMin32(next_x, sw);
93
reed@android.com45607672009-09-21 00:27:08 +000094 uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
95 *dst++ = SkToU8(tmp * scale >> 24);
reed@android.com8a1c16f2008-12-17 15:59:43 +000096
97 prev_x += 1;
98 next_x += 1;
99 }
tomhudson@google.com8caac642011-11-22 15:58:06 +0000100
101 prev_y += 1;
102 next_y += 1;
103 }
104}
105/**
106 * sw and sh are the width and height of the src. Since the sum buffer
107 * matches that, but has an extra row and col at the beginning (with zeros),
108 * we can just use sw and sh as our "max" values for pinning coordinates
109 * when sampling into sum[][]
110 *
111 * The inner loop is conceptually simple; we break it into several sections
112 * to improve performance. Here's the original version:
113 for (int x = 0; x < dw; x++) {
114 int px = SkClampPos(prev_x);
115 int nx = SkFastMin32(next_x, sw);
116
117 uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
118 *dst++ = SkToU8(tmp * scale >> 24);
119
120 prev_x += 1;
121 next_x += 1;
122 }
123*/
124static void apply_kernel(uint8_t dst[], int rx, int ry, const uint32_t sum[],
125 int sw, int sh) {
126 if (2*rx > sw) {
127 kernel_clamped(dst, rx, ry, sum, sw, sh);
128 return;
129 }
130
131 uint32_t scale = (1 << 24) / ((2*rx + 1)*(2*ry + 1));
132
133 int sumStride = sw + 1;
134
135 int dw = sw + 2*rx;
136 int dh = sh + 2*ry;
137
138 int prev_y = -2*ry;
139 int next_y = 1;
140
141 SkASSERT(2*rx <= dw - 2*rx);
142
143 for (int y = 0; y < dh; y++) {
144 int py = SkClampPos(prev_y) * sumStride;
145 int ny = SkFastMin32(next_y, sh) * sumStride;
146
147 int prev_x = -2*rx;
148 int next_x = 1;
149 int x = 0;
150
151 for (; x < 2*rx; x++) {
152 SkASSERT(prev_x <= 0);
153 SkASSERT(next_x <= sw);
154
155 int px = 0;
156 int nx = next_x;
157
158 uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
159 *dst++ = SkToU8(tmp * scale >> 24);
160
161 prev_x += 1;
162 next_x += 1;
163 }
164
165 for (; x < dw - 2*rx; x++) {
166 SkASSERT(prev_x >= 0);
167 SkASSERT(next_x <= sw);
168
169 int px = prev_x;
170 int nx = next_x;
171
172 uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
173 *dst++ = SkToU8(tmp * scale >> 24);
174
175 prev_x += 1;
176 next_x += 1;
177 }
178
179 for (; x < dw; x++) {
180 SkASSERT(prev_x >= 0);
181 SkASSERT(next_x > sw);
182
183 int px = prev_x;
184 int nx = sw;
185
186 uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
187 *dst++ = SkToU8(tmp * scale >> 24);
188
189 prev_x += 1;
190 next_x += 1;
191 }
192
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193 prev_y += 1;
194 next_y += 1;
195 }
196}
197
reed@google.com03016a32011-08-12 14:59:59 +0000198/**
tomhudson@google.com8caac642011-11-22 15:58:06 +0000199 * This is the path for apply_kernel_interp() to be taken when the kernel
200 * is wider than the source image.
reed@android.com45607672009-09-21 00:27:08 +0000201 */
tomhudson@google.com8caac642011-11-22 15:58:06 +0000202static void kernel_interp_clamped(uint8_t dst[], int rx, int ry,
reed@android.com45607672009-09-21 00:27:08 +0000203 const uint32_t sum[], int sw, int sh, U8CPU outer_weight) {
tomhudson@google.com8caac642011-11-22 15:58:06 +0000204 SkASSERT(2*rx > sw);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
206 int inner_weight = 255 - outer_weight;
207
208 // round these guys up if they're bigger than 127
209 outer_weight += outer_weight >> 7;
210 inner_weight += inner_weight >> 7;
211
212 uint32_t outer_scale = (outer_weight << 16) / ((2*rx + 1)*(2*ry + 1));
213 uint32_t inner_scale = (inner_weight << 16) / ((2*rx - 1)*(2*ry - 1));
214
reed@android.com45607672009-09-21 00:27:08 +0000215 int sumStride = sw + 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216
217 int dw = sw + 2*rx;
218 int dh = sh + 2*ry;
219
reed@android.com45607672009-09-21 00:27:08 +0000220 int prev_y = -2*ry;
221 int next_y = 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222
reed@android.com45607672009-09-21 00:27:08 +0000223 for (int y = 0; y < dh; y++) {
224 int py = SkClampPos(prev_y) * sumStride;
225 int ny = SkFastMin32(next_y, sh) * sumStride;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226
reed@android.com45607672009-09-21 00:27:08 +0000227 int ipy = SkClampPos(prev_y + 1) * sumStride;
228 int iny = SkClampMax(next_y - 1, sh) * sumStride;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229
reed@android.com45607672009-09-21 00:27:08 +0000230 int prev_x = -2*rx;
231 int next_x = 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232
reed@android.com45607672009-09-21 00:27:08 +0000233 for (int x = 0; x < dw; x++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 int px = SkClampPos(prev_x);
235 int nx = SkFastMin32(next_x, sw);
236
237 int ipx = SkClampPos(prev_x + 1);
238 int inx = SkClampMax(next_x - 1, sw);
239
tomhudson@google.com8caac642011-11-22 15:58:06 +0000240 uint32_t outer_sum = sum[px+py] + sum[nx+ny]
241 - sum[nx+py] - sum[px+ny];
242 uint32_t inner_sum = sum[ipx+ipy] + sum[inx+iny]
243 - sum[inx+ipy] - sum[ipx+iny];
244 *dst++ = SkToU8((outer_sum * outer_scale
245 + inner_sum * inner_scale) >> 24);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246
247 prev_x += 1;
248 next_x += 1;
249 }
250 prev_y += 1;
251 next_y += 1;
252 }
253}
254
tomhudson@google.com8caac642011-11-22 15:58:06 +0000255/**
256 * sw and sh are the width and height of the src. Since the sum buffer
257 * matches that, but has an extra row and col at the beginning (with zeros),
258 * we can just use sw and sh as our "max" values for pinning coordinates
259 * when sampling into sum[][]
260 *
261 * The inner loop is conceptually simple; we break it into several variants
262 * to improve performance. Here's the original version:
263 for (int x = 0; x < dw; x++) {
264 int px = SkClampPos(prev_x);
265 int nx = SkFastMin32(next_x, sw);
266
267 int ipx = SkClampPos(prev_x + 1);
268 int inx = SkClampMax(next_x - 1, sw);
269
270 uint32_t outer_sum = sum[px+py] + sum[nx+ny]
271 - sum[nx+py] - sum[px+ny];
272 uint32_t inner_sum = sum[ipx+ipy] + sum[inx+iny]
273 - sum[inx+ipy] - sum[ipx+iny];
274 *dst++ = SkToU8((outer_sum * outer_scale
275 + inner_sum * inner_scale) >> 24);
276
277 prev_x += 1;
278 next_x += 1;
279 }
280*/
281static void apply_kernel_interp(uint8_t dst[], int rx, int ry,
282 const uint32_t sum[], int sw, int sh, U8CPU outer_weight) {
283 SkASSERT(rx > 0 && ry > 0);
284 SkASSERT(outer_weight <= 255);
285
286 if (2*rx > sw) {
287 kernel_interp_clamped(dst, rx, ry, sum, sw, sh, outer_weight);
288 return;
289 }
290
291 int inner_weight = 255 - outer_weight;
292
293 // round these guys up if they're bigger than 127
294 outer_weight += outer_weight >> 7;
295 inner_weight += inner_weight >> 7;
296
297 uint32_t outer_scale = (outer_weight << 16) / ((2*rx + 1)*(2*ry + 1));
298 uint32_t inner_scale = (inner_weight << 16) / ((2*rx - 1)*(2*ry - 1));
299
300 int sumStride = sw + 1;
301
302 int dw = sw + 2*rx;
303 int dh = sh + 2*ry;
304
305 int prev_y = -2*ry;
306 int next_y = 1;
307
308 SkASSERT(2*rx <= dw - 2*rx);
309
310 for (int y = 0; y < dh; y++) {
311 int py = SkClampPos(prev_y) * sumStride;
312 int ny = SkFastMin32(next_y, sh) * sumStride;
313
314 int ipy = SkClampPos(prev_y + 1) * sumStride;
315 int iny = SkClampMax(next_y - 1, sh) * sumStride;
316
317 int prev_x = -2*rx;
318 int next_x = 1;
319 int x = 0;
320
321 for (; x < 2*rx; x++) {
322 SkASSERT(prev_x < 0);
323 SkASSERT(next_x <= sw);
324
325 int px = 0;
326 int nx = next_x;
327
328 int ipx = 0;
329 int inx = next_x - 1;
330
331 uint32_t outer_sum = sum[px+py] + sum[nx+ny]
332 - sum[nx+py] - sum[px+ny];
333 uint32_t inner_sum = sum[ipx+ipy] + sum[inx+iny]
334 - sum[inx+ipy] - sum[ipx+iny];
335 *dst++ = SkToU8((outer_sum * outer_scale
336 + inner_sum * inner_scale) >> 24);
337
338 prev_x += 1;
339 next_x += 1;
340 }
341
342 for (; x < dw - 2*rx; x++) {
343 SkASSERT(prev_x >= 0);
344 SkASSERT(next_x <= sw);
345
346 int px = prev_x;
347 int nx = next_x;
348
349 int ipx = prev_x + 1;
350 int inx = next_x - 1;
351
352 uint32_t outer_sum = sum[px+py] + sum[nx+ny]
353 - sum[nx+py] - sum[px+ny];
354 uint32_t inner_sum = sum[ipx+ipy] + sum[inx+iny]
355 - sum[inx+ipy] - sum[ipx+iny];
356 *dst++ = SkToU8((outer_sum * outer_scale
357 + inner_sum * inner_scale) >> 24);
358
359 prev_x += 1;
360 next_x += 1;
361 }
362
363 for (; x < dw; x++) {
364 SkASSERT(prev_x >= 0);
365 SkASSERT(next_x > sw);
366
367 int px = prev_x;
368 int nx = sw;
369
370 int ipx = prev_x + 1;
371 int inx = sw;
372
373 uint32_t outer_sum = sum[px+py] + sum[nx+ny]
374 - sum[nx+py] - sum[px+ny];
375 uint32_t inner_sum = sum[ipx+ipy] + sum[inx+iny]
376 - sum[inx+ipy] - sum[ipx+iny];
377 *dst++ = SkToU8((outer_sum * outer_scale
378 + inner_sum * inner_scale) >> 24);
379
380 prev_x += 1;
381 next_x += 1;
382 }
383
384 prev_y += 1;
385 next_y += 1;
386 }
387}
388
reed@android.com8a1c16f2008-12-17 15:59:43 +0000389#include "SkColorPriv.h"
390
reed@android.com0e3c6642009-09-18 13:41:56 +0000391static void merge_src_with_blur(uint8_t dst[], int dstRB,
392 const uint8_t src[], int srcRB,
393 const uint8_t blur[], int blurRB,
394 int sw, int sh) {
395 dstRB -= sw;
396 srcRB -= sw;
397 blurRB -= sw;
398 while (--sh >= 0) {
399 for (int x = sw - 1; x >= 0; --x) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400 *dst = SkToU8(SkAlphaMul(*blur, SkAlpha255To256(*src)));
401 dst += 1;
402 src += 1;
403 blur += 1;
404 }
reed@android.com0e3c6642009-09-18 13:41:56 +0000405 dst += dstRB;
406 src += srcRB;
407 blur += blurRB;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000408 }
409}
410
411static void clamp_with_orig(uint8_t dst[], int dstRowBytes,
reed@android.com0e3c6642009-09-18 13:41:56 +0000412 const uint8_t src[], int srcRowBytes,
413 int sw, int sh,
reed@android.com45607672009-09-21 00:27:08 +0000414 SkBlurMask::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415 int x;
reed@android.com0e3c6642009-09-18 13:41:56 +0000416 while (--sh >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000417 switch (style) {
418 case SkBlurMask::kSolid_Style:
reed@android.com0e3c6642009-09-18 13:41:56 +0000419 for (x = sw - 1; x >= 0; --x) {
420 int s = *src;
421 int d = *dst;
422 *dst = SkToU8(s + d - SkMulDiv255Round(s, d));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000423 dst += 1;
424 src += 1;
425 }
426 break;
427 case SkBlurMask::kOuter_Style:
reed@android.com0e3c6642009-09-18 13:41:56 +0000428 for (x = sw - 1; x >= 0; --x) {
429 if (*src) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000430 *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src)));
reed@android.com0e3c6642009-09-18 13:41:56 +0000431 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 dst += 1;
433 src += 1;
434 }
435 break;
436 default:
437 SkASSERT(!"Unexpected blur style here");
438 break;
439 }
440 dst += dstRowBytes - sw;
reed@android.com0e3c6642009-09-18 13:41:56 +0000441 src += srcRowBytes - sw;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442 }
443}
444
reed@google.com03016a32011-08-12 14:59:59 +0000445///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446
447// we use a local funciton to wrap the class static method to work around
448// a bug in gcc98
449void SkMask_FreeImage(uint8_t* image);
reed@google.com03016a32011-08-12 14:59:59 +0000450void SkMask_FreeImage(uint8_t* image) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000451 SkMask::FreeImage(image);
452}
453
454bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
bungeman@google.com5af16f82011-09-02 15:06:44 +0000455 SkScalar radius, Style style, Quality quality,
456 SkIPoint* margin)
457{
reed@google.com03016a32011-08-12 14:59:59 +0000458 if (src.fFormat != SkMask::kA8_Format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459 return false;
reed@google.com03016a32011-08-12 14:59:59 +0000460 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000461
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +0000462 // Force high quality off for small radii (performance)
463 if (radius < SkIntToScalar(3)) quality = kLow_Quality;
464
465 // highQuality: use three box blur passes as a cheap way to approximate a Gaussian blur
466 int passCount = (quality == kHigh_Quality) ? 3 : 1;
467 SkScalar passRadius = SkScalarDiv(radius, SkScalarSqrt(SkIntToScalar(passCount)));
468
469 int rx = SkScalarCeil(passRadius);
470 int outer_weight = 255 - SkScalarRound((SkIntToScalar(rx) - passRadius) * 255);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471
472 SkASSERT(rx >= 0);
473 SkASSERT((unsigned)outer_weight <= 255);
reed@android.com0e3c6642009-09-18 13:41:56 +0000474 if (rx <= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000475 return false;
reed@android.com0e3c6642009-09-18 13:41:56 +0000476 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000477
478 int ry = rx; // only do square blur for now
479
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +0000480 int padx = passCount * rx;
481 int pady = passCount * ry;
bungeman@google.com5af16f82011-09-02 15:06:44 +0000482 if (margin) {
483 margin->set(padx, pady);
484 }
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +0000485 dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady,
486 src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
reed@android.com49f0ff22009-03-19 21:52:42 +0000487 dst->fRowBytes = dst->fBounds.width();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000488 dst->fFormat = SkMask::kA8_Format;
489 dst->fImage = NULL;
490
reed@android.com0e3c6642009-09-18 13:41:56 +0000491 if (src.fImage) {
reed@android.com543ed932009-04-24 12:43:40 +0000492 size_t dstSize = dst->computeImageSize();
493 if (0 == dstSize) {
494 return false; // too big to allocate, abort
495 }
496
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497 int sw = src.fBounds.width();
498 int sh = src.fBounds.height();
499 const uint8_t* sp = src.fImage;
reed@android.com543ed932009-04-24 12:43:40 +0000500 uint8_t* dp = SkMask::AllocImage(dstSize);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501
502 SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp);
503
504 // build the blurry destination
505 {
reed@google.com03016a32011-08-12 14:59:59 +0000506 const size_t storageW = sw + 2 * (passCount - 1) * rx + 1;
507 const size_t storageH = sh + 2 * (passCount - 1) * ry + 1;
508 SkAutoTMalloc<uint32_t> storage(storageW * storageH);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 uint32_t* sumBuffer = storage.get();
510
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +0000511 //pass1: sp is source, dp is destination
reed@android.com8a1c16f2008-12-17 15:59:43 +0000512 build_sum_buffer(sumBuffer, sw, sh, sp, src.fRowBytes);
reed@google.com03016a32011-08-12 14:59:59 +0000513 if (outer_weight == 255) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514 apply_kernel(dp, rx, ry, sumBuffer, sw, sh);
reed@google.com03016a32011-08-12 14:59:59 +0000515 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 apply_kernel_interp(dp, rx, ry, sumBuffer, sw, sh, outer_weight);
reed@google.com03016a32011-08-12 14:59:59 +0000517 }
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +0000518
reed@google.com03016a32011-08-12 14:59:59 +0000519 if (quality == kHigh_Quality) {
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +0000520 //pass2: dp is source, tmpBuffer is destination
521 int tmp_sw = sw + 2 * rx;
522 int tmp_sh = sh + 2 * ry;
523 SkAutoTMalloc<uint8_t> tmpBuffer(dstSize);
524 build_sum_buffer(sumBuffer, tmp_sw, tmp_sh, dp, tmp_sw);
525 if (outer_weight == 255)
526 apply_kernel(tmpBuffer.get(), rx, ry, sumBuffer, tmp_sw, tmp_sh);
527 else
reed@google.com03016a32011-08-12 14:59:59 +0000528 apply_kernel_interp(tmpBuffer.get(), rx, ry, sumBuffer,
529 tmp_sw, tmp_sh, outer_weight);
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +0000530
531 //pass3: tmpBuffer is source, dp is destination
532 tmp_sw += 2 * rx;
533 tmp_sh += 2 * ry;
534 build_sum_buffer(sumBuffer, tmp_sw, tmp_sh, tmpBuffer.get(), tmp_sw);
535 if (outer_weight == 255)
536 apply_kernel(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh);
537 else
reed@google.com03016a32011-08-12 14:59:59 +0000538 apply_kernel_interp(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh,
539 outer_weight);
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +0000540 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000541 }
542
543 dst->fImage = dp;
544 // if need be, alloc the "real" dst (same size as src) and copy/merge
545 // the blur into it (applying the src)
reed@android.com0e3c6642009-09-18 13:41:56 +0000546 if (style == kInner_Style) {
547 // now we allocate the "real" dst, mirror the size of src
reed@android.com543ed932009-04-24 12:43:40 +0000548 size_t srcSize = src.computeImageSize();
549 if (0 == srcSize) {
550 return false; // too big to allocate, abort
551 }
552 dst->fImage = SkMask::AllocImage(srcSize);
reed@android.com0e3c6642009-09-18 13:41:56 +0000553 merge_src_with_blur(dst->fImage, src.fRowBytes,
554 sp, src.fRowBytes,
reed@google.com03016a32011-08-12 14:59:59 +0000555 dp + passCount * (rx + ry * dst->fRowBytes),
556 dst->fRowBytes, sw, sh);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557 SkMask::FreeImage(dp);
reed@android.com0e3c6642009-09-18 13:41:56 +0000558 } else if (style != kNormal_Style) {
reed@google.com03016a32011-08-12 14:59:59 +0000559 clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes),
560 dst->fRowBytes, sp, src.fRowBytes, sw, sh, style);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000561 }
562 (void)autoCall.detach();
563 }
564
reed@android.com0e3c6642009-09-18 13:41:56 +0000565 if (style == kInner_Style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000566 dst->fBounds = src.fBounds; // restore trimmed bounds
reed@android.com0e3c6642009-09-18 13:41:56 +0000567 dst->fRowBytes = src.fRowBytes;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000568 }
569
reed@android.com8a1c16f2008-12-17 15:59:43 +0000570 return true;
571}
572