SkBlurMask.cpp revision 7bd141dce43ea3405bc60c9c84e6f910b851b079
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurMask.h"
11889bd8bd7f604acae0a6303365bc82c06da1e6f3tomhudson@google.com#include "SkMath.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTemplates.h"
1301224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com#include "SkEndian.h"
1401224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com
157ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com
167ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.comSkScalar SkBlurMask::ConvertRadiusToSigma(SkScalar radius) {
177ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    // This constant approximates the scaling done in the software path's
187ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
197ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    // IMHO, it actually should be 1:  we blur "less" than we should do
207ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    // according to the CSS and canvas specs, simply because Safari does the same.
217ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    // Firefox used to do the same too, until 4.0 where they fixed it.  So at some
227ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    // point we should probably get rid of these scaling constants and rebaseline
237ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    // all the blur tests.
247ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    static const SkScalar kBLUR_SIGMA_SCALE = SkFloatToScalar(0.57735f);
257ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com
267ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    return radius ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
277ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com}
287c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
299b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define UNROLL_SEPARABLE_LOOPS
309b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
31908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org/**
32908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org * This function performs a box blur in X, of the given radius.  If the
33884e60be30e20f38b3466a4697081187d2f1f814skia.committer@gmail.com * "transpose" parameter is true, it will transpose the pixels on write,
34908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org * such that X and Y are swapped. Reads are always performed from contiguous
35908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org * memory in X, for speed. The destination buffer (dst) must be at least
369b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org * (width + leftRadius + rightRadius) * height bytes in size.
374a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *
384a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org * This is what the inner loop looks like before unrolling, and with the two
394a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org * cases broken out separately (width < diameter, width >= diameter):
4076bf70d38fd109a09ee44d074cfd392e1884afffskia.committer@gmail.com *
414a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      if (width < diameter) {
424a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < width; ++x) {
434a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum += *right++;
4476bf70d38fd109a09ee44d074cfd392e1884afffskia.committer@gmail.com *              *dptr = (sum * scale + half) >> 24;
454a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
464a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
474a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = width; x < diameter; ++x) {
484a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (sum * scale + half) >> 24;
494a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
504a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
514a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < width; ++x) {
524a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (sum * scale + half) >> 24;
534a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum -= *left++;
544a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
554a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
564a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      } else {
574a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < diameter; ++x) {
584a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum += *right++;
594a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (sum * scale + half) >> 24;
604a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
614a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
624a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = diameter; x < width; ++x) {
634a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum += *right++;
644a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (sum * scale + half) >> 24;
654a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum -= *left++;
664a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
674a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
684a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < diameter; ++x) {
694a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (sum * scale + half) >> 24;
704a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum -= *left++;
714a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
724a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
734a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      }
74908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org */
75908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.orgstatic int boxBlur(const uint8_t* src, int src_y_stride, uint8_t* dst,
76c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org                   int leftRadius, int rightRadius, int width, int height,
77c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org                   bool transpose)
7871f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org{
799b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int diameter = leftRadius + rightRadius;
809b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int kernelSize = diameter + 1;
819b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int border = SkMin32(width, diameter);
8271f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org    uint32_t scale = (1 << 24) / kernelSize;
83c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org    int new_width = width + SkMax32(leftRadius, rightRadius) * 2;
84908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org    int dst_x_stride = transpose ? height : 1;
85908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org    int dst_y_stride = transpose ? 1 : new_width;
864a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#ifndef SK_DISABLE_BLUR_ROUNDING
874a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org    uint32_t half = 1 << 23;
884a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#else
894a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org    uint32_t half = 0;
904a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#endif
9171f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org    for (int y = 0; y < height; ++y) {
924a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org        uint32_t sum = 0;
93908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org        uint8_t* dptr = dst + y * dst_y_stride;
94908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org        const uint8_t* right = src + y * src_y_stride;
95908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org        const uint8_t* left = right;
96336b4da6b0d20f27f9980b03415354a2f0698e18senorblanco@chromium.org        for (int x = 0; x < rightRadius - leftRadius; x++) {
97336b4da6b0d20f27f9980b03415354a2f0698e18senorblanco@chromium.org            *dptr = 0;
98336b4da6b0d20f27f9980b03415354a2f0698e18senorblanco@chromium.org            dptr += dst_x_stride;
99c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org        }
1009b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define LEFT_BORDER_ITER \
1019b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            sum += *right++; \
1024a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (sum * scale + half) >> 24; \
103908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org            dptr += dst_x_stride;
1049b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
1059b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        int x = 0;
1069b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
1079b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < border - 16; x += 16) {
1089b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1099b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1109b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1119b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1129b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1139b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1149b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1159b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1169b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1179b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1189b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1199b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1209b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1219b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1229b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1239b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
12471f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        }
1259b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
1269b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < border; ++x) {
1279b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1289b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
1299b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef LEFT_BORDER_ITER
1309b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define TRIVIAL_ITER \
1314a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (sum * scale + half) >> 24; \
132908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org            dptr += dst_x_stride;
1339b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        x = width;
1349b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
1359b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < diameter - 16; x += 16) {
1369b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1379b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1389b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1399b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1409b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1419b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1429b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1439b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1449b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1459b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1469b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1479b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1489b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1499b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1509b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1519b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1529b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
1539b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
1549b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < diameter; ++x) {
1559b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
15671f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        }
1579b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef TRIVIAL_ITER
1589b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define CENTER_ITER \
1599b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            sum += *right++; \
1604a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (sum * scale + half) >> 24; \
1619b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            sum -= *left++; \
162908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org            dptr += dst_x_stride;
1639b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
1649b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        x = diameter;
1659b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
1669b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < width - 16; x += 16) {
1679b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1689b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1699b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1709b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1719b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1729b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1739b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1749b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1759b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1769b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1779b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1789b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1799b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1809b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1819b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1829b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1839b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
1849b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
1859b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < width; ++x) {
1869b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
18771f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        }
1889b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef CENTER_ITER
1899b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define RIGHT_BORDER_ITER \
1904a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (sum * scale + half) >> 24; \
1919b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            sum -= *left++; \
192908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org            dptr += dst_x_stride;
1939b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
1949b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        x = 0;
1959b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
1969b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < border - 16; x += 16) {
1979b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
1989b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
1999b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2009b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2019b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2029b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2039b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2049b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2059b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2069b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2079b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2089b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2099b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2109b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2119b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2129b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
2139b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
2149b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
2159b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < border; ++x) {
2169b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
21771f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        }
2189b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef RIGHT_BORDER_ITER
219a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int x = 0; x < leftRadius - rightRadius; ++x) {
220336b4da6b0d20f27f9980b03415354a2f0698e18senorblanco@chromium.org            *dptr = 0;
221336b4da6b0d20f27f9980b03415354a2f0698e18senorblanco@chromium.org            dptr += dst_x_stride;
222c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org        }
22371f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        SkASSERT(sum == 0);
22471f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org    }
225908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org    return new_width;
22671f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org}
22771f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org
2289b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org/**
2299b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org * This variant of the box blur handles blurring of non-integer radii.  It
2309b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org * keeps two running sums: an outer sum for the rounded-up kernel radius, and
2319b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org * an inner sum for the rounded-down kernel radius.  For each pixel, it linearly
2329b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org * interpolates between them.  In float this would be:
2339b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org *  outer_weight * outer_sum / kernelSize +
2349b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org *  (1.0 - outer_weight) * innerSum / (kernelSize - 2)
23576bf70d38fd109a09ee44d074cfd392e1884afffskia.committer@gmail.com *
2364a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org * This is what the inner loop looks like before unrolling, and with the two
2374a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org * cases broken out separately (width < diameter, width >= diameter):
23876bf70d38fd109a09ee44d074cfd392e1884afffskia.committer@gmail.com *
2394a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      if (width < diameter) {
2404a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < width; x++) {
2414a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              inner_sum = outer_sum;
2424a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              outer_sum += *right++;
2434a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
2444a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
2454a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2464a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = width; x < diameter; ++x) {
2474a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
2484a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
2494a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2504a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < width; x++) {
2514a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              inner_sum = outer_sum - *left++;
2524a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
2534a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
2544a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              outer_sum = inner_sum;
2554a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2564a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      } else {
2574a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < diameter; x++) {
2584a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              inner_sum = outer_sum;
2594a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              outer_sum += *right++;
2604a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
2614a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
2624a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2634a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = diameter; x < width; ++x) {
2644a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              inner_sum = outer_sum - *left;
2654a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              outer_sum += *right++;
2664a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
2674a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
2684a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              outer_sum -= *left++;
2694a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2704a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < diameter; x++) {
2714a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              inner_sum = outer_sum - *left++;
2724a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
2734a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
2744a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              outer_sum = inner_sum;
2754a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2764a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      }
2774a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *  }
2784a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *  return new_width;
2799b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org */
2804a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org
2819b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.orgstatic int boxBlurInterp(const uint8_t* src, int src_y_stride, uint8_t* dst,
2829b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org                         int radius, int width, int height,
2839b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org                         bool transpose, uint8_t outer_weight)
2849b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org{
2859b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int diameter = radius * 2;
2869b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int kernelSize = diameter + 1;
2879b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int border = SkMin32(width, diameter);
2889b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int inner_weight = 255 - outer_weight;
2899b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    outer_weight += outer_weight >> 7;
2909b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    inner_weight += inner_weight >> 7;
2919b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    uint32_t outer_scale = (outer_weight << 16) / kernelSize;
2929b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    uint32_t inner_scale = (inner_weight << 16) / (kernelSize - 2);
2934a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#ifndef SK_DISABLE_BLUR_ROUNDING
2944a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org    uint32_t half = 1 << 23;
2954a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#else
2964a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org    uint32_t half = 0;
2974a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#endif
2989b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int new_width = width + diameter;
2999b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int dst_x_stride = transpose ? height : 1;
3009b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int dst_y_stride = transpose ? 1 : new_width;
3019b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    for (int y = 0; y < height; ++y) {
3024a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org        uint32_t outer_sum = 0, inner_sum = 0;
3039b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        uint8_t* dptr = dst + y * dst_y_stride;
3049b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        const uint8_t* right = src + y * src_y_stride;
3059b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        const uint8_t* left = right;
3069b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        int x = 0;
3079b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3089b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define LEFT_BORDER_ITER \
3099b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            inner_sum = outer_sum; \
3109b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            outer_sum += *right++; \
3114a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24; \
3129b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            dptr += dst_x_stride;
3139b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3149b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
3159b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (;x < border - 16; x += 16) {
3169b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3179b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3189b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3199b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3209b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3219b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3229b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3239b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3249b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3259b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3269b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3279b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3289b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3299b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3309b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3319b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3329b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
3339b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
3349b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
335a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (;x < border; ++x) {
3369b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3379b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
3389b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef LEFT_BORDER_ITER
3399b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (int x = width; x < diameter; ++x) {
3404a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
3419b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            dptr += dst_x_stride;
3429b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
3439b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        x = diameter;
3449b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3459b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define CENTER_ITER \
3469b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            inner_sum = outer_sum - *left; \
3479b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            outer_sum += *right++; \
3484a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24; \
3499b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            dptr += dst_x_stride; \
3509b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            outer_sum -= *left++;
3519b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3529b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
3539b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < width - 16; x += 16) {
3549b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3559b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3569b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3579b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3589b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3599b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3609b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3619b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3629b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3639b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3649b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3659b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3669b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3679b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3689b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3699b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3709b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
3719b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
3729b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < width; ++x) {
3739b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3749b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
3759b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef CENTER_ITER
3769b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3779b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        #define RIGHT_BORDER_ITER \
3789b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            inner_sum = outer_sum - *left++; \
3794a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24; \
3809b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            dptr += dst_x_stride; \
3819b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            outer_sum = inner_sum;
3829b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3839b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        x = 0;
3849b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
3859b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < border - 16; x += 16) {
3869b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3879b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3889b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3899b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3909b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3919b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3929b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3939b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3949b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3959b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3969b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3979b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3989b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3999b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
4009b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
4019b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
4029b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
4039b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
404a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (; x < border; ++x) {
4059b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
4069b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
4079b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef RIGHT_BORDER_ITER
4089b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        SkASSERT(outer_sum == 0 && inner_sum == 0);
4099b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    }
4109b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    return new_width;
4119b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org}
4129b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
413c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.orgstatic void get_adjusted_radii(SkScalar passRadius, int *loRadius, int *hiRadius)
414c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org{
415c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org    *loRadius = *hiRadius = SkScalarCeil(passRadius);
416c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org    if (SkIntToScalar(*hiRadius) - passRadius > SkFloatToScalar(0.5f)) {
417c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org        *loRadius = *hiRadius - 1;
418c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org    }
419c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org}
420c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org
4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4230e3c664250f561ec9f7107b92136517a72d03afdreed@android.comstatic void merge_src_with_blur(uint8_t dst[], int dstRB,
4240e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                                const uint8_t src[], int srcRB,
4250e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                                const uint8_t blur[], int blurRB,
4260e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                                int sw, int sh) {
4270e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    dstRB -= sw;
4280e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    srcRB -= sw;
4290e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    blurRB -= sw;
4300e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    while (--sh >= 0) {
4310e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        for (int x = sw - 1; x >= 0; --x) {
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *dst = SkToU8(SkAlphaMul(*blur, SkAlpha255To256(*src)));
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst += 1;
4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            src += 1;
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            blur += 1;
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4370e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        dst += dstRB;
4380e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        src += srcRB;
4390e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        blur += blurRB;
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void clamp_with_orig(uint8_t dst[], int dstRowBytes,
4440e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                            const uint8_t src[], int srcRowBytes,
4450e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                            int sw, int sh,
4464560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com                            SkBlurMask::Style style) {
4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int x;
4480e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    while (--sh >= 0) {
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        switch (style) {
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkBlurMask::kSolid_Style:
4510e3c664250f561ec9f7107b92136517a72d03afdreed@android.com            for (x = sw - 1; x >= 0; --x) {
4520e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                int s = *src;
4530e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                int d = *dst;
4540e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                *dst = SkToU8(s + d - SkMulDiv255Round(s, d));
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                dst += 1;
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                src += 1;
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkBlurMask::kOuter_Style:
4600e3c664250f561ec9f7107b92136517a72d03afdreed@android.com            for (x = sw - 1; x >= 0; --x) {
4610e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                if (*src) {
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src)));
4630e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                }
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                dst += 1;
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                src += 1;
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        default:
4690c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com            SkDEBUGFAIL("Unexpected blur style here");
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst += dstRowBytes - sw;
4730e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        src += srcRowBytes - sw;
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
47703016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com///////////////////////////////////////////////////////////////////////////////
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
47933cdbdea3ddcec9323b65eace86e10557312ae9bbsalomon@google.com// we use a local function to wrap the class static method to work around
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// a bug in gcc98
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMask_FreeImage(uint8_t* image);
48203016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.comvoid SkMask_FreeImage(uint8_t* image) {
4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMask::FreeImage(image);
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
4875af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                      SkScalar radius, Style style, Quality quality,
4887ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                      SkIPoint* margin) {
4897bd141dce43ea3405bc60c9c84e6f910b851b079skia.committer@gmail.com    return SkBlurMask::BoxBlur(dst, src,
4907ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                               SkBlurMask::ConvertRadiusToSigma(radius),
4917ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                               style, quality, margin);
4927ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com}
4937ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com
4947ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.combool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src,
4957ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                         SkScalar sigma, Style style, Quality quality,
4967ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                         SkIPoint* margin) {
497a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
49803016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com    if (src.fFormat != SkMask::kA8_Format) {
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
50003016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com    }
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5024868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    // Force high quality off for small radii (performance)
5037ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    if (sigma <= SkIntToScalar(2)) {
50491f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org        quality = kLow_Quality;
50591f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org    }
506d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
5077ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    SkScalar passRadius;
5087ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    if (kHigh_Quality == quality) {
5097ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        // For the high quality path the 3 pass box blur kernel width is
5107ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        // 6*rad+1 while the full Gaussian width is 6*sigma.
5117ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        passRadius = sigma - (1/6.0f);
5127ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    } else {
5137bd141dce43ea3405bc60c9c84e6f910b851b079skia.committer@gmail.com        // For the low quality path we only attempt to cover 3*sigma of the
5147bd141dce43ea3405bc60c9c84e6f910b851b079skia.committer@gmail.com        // Gaussian blur area (1.5*sigma on each side). The single pass box
5157ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        // blur's kernel size is 2*rad+1.
5167ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com        passRadius = 1.5f*sigma - 0.5f;
5177ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    }
5187ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com
519d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com    // highQuality: use three box blur passes as a cheap way
520a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // to approximate a Gaussian blur
52191f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org    int passCount = (kHigh_Quality == quality) ? 3 : 1;
522a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
5234868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    int rx = SkScalarCeil(passRadius);
524a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int outerWeight = 255 - SkScalarRound((SkIntToScalar(rx) - passRadius) * 255);
5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(rx >= 0);
527a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    SkASSERT((unsigned)outerWeight <= 255);
5280e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    if (rx <= 0) {
5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
5300e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    }
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int ry = rx;    // only do square blur for now
5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5344868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    int padx = passCount * rx;
5354868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    int pady = passCount * ry;
536d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
5375af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    if (margin) {
5385af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        margin->set(padx, pady);
5395af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    }
5404868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady,
5417ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                     src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
542d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
54349f0ff25a046d6001dc2d095b6fa3c30f0f46b6areed@android.com    dst->fRowBytes = dst->fBounds.width();
5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fFormat = SkMask::kA8_Format;
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fImage = NULL;
5468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5470e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    if (src.fImage) {
548543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        size_t dstSize = dst->computeImageSize();
549543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        if (0 == dstSize) {
550543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            return false;   // too big to allocate, abort
551543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        }
552543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com
5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int             sw = src.fBounds.width();
5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int             sh = src.fBounds.height();
5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const uint8_t*  sp = src.fImage;
556543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        uint8_t*        dp = SkMask::AllocImage(dstSize);
5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp);
5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // build the blurry destination
5600a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org        SkAutoTMalloc<uint8_t>  tmpBuffer(dstSize);
5610a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org        uint8_t*                tp = tmpBuffer.get();
5620a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org        int w = sw, h = sh;
563d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
5640a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org        if (outerWeight == 255) {
5650a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org            int loRadius, hiRadius;
5660a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org            get_adjusted_radii(passRadius, &loRadius, &hiRadius);
5670a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org            if (kHigh_Quality == quality) {
5680a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                // Do three X blurs, with a transpose on the final one.
5690a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                w = boxBlur(sp, src.fRowBytes, tp, loRadius, hiRadius, w, h, false);
5700a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                w = boxBlur(tp, w,             dp, hiRadius, loRadius, w, h, false);
5710a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                w = boxBlur(dp, w,             tp, hiRadius, hiRadius, w, h, true);
5720a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                // Do three Y blurs, with a transpose on the final one.
5730a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                h = boxBlur(tp, h,             dp, loRadius, hiRadius, h, w, false);
5740a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                h = boxBlur(dp, h,             tp, hiRadius, loRadius, h, w, false);
5750a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                h = boxBlur(tp, h,             dp, hiRadius, hiRadius, h, w, true);
576908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org            } else {
5770a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                w = boxBlur(sp, src.fRowBytes, tp, rx, rx, w, h, true);
5780a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                h = boxBlur(tp, h,             dp, ry, ry, h, w, true);
57971f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org            }
58071f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        } else {
58191f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org            if (kHigh_Quality == quality) {
5820a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                // Do three X blurs, with a transpose on the final one.
5830a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, false, outerWeight);
5840a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                w = boxBlurInterp(tp, w,             dp, rx, w, h, false, outerWeight);
5850a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                w = boxBlurInterp(dp, w,             tp, rx, w, h, true, outerWeight);
5860a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                // Do three Y blurs, with a transpose on the final one.
5870a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                h = boxBlurInterp(tp, h,             dp, ry, h, w, false, outerWeight);
5880a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                h = boxBlurInterp(dp, h,             tp, ry, h, w, false, outerWeight);
5890a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                h = boxBlurInterp(tp, h,             dp, ry, h, w, true, outerWeight);
5900a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org            } else {
5910a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, true, outerWeight);
5920a1c3872de6642ada98bd7226ff9ed14750241b9commit-bot@chromium.org                h = boxBlurInterp(tp, h,             dp, ry, h, w, true, outerWeight);
5934868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org            }
5948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst->fImage = dp;
5978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // if need be, alloc the "real" dst (same size as src) and copy/merge
5988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // the blur into it (applying the src)
5990e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        if (style == kInner_Style) {
6000e3c664250f561ec9f7107b92136517a72d03afdreed@android.com            // now we allocate the "real" dst, mirror the size of src
601543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            size_t srcSize = src.computeImageSize();
602543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            if (0 == srcSize) {
603543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com                return false;   // too big to allocate, abort
604543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            }
605543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            dst->fImage = SkMask::AllocImage(srcSize);
6060e3c664250f561ec9f7107b92136517a72d03afdreed@android.com            merge_src_with_blur(dst->fImage, src.fRowBytes,
6070e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                                sp, src.fRowBytes,
60803016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                                dp + passCount * (rx + ry * dst->fRowBytes),
60903016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                                dst->fRowBytes, sw, sh);
6108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkMask::FreeImage(dp);
6110e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        } else if (style != kNormal_Style) {
61203016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com            clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes),
61303016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                            dst->fRowBytes, sp, src.fRowBytes, sw, sh, style);
6148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        (void)autoCall.detach();
6168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6180e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    if (style == kInner_Style) {
6198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst->fBounds = src.fBounds; // restore trimmed bounds
6200e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        dst->fRowBytes = src.fRowBytes;
6218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6267c7292c6071898d73dc935c3b66b9816183806f0humper@google.com/* Convolving a box with itself three times results in a piecewise
6277c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   quadratic function:
6288ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
6297c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   0                              x <= -1.5
630a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   9/8 + 3/2 x + 1/2 x^2   -1.5 < x <= -.5
6317c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   3/4 - x^2                -.5 < x <= .5
6327c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   9/8 - 3/2 x + 1/2 x^2    0.5 < x <= 1.5
6337c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   0                        1.5 < x
634d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
635a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   Mathematica:
636d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
637a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   g[x_] := Piecewise [ {
638a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     {9/8 + 3/2 x + 1/2 x^2 ,  -1.5 < x <= -.5},
639a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     {3/4 - x^2             ,   -.5 < x <= .5},
640a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     {9/8 - 3/2 x + 1/2 x^2 ,   0.5 < x <= 1.5}
641a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   }, 0]
6428ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
6437c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   To get the profile curve of the blurred step function at the rectangle
6447c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   edge, we evaluate the indefinite integral, which is piecewise cubic:
6458ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
6467c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   0                                        x <= -1.5
647a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3   -1.5 < x <= -0.5
6487c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   1/2 + 3/4 x - 1/3 x^3              -.5 < x <= .5
649a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3     .5 < x <= 1.5
6507c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   1                                  1.5 < x
651d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
652a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   in Mathematica code:
653d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
654a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   gi[x_] := Piecewise[ {
655a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     { 0 , x <= -1.5 },
656a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     { 9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3, -1.5 < x <= -0.5 },
657a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     { 1/2 + 3/4 x - 1/3 x^3          ,  -.5 < x <= .5},
658a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     { 7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3,   .5 < x <= 1.5}
659a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   },1]
6607c7292c6071898d73dc935c3b66b9816183806f0humper@google.com*/
6617c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
662a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.comstatic float gaussianIntegral(float x) {
663a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (x > 1.5f) {
6647c7292c6071898d73dc935c3b66b9816183806f0humper@google.com        return 0.0f;
6657c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
666a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (x < -1.5f) {
6677c7292c6071898d73dc935c3b66b9816183806f0humper@google.com        return 1.0f;
6687c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
6697c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
6707c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    float x2 = x*x;
6717c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    float x3 = x2*x;
6727c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
6739c4e5ac5b7d32151d4d8ab1fb7ed443b35eb1254jvanverth@google.com    if ( x > 0.5f ) {
674a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        return 0.5625f - (x3 / 6.0f - 3.0f * x2 * 0.25f + 1.125f * x);
6757c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
6769c4e5ac5b7d32151d4d8ab1fb7ed443b35eb1254jvanverth@google.com    if ( x > -0.5f ) {
6779c4e5ac5b7d32151d4d8ab1fb7ed443b35eb1254jvanverth@google.com        return 0.5f - (0.75f * x - x3 / 3.0f);
6787c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
6799c4e5ac5b7d32151d4d8ab1fb7ed443b35eb1254jvanverth@google.com    return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x);
6807c7292c6071898d73dc935c3b66b9816183806f0humper@google.com}
6817c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
6827c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com/*  compute_profile allocates and fills in an array of floating
6838ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com    point values between 0 and 255 for the profile signature of
6847c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    a blurred half-plane with the given blur radius.  Since we're
6857c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    going to be doing screened multiplications (i.e., 1 - (1-x)(1-y))
6867c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    all the time, we actually fill in the profile pre-inverted
6877c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    (already done 255-x).
6888ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
6897c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    It's the responsibility of the caller to delete the
6907c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    memory returned in profile_out.
6917c7292c6071898d73dc935c3b66b9816183806f0humper@google.com*/
6927c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
6937ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.comstatic void compute_profile(SkScalar sigma, unsigned int **profile_out) {
6947ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    int size = SkScalarCeilToInt(6*sigma);
6952e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
6967c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    int center = size >> 1;
69733cdbdea3ddcec9323b65eace86e10557312ae9bbsalomon@google.com    unsigned int *profile = SkNEW_ARRAY(unsigned int, size);
6987c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
6997ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    float invr = 1.f/(2*sigma);
7007c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
7017c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    profile[0] = 255;
702a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int x = 1 ; x < size ; ++x) {
703d98df1a3c468a2a7a5fff5efbf6dbdaf077d1abejvanverth@google.com        float scaled_x = (center - x - .5f) * invr;
704a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        float gi = gaussianIntegral(scaled_x);
705a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        profile[x] = 255 - (uint8_t) (255.f * gi);
7067c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
7077c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
7087c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    *profile_out = profile;
7097c7292c6071898d73dc935c3b66b9816183806f0humper@google.com}
7107c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
7118ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com// TODO MAYBE: Maintain a profile cache to avoid recomputing this for
7127c7292c6071898d73dc935c3b66b9816183806f0humper@google.com// commonly used radii.  Consider baking some of the most common blur radii
7137c7292c6071898d73dc935c3b66b9816183806f0humper@google.com// directly in as static data?
7147c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
7157c7292c6071898d73dc935c3b66b9816183806f0humper@google.com// Implementation adapted from Michael Herf's approach:
7167c7292c6071898d73dc935c3b66b9816183806f0humper@google.com// http://stereopsis.com/shadowrect/
7177c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
718a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.comstatic inline unsigned int profile_lookup( unsigned int *profile, int loc, int blurred_width, int sharp_width ) {
719a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int dx = SkAbs32(((loc << 1) + 1) - blurred_width) - sharp_width; // how far are we from the original edge?
720a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int ox = dx >> 1;
721a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (ox < 0) {
722a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        ox = 0;
723a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
724d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
725a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    return profile[ox];
726a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com}
727a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
7287c7292c6071898d73dc935c3b66b9816183806f0humper@google.combool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
7297ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                          SkScalar radius, Style style,
7307c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com                          SkIPoint *margin, SkMask::CreateMode createMode) {
7317ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius),
7327bd141dce43ea3405bc60c9c84e6f910b851b079skia.committer@gmail.com                                dst, src,
7337ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                                style, margin, createMode);
7347ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com}
7358ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
7367bd141dce43ea3405bc60c9c84e6f910b851b079skia.committer@gmail.combool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst,
7377ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                          const SkRect &src, Style style,
7387ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                          SkIPoint *margin, SkMask::CreateMode createMode) {
7397ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    int profile_size = SkScalarCeilToInt(6*sigma);
7402e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
741a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int pad = profile_size/2;
7427c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    if (margin) {
7437c7292c6071898d73dc935c3b66b9816183806f0humper@google.com        margin->set( pad, pad );
7447c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
745d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
7462e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com    dst->fBounds.set(SkScalarRoundToInt(src.fLeft - pad),
7472e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                     SkScalarRoundToInt(src.fTop - pad),
7482e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                     SkScalarRoundToInt(src.fRight + pad),
74968a690cb05d78060a95b1c8af0e60467740730a4humper@google.com                     SkScalarRoundToInt(src.fBottom + pad));
7508ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
7517c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    dst->fRowBytes = dst->fBounds.width();
7527c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    dst->fFormat = SkMask::kA8_Format;
7537c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    dst->fImage = NULL;
7542e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
7557c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    int             sw = SkScalarFloorToInt(src.width());
7567c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    int             sh = SkScalarFloorToInt(src.height());
7572e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
7587c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    if (createMode == SkMask::kJustComputeBounds_CreateMode) {
7597c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        if (style == kInner_Style) {
7602e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com            dst->fBounds.set(SkScalarRoundToInt(src.fLeft),
7612e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                             SkScalarRoundToInt(src.fTop),
7622e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                             SkScalarRoundToInt(src.fRight),
76368a690cb05d78060a95b1c8af0e60467740730a4humper@google.com                             SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds
7647c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com            dst->fRowBytes = sw;
7657c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        }
7667c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        return true;
7677c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    }
7687c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    unsigned int *profile = NULL;
7692e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
7707ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    compute_profile(sigma, &profile);
7717c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    SkAutoTDeleteArray<unsigned int> ada(profile);
7722e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
7737c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    size_t dstSize = dst->computeImageSize();
7747c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    if (0 == dstSize) {
7757c7292c6071898d73dc935c3b66b9816183806f0humper@google.com        return false;   // too big to allocate, abort
7767c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
7778ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
7787c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    uint8_t*        dp = SkMask::AllocImage(dstSize);
7798ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
7807c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    dst->fImage = dp;
7818ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
782a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int dstHeight = dst->fBounds.height();
783a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int dstWidth = dst->fBounds.width();
7848ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
7857c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    // nearest odd number less than the profile size represents the center
7867c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    // of the (2x scaled) profile
7877c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    int center = ( profile_size & ~1 ) - 1;
7888ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
7897c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    int w = sw - center;
7907c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    int h = sh - center;
7918ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
7927c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    uint8_t *outptr = dp;
793d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
794a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth);
7958ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
796a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int x = 0 ; x < dstWidth ; ++x) {
797a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        if (profile_size <= sw) {
798a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            horizontalScanline[x] = profile_lookup(profile, x, dstWidth, w);
799a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        } else {
8007ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com            float span = float(sw)/(2*sigma);
8017ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com            float giX = 1.5f - (x+.5f)/(2*sigma);
802a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span)));
803a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
804a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
805d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
806a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int y = 0 ; y < dstHeight ; ++y) {
807a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        unsigned int profile_y;
808a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        if (profile_size <= sh) {
809a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            profile_y = profile_lookup(profile, y, dstHeight, h);
810a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        } else {
8117ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com            float span = float(sh)/(2*sigma);
8127ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com            float giY = 1.5f - (y+.5f)/(2*sigma);
813a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIntegral(giY + span)));
814a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
8158ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
816a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int x = 0 ; x < dstWidth ; x++) {
817a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], profile_y);
818a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            *(outptr++) = maskval;
819a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
820a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
821d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
822a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (style == kInner_Style) {
823a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // now we allocate the "real" dst, mirror the size of src
824d98df1a3c468a2a7a5fff5efbf6dbdaf077d1abejvanverth@google.com        size_t srcSize = (size_t)(src.width() * src.height());
825a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        if (0 == srcSize) {
826a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            return false;   // too big to allocate, abort
827a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
828a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        dst->fImage = SkMask::AllocImage(srcSize);
829a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int y = 0 ; y < sh ; y++) {
830a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad;
831a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint8_t *inner_scanline = dst->fImage + y*sw;
832a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            memcpy(inner_scanline, blur_scanline, sw);
833a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
834a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        SkMask::FreeImage(dp);
835a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
8362e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com        dst->fBounds.set(SkScalarRoundToInt(src.fLeft),
8372e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                         SkScalarRoundToInt(src.fTop),
8382e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                         SkScalarRoundToInt(src.fRight),
83968a690cb05d78060a95b1c8af0e60467740730a4humper@google.com                         SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds
840a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        dst->fRowBytes = sw;
841d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
842a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    } else if (style == kOuter_Style) {
843a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int y = pad ; y < dstHeight-pad ; y++) {
844a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint8_t *dst_scanline = dp + y*dstWidth + pad;
845a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            memset(dst_scanline, 0, sw);
846a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
847d4d573057ee126bae354934b8d31f5695af387b6humper@google.com    } else if (style == kSolid_Style) {
848d4d573057ee126bae354934b8d31f5695af387b6humper@google.com        for (int y = pad ; y < dstHeight-pad ; y++) {
849d4d573057ee126bae354934b8d31f5695af387b6humper@google.com            uint8_t *dst_scanline = dp + y*dstWidth + pad;
850d4d573057ee126bae354934b8d31f5695af387b6humper@google.com            memset(dst_scanline, 0xff, sw);
8512e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com        }
852a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
853a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // normal and solid styles are the same for analytic rect blurs, so don't
854a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // need to handle solid specially.
8558ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
856a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    return true;
857a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com}
8588ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
8597ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.combool SkBlurMask::BlurGroundTruth(SkMask* dst, const SkMask& src, SkScalar radius,
8607ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                                 Style style, SkIPoint* margin) {
8617ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    return BlurGroundTruth(ConvertRadiusToSigma(radius), dst, src, style, margin);
8627ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com}
863a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com// The "simple" blur is a direct implementation of separable convolution with a discrete
864a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com// gaussian kernel.  It's "ground truth" in a sense; too slow to be used, but very
865a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com// useful for correctness comparisons.
8668ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
8677ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.combool SkBlurMask::BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src,
8687ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com                                 Style style, SkIPoint* margin) {
869d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
870a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (src.fFormat != SkMask::kA8_Format) {
871a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        return false;
872a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
8738ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
8747ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    float variance = sigma * sigma;
875a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
8767ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com    int windowSize = SkScalarCeil(sigma*4);
877a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // round window size up to nearest odd number
878a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    windowSize |= 1;
879a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
880a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    SkAutoTMalloc<float> gaussWindow(windowSize);
881a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
882a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int halfWindow = windowSize >> 1;
883d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
884a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    gaussWindow[halfWindow] = 1;
885d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
886a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    float windowSum = 1;
887a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int x = 1 ; x <= halfWindow ; ++x) {
888a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        float gaussian = expf(-x*x / variance);
889a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        gaussWindow[halfWindow + x] = gaussWindow[halfWindow-x] = gaussian;
890a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        windowSum += 2*gaussian;
891a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
892a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
893a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // leave the filter un-normalized for now; we will divide by the normalization
894a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // sum later;
895d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
896a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int pad = halfWindow;
897a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (margin) {
898a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        margin->set( pad, pad );
899a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
900a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
901a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    dst->fBounds = src.fBounds;
902a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    dst->fBounds.outset(pad, pad);
903a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
904a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    dst->fRowBytes = dst->fBounds.width();
905a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    dst->fFormat = SkMask::kA8_Format;
906a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    dst->fImage = NULL;
907a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
908a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (src.fImage) {
909a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
910a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        size_t dstSize = dst->computeImageSize();
911a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        if (0 == dstSize) {
912a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            return false;   // too big to allocate, abort
913a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
914d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
915a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int             srcWidth = src.fBounds.width();
916a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int             srcHeight = src.fBounds.height();
917a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int             dstWidth = dst->fBounds.width();
918d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
919a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        const uint8_t*  srcPixels = src.fImage;
920a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        uint8_t*        dstPixels = SkMask::AllocImage(dstSize);
921a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dstPixels);
922a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
923a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // do the actual blur.  First, make a padded copy of the source.
924a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // use double pad so we never have to check if we're outside anything
925d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
926a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int padWidth = srcWidth + 4*pad;
927a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int padHeight = srcHeight;
928a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int padSize = padWidth * padHeight;
929d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
930a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        SkAutoTMalloc<uint8_t> padPixels(padSize);
931a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        memset(padPixels, 0, padSize);
932d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
933a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int y = 0 ; y < srcHeight; ++y) {
934a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint8_t* padptr = padPixels + y * padWidth + 2*pad;
935a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            const uint8_t* srcptr = srcPixels + y * srcWidth;
936a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            memcpy(padptr, srcptr, srcWidth);
937a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
938d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
939a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // blur in X, transposing the result into a temporary floating point buffer.
940a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // also double-pad the intermediate result so that the second blur doesn't
941a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // have to do extra conditionals.
942d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
943a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int tmpWidth = padHeight + 4*pad;
944a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int tmpHeight = padWidth - 2*pad;
945a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int tmpSize = tmpWidth * tmpHeight;
946d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
947a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        SkAutoTMalloc<float> tmpImage(tmpSize);
948a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        memset(tmpImage, 0, tmpSize*sizeof(tmpImage[0]));
949a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
950a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int y = 0 ; y < padHeight ; ++y) {
951a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint8_t *srcScanline = padPixels + y*padWidth;
952a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            for (int x = pad ; x < padWidth - pad ; ++x) {
953a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                float *outPixel = tmpImage + (x-pad)*tmpWidth + y + 2*pad; // transposed output
954a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                uint8_t *windowCenter = srcScanline + x;
955a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                for (int i = -pad ; i <= pad ; ++i) {
956a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    *outPixel += gaussWindow[pad+i]*windowCenter[i];
957a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                }
958a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                *outPixel /= windowSum;
959d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com            }
960a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
961d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
962a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // blur in Y; now filling in the actual desired destination.  We have to do
963d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com        // the transpose again; these transposes guarantee that we read memory in
964a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // linear order.
965d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
966a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int y = 0 ; y < tmpHeight ; ++y) {
967a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            float *srcScanline = tmpImage + y*tmpWidth;
968a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            for (int x = pad ; x < tmpWidth - pad ; ++x) {
969a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                float *windowCenter = srcScanline + x;
970a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                float finalValue = 0;
971a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                for (int i = -pad ; i <= pad ; ++i) {
972a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    finalValue += gaussWindow[pad+i]*windowCenter[i];
973a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                }
974a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                finalValue /= windowSum;
975a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                uint8_t *outPixel = dstPixels + (x-pad)*dstWidth + y; // transposed output
976a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                int integerPixel = int(finalValue + 0.5f);
977a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                *outPixel = SkClampMax( SkClampPos(integerPixel), 255 );
978a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            }
979a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
980d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
981a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        dst->fImage = dstPixels;
982a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // if need be, alloc the "real" dst (same size as src) and copy/merge
983a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // the blur into it (applying the src)
984a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        if (style == kInner_Style) {
985a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            // now we allocate the "real" dst, mirror the size of src
986a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            size_t srcSize = src.computeImageSize();
987a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            if (0 == srcSize) {
988a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                return false;   // too big to allocate, abort
989a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            }
990a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            dst->fImage = SkMask::AllocImage(srcSize);
991a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            merge_src_with_blur(dst->fImage, src.fRowBytes,
992a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                srcPixels, src.fRowBytes,
993a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                dstPixels + pad*dst->fRowBytes + pad,
994a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                dst->fRowBytes, srcWidth, srcHeight);
995a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            SkMask::FreeImage(dstPixels);
996a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        } else if (style != kNormal_Style) {
997a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            clamp_with_orig(dstPixels + pad*dst->fRowBytes + pad,
998a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                dst->fRowBytes, srcPixels, src.fRowBytes, srcWidth, srcHeight, style);
9997c7292c6071898d73dc935c3b66b9816183806f0humper@google.com        }
1000a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        (void)autoCall.detach();
1001a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
1002a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1003a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (style == kInner_Style) {
1004a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        dst->fBounds = src.fBounds; // restore trimmed bounds
1005a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        dst->fRowBytes = src.fRowBytes;
10067c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
10078ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
10087c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    return true;
10097c7292c6071898d73dc935c3b66b9816183806f0humper@google.com}
1010