1 
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 
9 
10 #include "SkBlurMask.h"
11 #include "SkMath.h"
12 #include "SkTemplates.h"
13 #include "SkEndian.h"
14 
15 
16 // This constant approximates the scaling done in the software path's
17 // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
18 // IMHO, it actually should be 1:  we blur "less" than we should do
19 // according to the CSS and canvas specs, simply because Safari does the same.
20 // Firefox used to do the same too, until 4.0 where they fixed it.  So at some
21 // point we should probably get rid of these scaling constants and rebaseline
22 // all the blur tests.
23 static const SkScalar kBLUR_SIGMA_SCALE = 0.57735f;
24 
ConvertRadiusToSigma(SkScalar radius)25 SkScalar SkBlurMask::ConvertRadiusToSigma(SkScalar radius) {
26     return radius > 0 ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
27 }
28 
ConvertSigmaToRadius(SkScalar sigma)29 SkScalar SkBlurMask::ConvertSigmaToRadius(SkScalar sigma) {
30     return sigma > 0.5f ? (sigma - 0.5f) / kBLUR_SIGMA_SCALE : 0.0f;
31 }
32 
33 #define UNROLL_SEPARABLE_LOOPS
34 
35 /**
36  * This function performs a box blur in X, of the given radius.  If the
37  * "transpose" parameter is true, it will transpose the pixels on write,
38  * such that X and Y are swapped. Reads are always performed from contiguous
39  * memory in X, for speed. The destination buffer (dst) must be at least
40  * (width + leftRadius + rightRadius) * height bytes in size.
41  *
42  * This is what the inner loop looks like before unrolling, and with the two
43  * cases broken out separately (width < diameter, width >= diameter):
44  *
45  *      if (width < diameter) {
46  *          for (int x = 0; x < width; ++x) {
47  *              sum += *right++;
48  *              *dptr = (sum * scale + half) >> 24;
49  *              dptr += dst_x_stride;
50  *          }
51  *          for (int x = width; x < diameter; ++x) {
52  *              *dptr = (sum * scale + half) >> 24;
53  *              dptr += dst_x_stride;
54  *          }
55  *          for (int x = 0; x < width; ++x) {
56  *              *dptr = (sum * scale + half) >> 24;
57  *              sum -= *left++;
58  *              dptr += dst_x_stride;
59  *          }
60  *      } else {
61  *          for (int x = 0; x < diameter; ++x) {
62  *              sum += *right++;
63  *              *dptr = (sum * scale + half) >> 24;
64  *              dptr += dst_x_stride;
65  *          }
66  *          for (int x = diameter; x < width; ++x) {
67  *              sum += *right++;
68  *              *dptr = (sum * scale + half) >> 24;
69  *              sum -= *left++;
70  *              dptr += dst_x_stride;
71  *          }
72  *          for (int x = 0; x < diameter; ++x) {
73  *              *dptr = (sum * scale + half) >> 24;
74  *              sum -= *left++;
75  *              dptr += dst_x_stride;
76  *          }
77  *      }
78  */
boxBlur(const uint8_t * src,int src_y_stride,uint8_t * dst,int leftRadius,int rightRadius,int width,int height,bool transpose)79 static int boxBlur(const uint8_t* src, int src_y_stride, uint8_t* dst,
80                    int leftRadius, int rightRadius, int width, int height,
81                    bool transpose)
82 {
83     int diameter = leftRadius + rightRadius;
84     int kernelSize = diameter + 1;
85     int border = SkMin32(width, diameter);
86     uint32_t scale = (1 << 24) / kernelSize;
87     int new_width = width + SkMax32(leftRadius, rightRadius) * 2;
88     int dst_x_stride = transpose ? height : 1;
89     int dst_y_stride = transpose ? 1 : new_width;
90     uint32_t half = 1 << 23;
91     for (int y = 0; y < height; ++y) {
92         uint32_t sum = 0;
93         uint8_t* dptr = dst + y * dst_y_stride;
94         const uint8_t* right = src + y * src_y_stride;
95         const uint8_t* left = right;
96         for (int x = 0; x < rightRadius - leftRadius; x++) {
97             *dptr = 0;
98             dptr += dst_x_stride;
99         }
100 #define LEFT_BORDER_ITER \
101             sum += *right++; \
102             *dptr = (sum * scale + half) >> 24; \
103             dptr += dst_x_stride;
104 
105         int x = 0;
106 #ifdef UNROLL_SEPARABLE_LOOPS
107         for (; x < border - 16; x += 16) {
108             LEFT_BORDER_ITER
109             LEFT_BORDER_ITER
110             LEFT_BORDER_ITER
111             LEFT_BORDER_ITER
112             LEFT_BORDER_ITER
113             LEFT_BORDER_ITER
114             LEFT_BORDER_ITER
115             LEFT_BORDER_ITER
116             LEFT_BORDER_ITER
117             LEFT_BORDER_ITER
118             LEFT_BORDER_ITER
119             LEFT_BORDER_ITER
120             LEFT_BORDER_ITER
121             LEFT_BORDER_ITER
122             LEFT_BORDER_ITER
123             LEFT_BORDER_ITER
124         }
125 #endif
126         for (; x < border; ++x) {
127             LEFT_BORDER_ITER
128         }
129 #undef LEFT_BORDER_ITER
130 #define TRIVIAL_ITER \
131             *dptr = (sum * scale + half) >> 24; \
132             dptr += dst_x_stride;
133         x = width;
134 #ifdef UNROLL_SEPARABLE_LOOPS
135         for (; x < diameter - 16; x += 16) {
136             TRIVIAL_ITER
137             TRIVIAL_ITER
138             TRIVIAL_ITER
139             TRIVIAL_ITER
140             TRIVIAL_ITER
141             TRIVIAL_ITER
142             TRIVIAL_ITER
143             TRIVIAL_ITER
144             TRIVIAL_ITER
145             TRIVIAL_ITER
146             TRIVIAL_ITER
147             TRIVIAL_ITER
148             TRIVIAL_ITER
149             TRIVIAL_ITER
150             TRIVIAL_ITER
151             TRIVIAL_ITER
152         }
153 #endif
154         for (; x < diameter; ++x) {
155             TRIVIAL_ITER
156         }
157 #undef TRIVIAL_ITER
158 #define CENTER_ITER \
159             sum += *right++; \
160             *dptr = (sum * scale + half) >> 24; \
161             sum -= *left++; \
162             dptr += dst_x_stride;
163 
164         x = diameter;
165 #ifdef UNROLL_SEPARABLE_LOOPS
166         for (; x < width - 16; x += 16) {
167             CENTER_ITER
168             CENTER_ITER
169             CENTER_ITER
170             CENTER_ITER
171             CENTER_ITER
172             CENTER_ITER
173             CENTER_ITER
174             CENTER_ITER
175             CENTER_ITER
176             CENTER_ITER
177             CENTER_ITER
178             CENTER_ITER
179             CENTER_ITER
180             CENTER_ITER
181             CENTER_ITER
182             CENTER_ITER
183         }
184 #endif
185         for (; x < width; ++x) {
186             CENTER_ITER
187         }
188 #undef CENTER_ITER
189 #define RIGHT_BORDER_ITER \
190             *dptr = (sum * scale + half) >> 24; \
191             sum -= *left++; \
192             dptr += dst_x_stride;
193 
194         x = 0;
195 #ifdef UNROLL_SEPARABLE_LOOPS
196         for (; x < border - 16; x += 16) {
197             RIGHT_BORDER_ITER
198             RIGHT_BORDER_ITER
199             RIGHT_BORDER_ITER
200             RIGHT_BORDER_ITER
201             RIGHT_BORDER_ITER
202             RIGHT_BORDER_ITER
203             RIGHT_BORDER_ITER
204             RIGHT_BORDER_ITER
205             RIGHT_BORDER_ITER
206             RIGHT_BORDER_ITER
207             RIGHT_BORDER_ITER
208             RIGHT_BORDER_ITER
209             RIGHT_BORDER_ITER
210             RIGHT_BORDER_ITER
211             RIGHT_BORDER_ITER
212             RIGHT_BORDER_ITER
213         }
214 #endif
215         for (; x < border; ++x) {
216             RIGHT_BORDER_ITER
217         }
218 #undef RIGHT_BORDER_ITER
219         for (int x = 0; x < leftRadius - rightRadius; ++x) {
220             *dptr = 0;
221             dptr += dst_x_stride;
222         }
223         SkASSERT(sum == 0);
224     }
225     return new_width;
226 }
227 
228 /**
229  * This variant of the box blur handles blurring of non-integer radii.  It
230  * keeps two running sums: an outer sum for the rounded-up kernel radius, and
231  * an inner sum for the rounded-down kernel radius.  For each pixel, it linearly
232  * interpolates between them.  In float this would be:
233  *  outer_weight * outer_sum / kernelSize +
234  *  (1.0 - outer_weight) * innerSum / (kernelSize - 2)
235  *
236  * This is what the inner loop looks like before unrolling, and with the two
237  * cases broken out separately (width < diameter, width >= diameter):
238  *
239  *      if (width < diameter) {
240  *          for (int x = 0; x < width; x++) {
241  *              inner_sum = outer_sum;
242  *              outer_sum += *right++;
243  *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
244  *              dptr += dst_x_stride;
245  *          }
246  *          for (int x = width; x < diameter; ++x) {
247  *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
248  *              dptr += dst_x_stride;
249  *          }
250  *          for (int x = 0; x < width; x++) {
251  *              inner_sum = outer_sum - *left++;
252  *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
253  *              dptr += dst_x_stride;
254  *              outer_sum = inner_sum;
255  *          }
256  *      } else {
257  *          for (int x = 0; x < diameter; x++) {
258  *              inner_sum = outer_sum;
259  *              outer_sum += *right++;
260  *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
261  *              dptr += dst_x_stride;
262  *          }
263  *          for (int x = diameter; x < width; ++x) {
264  *              inner_sum = outer_sum - *left;
265  *              outer_sum += *right++;
266  *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
267  *              dptr += dst_x_stride;
268  *              outer_sum -= *left++;
269  *          }
270  *          for (int x = 0; x < diameter; x++) {
271  *              inner_sum = outer_sum - *left++;
272  *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
273  *              dptr += dst_x_stride;
274  *              outer_sum = inner_sum;
275  *          }
276  *      }
277  *  }
278  *  return new_width;
279  */
280 
boxBlurInterp(const uint8_t * src,int src_y_stride,uint8_t * dst,int radius,int width,int height,bool transpose,uint8_t outer_weight)281 static int boxBlurInterp(const uint8_t* src, int src_y_stride, uint8_t* dst,
282                          int radius, int width, int height,
283                          bool transpose, uint8_t outer_weight)
284 {
285     int diameter = radius * 2;
286     int kernelSize = diameter + 1;
287     int border = SkMin32(width, diameter);
288     int inner_weight = 255 - outer_weight;
289     outer_weight += outer_weight >> 7;
290     inner_weight += inner_weight >> 7;
291     uint32_t outer_scale = (outer_weight << 16) / kernelSize;
292     uint32_t inner_scale = (inner_weight << 16) / (kernelSize - 2);
293     uint32_t half = 1 << 23;
294     int new_width = width + diameter;
295     int dst_x_stride = transpose ? height : 1;
296     int dst_y_stride = transpose ? 1 : new_width;
297     for (int y = 0; y < height; ++y) {
298         uint32_t outer_sum = 0, inner_sum = 0;
299         uint8_t* dptr = dst + y * dst_y_stride;
300         const uint8_t* right = src + y * src_y_stride;
301         const uint8_t* left = right;
302         int x = 0;
303 
304 #define LEFT_BORDER_ITER \
305             inner_sum = outer_sum; \
306             outer_sum += *right++; \
307             *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24; \
308             dptr += dst_x_stride;
309 
310 #ifdef UNROLL_SEPARABLE_LOOPS
311         for (;x < border - 16; x += 16) {
312             LEFT_BORDER_ITER
313             LEFT_BORDER_ITER
314             LEFT_BORDER_ITER
315             LEFT_BORDER_ITER
316             LEFT_BORDER_ITER
317             LEFT_BORDER_ITER
318             LEFT_BORDER_ITER
319             LEFT_BORDER_ITER
320             LEFT_BORDER_ITER
321             LEFT_BORDER_ITER
322             LEFT_BORDER_ITER
323             LEFT_BORDER_ITER
324             LEFT_BORDER_ITER
325             LEFT_BORDER_ITER
326             LEFT_BORDER_ITER
327             LEFT_BORDER_ITER
328         }
329 #endif
330 
331         for (;x < border; ++x) {
332             LEFT_BORDER_ITER
333         }
334 #undef LEFT_BORDER_ITER
335         for (int x = width; x < diameter; ++x) {
336             *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
337             dptr += dst_x_stride;
338         }
339         x = diameter;
340 
341 #define CENTER_ITER \
342             inner_sum = outer_sum - *left; \
343             outer_sum += *right++; \
344             *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24; \
345             dptr += dst_x_stride; \
346             outer_sum -= *left++;
347 
348 #ifdef UNROLL_SEPARABLE_LOOPS
349         for (; x < width - 16; x += 16) {
350             CENTER_ITER
351             CENTER_ITER
352             CENTER_ITER
353             CENTER_ITER
354             CENTER_ITER
355             CENTER_ITER
356             CENTER_ITER
357             CENTER_ITER
358             CENTER_ITER
359             CENTER_ITER
360             CENTER_ITER
361             CENTER_ITER
362             CENTER_ITER
363             CENTER_ITER
364             CENTER_ITER
365             CENTER_ITER
366         }
367 #endif
368         for (; x < width; ++x) {
369             CENTER_ITER
370         }
371 #undef CENTER_ITER
372 
373         #define RIGHT_BORDER_ITER \
374             inner_sum = outer_sum - *left++; \
375             *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24; \
376             dptr += dst_x_stride; \
377             outer_sum = inner_sum;
378 
379         x = 0;
380 #ifdef UNROLL_SEPARABLE_LOOPS
381         for (; x < border - 16; x += 16) {
382             RIGHT_BORDER_ITER
383             RIGHT_BORDER_ITER
384             RIGHT_BORDER_ITER
385             RIGHT_BORDER_ITER
386             RIGHT_BORDER_ITER
387             RIGHT_BORDER_ITER
388             RIGHT_BORDER_ITER
389             RIGHT_BORDER_ITER
390             RIGHT_BORDER_ITER
391             RIGHT_BORDER_ITER
392             RIGHT_BORDER_ITER
393             RIGHT_BORDER_ITER
394             RIGHT_BORDER_ITER
395             RIGHT_BORDER_ITER
396             RIGHT_BORDER_ITER
397             RIGHT_BORDER_ITER
398         }
399 #endif
400         for (; x < border; ++x) {
401             RIGHT_BORDER_ITER
402         }
403 #undef RIGHT_BORDER_ITER
404         SkASSERT(outer_sum == 0 && inner_sum == 0);
405     }
406     return new_width;
407 }
408 
get_adjusted_radii(SkScalar passRadius,int * loRadius,int * hiRadius)409 static void get_adjusted_radii(SkScalar passRadius, int *loRadius, int *hiRadius)
410 {
411     *loRadius = *hiRadius = SkScalarCeilToInt(passRadius);
412     if (SkIntToScalar(*hiRadius) - passRadius > 0.5f) {
413         *loRadius = *hiRadius - 1;
414     }
415 }
416 
417 #include "SkColorPriv.h"
418 
merge_src_with_blur(uint8_t dst[],int dstRB,const uint8_t src[],int srcRB,const uint8_t blur[],int blurRB,int sw,int sh)419 static void merge_src_with_blur(uint8_t dst[], int dstRB,
420                                 const uint8_t src[], int srcRB,
421                                 const uint8_t blur[], int blurRB,
422                                 int sw, int sh) {
423     dstRB -= sw;
424     srcRB -= sw;
425     blurRB -= sw;
426     while (--sh >= 0) {
427         for (int x = sw - 1; x >= 0; --x) {
428             *dst = SkToU8(SkAlphaMul(*blur, SkAlpha255To256(*src)));
429             dst += 1;
430             src += 1;
431             blur += 1;
432         }
433         dst += dstRB;
434         src += srcRB;
435         blur += blurRB;
436     }
437 }
438 
clamp_with_orig(uint8_t dst[],int dstRowBytes,const uint8_t src[],int srcRowBytes,int sw,int sh,SkBlurStyle style)439 static void clamp_with_orig(uint8_t dst[], int dstRowBytes,
440                             const uint8_t src[], int srcRowBytes,
441                             int sw, int sh,
442                             SkBlurStyle style) {
443     int x;
444     while (--sh >= 0) {
445         switch (style) {
446         case kSolid_SkBlurStyle:
447             for (x = sw - 1; x >= 0; --x) {
448                 int s = *src;
449                 int d = *dst;
450                 *dst = SkToU8(s + d - SkMulDiv255Round(s, d));
451                 dst += 1;
452                 src += 1;
453             }
454             break;
455         case kOuter_SkBlurStyle:
456             for (x = sw - 1; x >= 0; --x) {
457                 if (*src) {
458                     *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src)));
459                 }
460                 dst += 1;
461                 src += 1;
462             }
463             break;
464         default:
465             SkDEBUGFAIL("Unexpected blur style here");
466             break;
467         }
468         dst += dstRowBytes - sw;
469         src += srcRowBytes - sw;
470     }
471 }
472 
473 ///////////////////////////////////////////////////////////////////////////////
474 
475 // we use a local function to wrap the class static method to work around
476 // a bug in gcc98
477 void SkMask_FreeImage(uint8_t* image);
SkMask_FreeImage(uint8_t * image)478 void SkMask_FreeImage(uint8_t* image) {
479     SkMask::FreeImage(image);
480 }
481 
BoxBlur(SkMask * dst,const SkMask & src,SkScalar sigma,SkBlurStyle style,SkBlurQuality quality,SkIPoint * margin,bool force_quality)482 bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src,
483                          SkScalar sigma, SkBlurStyle style, SkBlurQuality quality,
484                          SkIPoint* margin, bool force_quality) {
485 
486     if (src.fFormat != SkMask::kA8_Format) {
487         return false;
488     }
489 
490     // Force high quality off for small radii (performance)
491     if (!force_quality && sigma <= SkIntToScalar(2)) {
492         quality = kLow_SkBlurQuality;
493     }
494 
495     SkScalar passRadius;
496     if (kHigh_SkBlurQuality == quality) {
497         // For the high quality path the 3 pass box blur kernel width is
498         // 6*rad+1 while the full Gaussian width is 6*sigma.
499         passRadius = sigma - (1/6.0f);
500     } else {
501         // For the low quality path we only attempt to cover 3*sigma of the
502         // Gaussian blur area (1.5*sigma on each side). The single pass box
503         // blur's kernel size is 2*rad+1.
504         passRadius = 1.5f*sigma - 0.5f;
505     }
506 
507     // highQuality: use three box blur passes as a cheap way
508     // to approximate a Gaussian blur
509     int passCount = (kHigh_SkBlurQuality == quality) ? 3 : 1;
510 
511     int rx = SkScalarCeilToInt(passRadius);
512     int outerWeight = 255 - SkScalarRoundToInt((SkIntToScalar(rx) - passRadius) * 255);
513 
514     SkASSERT(rx >= 0);
515     SkASSERT((unsigned)outerWeight <= 255);
516     if (rx <= 0) {
517         return false;
518     }
519 
520     int ry = rx;    // only do square blur for now
521 
522     int padx = passCount * rx;
523     int pady = passCount * ry;
524 
525     if (margin) {
526         margin->set(padx, pady);
527     }
528     dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady,
529                      src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
530 
531     dst->fRowBytes = dst->fBounds.width();
532     dst->fFormat = SkMask::kA8_Format;
533     dst->fImage = NULL;
534 
535     if (src.fImage) {
536         size_t dstSize = dst->computeImageSize();
537         if (0 == dstSize) {
538             return false;   // too big to allocate, abort
539         }
540 
541         int             sw = src.fBounds.width();
542         int             sh = src.fBounds.height();
543         const uint8_t*  sp = src.fImage;
544         uint8_t*        dp = SkMask::AllocImage(dstSize);
545         SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp);
546 
547         // build the blurry destination
548         SkAutoTMalloc<uint8_t>  tmpBuffer(dstSize);
549         uint8_t*                tp = tmpBuffer.get();
550         int w = sw, h = sh;
551 
552         if (outerWeight == 255) {
553             int loRadius, hiRadius;
554             get_adjusted_radii(passRadius, &loRadius, &hiRadius);
555             if (kHigh_SkBlurQuality == quality) {
556                 // Do three X blurs, with a transpose on the final one.
557                 w = boxBlur(sp, src.fRowBytes, tp, loRadius, hiRadius, w, h, false);
558                 w = boxBlur(tp, w,             dp, hiRadius, loRadius, w, h, false);
559                 w = boxBlur(dp, w,             tp, hiRadius, hiRadius, w, h, true);
560                 // Do three Y blurs, with a transpose on the final one.
561                 h = boxBlur(tp, h,             dp, loRadius, hiRadius, h, w, false);
562                 h = boxBlur(dp, h,             tp, hiRadius, loRadius, h, w, false);
563                 h = boxBlur(tp, h,             dp, hiRadius, hiRadius, h, w, true);
564             } else {
565                 w = boxBlur(sp, src.fRowBytes, tp, rx, rx, w, h, true);
566                 h = boxBlur(tp, h,             dp, ry, ry, h, w, true);
567             }
568         } else {
569             if (kHigh_SkBlurQuality == quality) {
570                 // Do three X blurs, with a transpose on the final one.
571                 w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, false, outerWeight);
572                 w = boxBlurInterp(tp, w,             dp, rx, w, h, false, outerWeight);
573                 w = boxBlurInterp(dp, w,             tp, rx, w, h, true, outerWeight);
574                 // Do three Y blurs, with a transpose on the final one.
575                 h = boxBlurInterp(tp, h,             dp, ry, h, w, false, outerWeight);
576                 h = boxBlurInterp(dp, h,             tp, ry, h, w, false, outerWeight);
577                 h = boxBlurInterp(tp, h,             dp, ry, h, w, true, outerWeight);
578             } else {
579                 w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, true, outerWeight);
580                 h = boxBlurInterp(tp, h,             dp, ry, h, w, true, outerWeight);
581             }
582         }
583 
584         dst->fImage = dp;
585         // if need be, alloc the "real" dst (same size as src) and copy/merge
586         // the blur into it (applying the src)
587         if (style == kInner_SkBlurStyle) {
588             // now we allocate the "real" dst, mirror the size of src
589             size_t srcSize = src.computeImageSize();
590             if (0 == srcSize) {
591                 return false;   // too big to allocate, abort
592             }
593             dst->fImage = SkMask::AllocImage(srcSize);
594             merge_src_with_blur(dst->fImage, src.fRowBytes,
595                                 sp, src.fRowBytes,
596                                 dp + passCount * (rx + ry * dst->fRowBytes),
597                                 dst->fRowBytes, sw, sh);
598             SkMask::FreeImage(dp);
599         } else if (style != kNormal_SkBlurStyle) {
600             clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes),
601                             dst->fRowBytes, sp, src.fRowBytes, sw, sh, style);
602         }
603         (void)autoCall.detach();
604     }
605 
606     if (style == kInner_SkBlurStyle) {
607         dst->fBounds = src.fBounds; // restore trimmed bounds
608         dst->fRowBytes = src.fRowBytes;
609     }
610 
611     return true;
612 }
613 
614 /* Convolving a box with itself three times results in a piecewise
615    quadratic function:
616 
617    0                              x <= -1.5
618    9/8 + 3/2 x + 1/2 x^2   -1.5 < x <= -.5
619    3/4 - x^2                -.5 < x <= .5
620    9/8 - 3/2 x + 1/2 x^2    0.5 < x <= 1.5
621    0                        1.5 < x
622 
623    Mathematica:
624 
625    g[x_] := Piecewise [ {
626      {9/8 + 3/2 x + 1/2 x^2 ,  -1.5 < x <= -.5},
627      {3/4 - x^2             ,   -.5 < x <= .5},
628      {9/8 - 3/2 x + 1/2 x^2 ,   0.5 < x <= 1.5}
629    }, 0]
630 
631    To get the profile curve of the blurred step function at the rectangle
632    edge, we evaluate the indefinite integral, which is piecewise cubic:
633 
634    0                                        x <= -1.5
635    9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3   -1.5 < x <= -0.5
636    1/2 + 3/4 x - 1/3 x^3              -.5 < x <= .5
637    7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3     .5 < x <= 1.5
638    1                                  1.5 < x
639 
640    in Mathematica code:
641 
642    gi[x_] := Piecewise[ {
643      { 0 , x <= -1.5 },
644      { 9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3, -1.5 < x <= -0.5 },
645      { 1/2 + 3/4 x - 1/3 x^3          ,  -.5 < x <= .5},
646      { 7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3,   .5 < x <= 1.5}
647    },1]
648 */
649 
gaussianIntegral(float x)650 static float gaussianIntegral(float x) {
651     if (x > 1.5f) {
652         return 0.0f;
653     }
654     if (x < -1.5f) {
655         return 1.0f;
656     }
657 
658     float x2 = x*x;
659     float x3 = x2*x;
660 
661     if ( x > 0.5f ) {
662         return 0.5625f - (x3 / 6.0f - 3.0f * x2 * 0.25f + 1.125f * x);
663     }
664     if ( x > -0.5f ) {
665         return 0.5f - (0.75f * x - x3 / 3.0f);
666     }
667     return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x);
668 }
669 
670 /*  ComputeBlurProfile allocates and fills in an array of floating
671     point values between 0 and 255 for the profile signature of
672     a blurred half-plane with the given blur radius.  Since we're
673     going to be doing screened multiplications (i.e., 1 - (1-x)(1-y))
674     all the time, we actually fill in the profile pre-inverted
675     (already done 255-x).
676 
677     It's the responsibility of the caller to delete the
678     memory returned in profile_out.
679 */
680 
ComputeBlurProfile(SkScalar sigma,uint8_t ** profile_out)681 void SkBlurMask::ComputeBlurProfile(SkScalar sigma, uint8_t **profile_out) {
682     int size = SkScalarCeilToInt(6*sigma);
683 
684     int center = size >> 1;
685     uint8_t *profile = SkNEW_ARRAY(uint8_t, size);
686 
687     float invr = 1.f/(2*sigma);
688 
689     profile[0] = 255;
690     for (int x = 1 ; x < size ; ++x) {
691         float scaled_x = (center - x - .5f) * invr;
692         float gi = gaussianIntegral(scaled_x);
693         profile[x] = 255 - (uint8_t) (255.f * gi);
694     }
695 
696     *profile_out = profile;
697 }
698 
699 // TODO MAYBE: Maintain a profile cache to avoid recomputing this for
700 // commonly used radii.  Consider baking some of the most common blur radii
701 // directly in as static data?
702 
703 // Implementation adapted from Michael Herf's approach:
704 // http://stereopsis.com/shadowrect/
705 
ProfileLookup(const uint8_t * profile,int loc,int blurred_width,int sharp_width)706 uint8_t SkBlurMask::ProfileLookup(const uint8_t *profile, int loc, int blurred_width, int sharp_width) {
707     int dx = SkAbs32(((loc << 1) + 1) - blurred_width) - sharp_width; // how far are we from the original edge?
708     int ox = dx >> 1;
709     if (ox < 0) {
710         ox = 0;
711     }
712 
713     return profile[ox];
714 }
715 
ComputeBlurredScanline(uint8_t * pixels,const uint8_t * profile,unsigned int width,SkScalar sigma)716 void SkBlurMask::ComputeBlurredScanline(uint8_t *pixels, const uint8_t *profile,
717                                         unsigned int width, SkScalar sigma) {
718 
719     unsigned int profile_size = SkScalarCeilToInt(6*sigma);
720     SkAutoTMalloc<uint8_t> horizontalScanline(width);
721 
722     unsigned int sw = width - profile_size;
723     // nearest odd number less than the profile size represents the center
724     // of the (2x scaled) profile
725     int center = ( profile_size & ~1 ) - 1;
726 
727     int w = sw - center;
728 
729     for (unsigned int x = 0 ; x < width ; ++x) {
730        if (profile_size <= sw) {
731            pixels[x] = ProfileLookup(profile, x, width, w);
732        } else {
733            float span = float(sw)/(2*sigma);
734            float giX = 1.5f - (x+.5f)/(2*sigma);
735            pixels[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span)));
736        }
737     }
738 }
739 
BlurRect(SkScalar sigma,SkMask * dst,const SkRect & src,SkBlurStyle style,SkIPoint * margin,SkMask::CreateMode createMode)740 bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst,
741                           const SkRect &src, SkBlurStyle style,
742                           SkIPoint *margin, SkMask::CreateMode createMode) {
743     int profile_size = SkScalarCeilToInt(6*sigma);
744 
745     int pad = profile_size/2;
746     if (margin) {
747         margin->set( pad, pad );
748     }
749 
750     dst->fBounds.set(SkScalarRoundToInt(src.fLeft - pad),
751                      SkScalarRoundToInt(src.fTop - pad),
752                      SkScalarRoundToInt(src.fRight + pad),
753                      SkScalarRoundToInt(src.fBottom + pad));
754 
755     dst->fRowBytes = dst->fBounds.width();
756     dst->fFormat = SkMask::kA8_Format;
757     dst->fImage = NULL;
758 
759     int             sw = SkScalarFloorToInt(src.width());
760     int             sh = SkScalarFloorToInt(src.height());
761 
762     if (createMode == SkMask::kJustComputeBounds_CreateMode) {
763         if (style == kInner_SkBlurStyle) {
764             dst->fBounds.set(SkScalarRoundToInt(src.fLeft),
765                              SkScalarRoundToInt(src.fTop),
766                              SkScalarRoundToInt(src.fRight),
767                              SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds
768             dst->fRowBytes = sw;
769         }
770         return true;
771     }
772     uint8_t *profile = NULL;
773 
774     ComputeBlurProfile(sigma, &profile);
775     SkAutoTDeleteArray<uint8_t> ada(profile);
776 
777     size_t dstSize = dst->computeImageSize();
778     if (0 == dstSize) {
779         return false;   // too big to allocate, abort
780     }
781 
782     uint8_t*        dp = SkMask::AllocImage(dstSize);
783 
784     dst->fImage = dp;
785 
786     int dstHeight = dst->fBounds.height();
787     int dstWidth = dst->fBounds.width();
788 
789     uint8_t *outptr = dp;
790 
791     SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth);
792     SkAutoTMalloc<uint8_t> verticalScanline(dstHeight);
793 
794     ComputeBlurredScanline(horizontalScanline, profile, dstWidth, sigma);
795     ComputeBlurredScanline(verticalScanline, profile, dstHeight, sigma);
796 
797     for (int y = 0 ; y < dstHeight ; ++y) {
798         for (int x = 0 ; x < dstWidth ; x++) {
799             unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], verticalScanline[y]);
800             *(outptr++) = maskval;
801         }
802     }
803 
804     if (style == kInner_SkBlurStyle) {
805         // now we allocate the "real" dst, mirror the size of src
806         size_t srcSize = (size_t)(src.width() * src.height());
807         if (0 == srcSize) {
808             return false;   // too big to allocate, abort
809         }
810         dst->fImage = SkMask::AllocImage(srcSize);
811         for (int y = 0 ; y < sh ; y++) {
812             uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad;
813             uint8_t *inner_scanline = dst->fImage + y*sw;
814             memcpy(inner_scanline, blur_scanline, sw);
815         }
816         SkMask::FreeImage(dp);
817 
818         dst->fBounds.set(SkScalarRoundToInt(src.fLeft),
819                          SkScalarRoundToInt(src.fTop),
820                          SkScalarRoundToInt(src.fRight),
821                          SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds
822         dst->fRowBytes = sw;
823 
824     } else if (style == kOuter_SkBlurStyle) {
825         for (int y = pad ; y < dstHeight-pad ; y++) {
826             uint8_t *dst_scanline = dp + y*dstWidth + pad;
827             memset(dst_scanline, 0, sw);
828         }
829     } else if (style == kSolid_SkBlurStyle) {
830         for (int y = pad ; y < dstHeight-pad ; y++) {
831             uint8_t *dst_scanline = dp + y*dstWidth + pad;
832             memset(dst_scanline, 0xff, sw);
833         }
834     }
835     // normal and solid styles are the same for analytic rect blurs, so don't
836     // need to handle solid specially.
837 
838     return true;
839 }
840 
BlurRRect(SkScalar sigma,SkMask * dst,const SkRRect & src,SkBlurStyle style,SkIPoint * margin,SkMask::CreateMode createMode)841 bool SkBlurMask::BlurRRect(SkScalar sigma, SkMask *dst,
842                            const SkRRect &src, SkBlurStyle style,
843                            SkIPoint *margin, SkMask::CreateMode createMode) {
844     // Temporary for now -- always fail, should cause caller to fall back
845     // to old path.  Plumbing just to land API and parallelize effort.
846 
847     return false;
848 }
849 
850 // The "simple" blur is a direct implementation of separable convolution with a discrete
851 // gaussian kernel.  It's "ground truth" in a sense; too slow to be used, but very
852 // useful for correctness comparisons.
853 
BlurGroundTruth(SkScalar sigma,SkMask * dst,const SkMask & src,SkBlurStyle style,SkIPoint * margin)854 bool SkBlurMask::BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src,
855                                  SkBlurStyle style, SkIPoint* margin) {
856 
857     if (src.fFormat != SkMask::kA8_Format) {
858         return false;
859     }
860 
861     float variance = sigma * sigma;
862 
863     int windowSize = SkScalarCeilToInt(sigma*6);
864     // round window size up to nearest odd number
865     windowSize |= 1;
866 
867     SkAutoTMalloc<float> gaussWindow(windowSize);
868 
869     int halfWindow = windowSize >> 1;
870 
871     gaussWindow[halfWindow] = 1;
872 
873     float windowSum = 1;
874     for (int x = 1 ; x <= halfWindow ; ++x) {
875         float gaussian = expf(-x*x / (2*variance));
876         gaussWindow[halfWindow + x] = gaussWindow[halfWindow-x] = gaussian;
877         windowSum += 2*gaussian;
878     }
879 
880     // leave the filter un-normalized for now; we will divide by the normalization
881     // sum later;
882 
883     int pad = halfWindow;
884     if (margin) {
885         margin->set( pad, pad );
886     }
887 
888     dst->fBounds = src.fBounds;
889     dst->fBounds.outset(pad, pad);
890 
891     dst->fRowBytes = dst->fBounds.width();
892     dst->fFormat = SkMask::kA8_Format;
893     dst->fImage = NULL;
894 
895     if (src.fImage) {
896 
897         size_t dstSize = dst->computeImageSize();
898         if (0 == dstSize) {
899             return false;   // too big to allocate, abort
900         }
901 
902         int             srcWidth = src.fBounds.width();
903         int             srcHeight = src.fBounds.height();
904         int             dstWidth = dst->fBounds.width();
905 
906         const uint8_t*  srcPixels = src.fImage;
907         uint8_t*        dstPixels = SkMask::AllocImage(dstSize);
908         SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dstPixels);
909 
910         // do the actual blur.  First, make a padded copy of the source.
911         // use double pad so we never have to check if we're outside anything
912 
913         int padWidth = srcWidth + 4*pad;
914         int padHeight = srcHeight;
915         int padSize = padWidth * padHeight;
916 
917         SkAutoTMalloc<uint8_t> padPixels(padSize);
918         memset(padPixels, 0, padSize);
919 
920         for (int y = 0 ; y < srcHeight; ++y) {
921             uint8_t* padptr = padPixels + y * padWidth + 2*pad;
922             const uint8_t* srcptr = srcPixels + y * srcWidth;
923             memcpy(padptr, srcptr, srcWidth);
924         }
925 
926         // blur in X, transposing the result into a temporary floating point buffer.
927         // also double-pad the intermediate result so that the second blur doesn't
928         // have to do extra conditionals.
929 
930         int tmpWidth = padHeight + 4*pad;
931         int tmpHeight = padWidth - 2*pad;
932         int tmpSize = tmpWidth * tmpHeight;
933 
934         SkAutoTMalloc<float> tmpImage(tmpSize);
935         memset(tmpImage, 0, tmpSize*sizeof(tmpImage[0]));
936 
937         for (int y = 0 ; y < padHeight ; ++y) {
938             uint8_t *srcScanline = padPixels + y*padWidth;
939             for (int x = pad ; x < padWidth - pad ; ++x) {
940                 float *outPixel = tmpImage + (x-pad)*tmpWidth + y + 2*pad; // transposed output
941                 uint8_t *windowCenter = srcScanline + x;
942                 for (int i = -pad ; i <= pad ; ++i) {
943                     *outPixel += gaussWindow[pad+i]*windowCenter[i];
944                 }
945                 *outPixel /= windowSum;
946             }
947         }
948 
949         // blur in Y; now filling in the actual desired destination.  We have to do
950         // the transpose again; these transposes guarantee that we read memory in
951         // linear order.
952 
953         for (int y = 0 ; y < tmpHeight ; ++y) {
954             float *srcScanline = tmpImage + y*tmpWidth;
955             for (int x = pad ; x < tmpWidth - pad ; ++x) {
956                 float *windowCenter = srcScanline + x;
957                 float finalValue = 0;
958                 for (int i = -pad ; i <= pad ; ++i) {
959                     finalValue += gaussWindow[pad+i]*windowCenter[i];
960                 }
961                 finalValue /= windowSum;
962                 uint8_t *outPixel = dstPixels + (x-pad)*dstWidth + y; // transposed output
963                 int integerPixel = int(finalValue + 0.5f);
964                 *outPixel = SkClampMax( SkClampPos(integerPixel), 255 );
965             }
966         }
967 
968         dst->fImage = dstPixels;
969         // if need be, alloc the "real" dst (same size as src) and copy/merge
970         // the blur into it (applying the src)
971         if (style == kInner_SkBlurStyle) {
972             // now we allocate the "real" dst, mirror the size of src
973             size_t srcSize = src.computeImageSize();
974             if (0 == srcSize) {
975                 return false;   // too big to allocate, abort
976             }
977             dst->fImage = SkMask::AllocImage(srcSize);
978             merge_src_with_blur(dst->fImage, src.fRowBytes,
979                 srcPixels, src.fRowBytes,
980                 dstPixels + pad*dst->fRowBytes + pad,
981                 dst->fRowBytes, srcWidth, srcHeight);
982             SkMask::FreeImage(dstPixels);
983         } else if (style != kNormal_SkBlurStyle) {
984             clamp_with_orig(dstPixels + pad*dst->fRowBytes + pad,
985                 dst->fRowBytes, srcPixels, src.fRowBytes, srcWidth, srcHeight, style);
986         }
987         (void)autoCall.detach();
988     }
989 
990     if (style == kInner_SkBlurStyle) {
991         dst->fBounds = src.fBounds; // restore trimmed bounds
992         dst->fRowBytes = src.fRowBytes;
993     }
994 
995     return true;
996 }
997