SkBlurMask.cpp revision 2e71f1619d9a2c51c1292e618f42a56ad2da1de8
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
158ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com// scale factor for the blur radius to match the behavior of the all existing blur
167c7292c6071898d73dc935c3b66b9816183806f0humper@google.com// code (both on the CPU and the GPU).  This magic constant is  1/sqrt(3).
177c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
188ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com// TODO: get rid of this fudge factor and move any required fudging up into
197c7292c6071898d73dc935c3b66b9816183806f0humper@google.com// the calling library
207c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
217c7292c6071898d73dc935c3b66b9816183806f0humper@google.com#define kBlurRadiusFudgeFactor SkFloatToScalar( .57735f )
227c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
239b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define UNROLL_SEPARABLE_LOOPS
249b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
25908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org/**
26908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org * This function performs a box blur in X, of the given radius.  If the
27884e60be30e20f38b3466a4697081187d2f1f814skia.committer@gmail.com * "transpose" parameter is true, it will transpose the pixels on write,
28908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org * such that X and Y are swapped. Reads are always performed from contiguous
29908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org * memory in X, for speed. The destination buffer (dst) must be at least
309b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org * (width + leftRadius + rightRadius) * height bytes in size.
314a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *
324a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org * This is what the inner loop looks like before unrolling, and with the two
334a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org * cases broken out separately (width < diameter, width >= diameter):
3476bf70d38fd109a09ee44d074cfd392e1884afffskia.committer@gmail.com *
354a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      if (width < diameter) {
364a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < width; ++x) {
374a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum += *right++;
3876bf70d38fd109a09ee44d074cfd392e1884afffskia.committer@gmail.com *              *dptr = (sum * scale + half) >> 24;
394a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
404a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
414a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = width; x < diameter; ++x) {
424a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (sum * scale + half) >> 24;
434a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
444a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
454a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < width; ++x) {
464a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (sum * scale + half) >> 24;
474a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum -= *left++;
484a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
494a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
504a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      } else {
514a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < diameter; ++x) {
524a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum += *right++;
534a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (sum * scale + half) >> 24;
544a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
554a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
564a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = diameter; x < width; ++x) {
574a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum += *right++;
584a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (sum * scale + half) >> 24;
594a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum -= *left++;
604a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
614a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
624a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < diameter; ++x) {
634a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (sum * scale + half) >> 24;
644a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              sum -= *left++;
654a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
664a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
674a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      }
68908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org */
69908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.orgstatic int boxBlur(const uint8_t* src, int src_y_stride, uint8_t* dst,
70c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org                   int leftRadius, int rightRadius, int width, int height,
71c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org                   bool transpose)
7271f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org{
739b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int diameter = leftRadius + rightRadius;
749b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int kernelSize = diameter + 1;
759b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int border = SkMin32(width, diameter);
7671f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org    uint32_t scale = (1 << 24) / kernelSize;
77c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org    int new_width = width + SkMax32(leftRadius, rightRadius) * 2;
78908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org    int dst_x_stride = transpose ? height : 1;
79908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org    int dst_y_stride = transpose ? 1 : new_width;
804a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#ifndef SK_DISABLE_BLUR_ROUNDING
814a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org    uint32_t half = 1 << 23;
824a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#else
834a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org    uint32_t half = 0;
844a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#endif
8571f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org    for (int y = 0; y < height; ++y) {
864a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org        uint32_t sum = 0;
87908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org        uint8_t* dptr = dst + y * dst_y_stride;
88908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org        const uint8_t* right = src + y * src_y_stride;
89908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org        const uint8_t* left = right;
90336b4da6b0d20f27f9980b03415354a2f0698e18senorblanco@chromium.org        for (int x = 0; x < rightRadius - leftRadius; x++) {
91336b4da6b0d20f27f9980b03415354a2f0698e18senorblanco@chromium.org            *dptr = 0;
92336b4da6b0d20f27f9980b03415354a2f0698e18senorblanco@chromium.org            dptr += dst_x_stride;
93c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org        }
949b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define LEFT_BORDER_ITER \
959b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            sum += *right++; \
964a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (sum * scale + half) >> 24; \
97908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org            dptr += dst_x_stride;
989b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
999b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        int x = 0;
1009b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
1019b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < border - 16; x += 16) {
1029b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1039b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1049b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1059b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1069b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1079b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
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
11871f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        }
1199b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
1209b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < border; ++x) {
1219b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
1229b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
1239b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef LEFT_BORDER_ITER
1249b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define TRIVIAL_ITER \
1254a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (sum * scale + half) >> 24; \
126908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org            dptr += dst_x_stride;
1279b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        x = width;
1289b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
1299b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < diameter - 16; x += 16) {
1309b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1319b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1329b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1339b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1349b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
1359b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
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        }
1479b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
1489b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < diameter; ++x) {
1499b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            TRIVIAL_ITER
15071f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        }
1519b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef TRIVIAL_ITER
1529b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define CENTER_ITER \
1539b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            sum += *right++; \
1544a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (sum * scale + half) >> 24; \
1559b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            sum -= *left++; \
156908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org            dptr += dst_x_stride;
1579b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
1589b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        x = diameter;
1599b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
1609b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < width - 16; x += 16) {
1619b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1629b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1639b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1649b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1659b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
1669b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
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        }
1789b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
1799b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < width; ++x) {
1809b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
18171f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        }
1829b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef CENTER_ITER
1839b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define RIGHT_BORDER_ITER \
1844a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (sum * scale + half) >> 24; \
1859b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            sum -= *left++; \
186908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org            dptr += dst_x_stride;
1879b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
1889b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        x = 0;
1899b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
1909b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < border - 16; x += 16) {
1919b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
1929b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
1939b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
1949b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
1959b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
1969b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
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        }
2089b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
2099b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < border; ++x) {
2109b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
21171f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        }
2129b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef RIGHT_BORDER_ITER
213a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int x = 0; x < leftRadius - rightRadius; ++x) {
214336b4da6b0d20f27f9980b03415354a2f0698e18senorblanco@chromium.org            *dptr = 0;
215336b4da6b0d20f27f9980b03415354a2f0698e18senorblanco@chromium.org            dptr += dst_x_stride;
216c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org        }
21771f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        SkASSERT(sum == 0);
21871f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org    }
219908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org    return new_width;
22071f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org}
22171f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org
2229b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org/**
2239b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org * This variant of the box blur handles blurring of non-integer radii.  It
2249b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org * keeps two running sums: an outer sum for the rounded-up kernel radius, and
2259b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org * an inner sum for the rounded-down kernel radius.  For each pixel, it linearly
2269b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org * interpolates between them.  In float this would be:
2279b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org *  outer_weight * outer_sum / kernelSize +
2289b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org *  (1.0 - outer_weight) * innerSum / (kernelSize - 2)
22976bf70d38fd109a09ee44d074cfd392e1884afffskia.committer@gmail.com *
2304a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org * This is what the inner loop looks like before unrolling, and with the two
2314a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org * cases broken out separately (width < diameter, width >= diameter):
23276bf70d38fd109a09ee44d074cfd392e1884afffskia.committer@gmail.com *
2334a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      if (width < diameter) {
2344a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < width; x++) {
2354a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              inner_sum = outer_sum;
2364a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              outer_sum += *right++;
2374a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
2384a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
2394a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2404a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = width; x < diameter; ++x) {
2414a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
2424a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
2434a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2444a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < width; x++) {
2454a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              inner_sum = outer_sum - *left++;
2464a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
2474a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
2484a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              outer_sum = inner_sum;
2494a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2504a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      } else {
2514a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < diameter; x++) {
2524a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              inner_sum = outer_sum;
2534a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              outer_sum += *right++;
2544a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
2554a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              dptr += dst_x_stride;
2564a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2574a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = diameter; x < width; ++x) {
2584a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              inner_sum = outer_sum - *left;
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 *              outer_sum -= *left++;
2634a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2644a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          for (int x = 0; x < diameter; x++) {
2654a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *              inner_sum = outer_sum - *left++;
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 = inner_sum;
2694a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *          }
2704a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *      }
2714a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *  }
2724a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org *  return new_width;
2739b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org */
2744a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org
2759b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.orgstatic int boxBlurInterp(const uint8_t* src, int src_y_stride, uint8_t* dst,
2769b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org                         int radius, int width, int height,
2779b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org                         bool transpose, uint8_t outer_weight)
2789b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org{
2799b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int diameter = radius * 2;
2809b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int kernelSize = diameter + 1;
2819b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int border = SkMin32(width, diameter);
2829b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int inner_weight = 255 - outer_weight;
2839b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    outer_weight += outer_weight >> 7;
2849b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    inner_weight += inner_weight >> 7;
2859b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    uint32_t outer_scale = (outer_weight << 16) / kernelSize;
2869b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    uint32_t inner_scale = (inner_weight << 16) / (kernelSize - 2);
2874a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#ifndef SK_DISABLE_BLUR_ROUNDING
2884a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org    uint32_t half = 1 << 23;
2894a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#else
2904a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org    uint32_t half = 0;
2914a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org#endif
2929b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int new_width = width + diameter;
2939b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int dst_x_stride = transpose ? height : 1;
2949b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    int dst_y_stride = transpose ? 1 : new_width;
2959b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    for (int y = 0; y < height; ++y) {
2964a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org        uint32_t outer_sum = 0, inner_sum = 0;
2979b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        uint8_t* dptr = dst + y * dst_y_stride;
2989b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        const uint8_t* right = src + y * src_y_stride;
2999b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        const uint8_t* left = right;
3009b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        int x = 0;
3019b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3029b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define LEFT_BORDER_ITER \
3039b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            inner_sum = outer_sum; \
3049b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            outer_sum += *right++; \
3054a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24; \
3069b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            dptr += dst_x_stride;
3079b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3089b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
3099b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (;x < border - 16; x += 16) {
3109b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3119b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3129b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3139b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3149b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3159b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
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        }
3279b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
3289b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
329a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (;x < border; ++x) {
3309b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            LEFT_BORDER_ITER
3319b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
3329b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef LEFT_BORDER_ITER
3339b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (int x = width; x < diameter; ++x) {
3344a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24;
3359b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            dptr += dst_x_stride;
3369b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
3379b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        x = diameter;
3389b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3399b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#define CENTER_ITER \
3409b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            inner_sum = outer_sum - *left; \
3419b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            outer_sum += *right++; \
3424a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24; \
3439b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            dptr += dst_x_stride; \
3449b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            outer_sum -= *left++;
3459b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3469b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
3479b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < width - 16; x += 16) {
3489b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3499b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3509b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3519b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3529b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3539b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
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        }
3659b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
3669b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < width; ++x) {
3679b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            CENTER_ITER
3689b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
3699b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef CENTER_ITER
3709b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3719b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        #define RIGHT_BORDER_ITER \
3729b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            inner_sum = outer_sum - *left++; \
3734a525d7fc2cc0d8029bc66095730ddba3df3cb9esenorblanco@chromium.org            *dptr = (outer_sum * outer_scale + inner_sum * inner_scale + half) >> 24; \
3749b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            dptr += dst_x_stride; \
3759b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            outer_sum = inner_sum;
3769b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
3779b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        x = 0;
3789b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#ifdef UNROLL_SEPARABLE_LOOPS
3799b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        for (; x < border - 16; x += 16) {
3809b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3819b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3829b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3839b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3849b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
3859b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
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        }
3979b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#endif
398a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (; x < border; ++x) {
3999b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org            RIGHT_BORDER_ITER
4009b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        }
4019b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org#undef RIGHT_BORDER_ITER
4029b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org        SkASSERT(outer_sum == 0 && inner_sum == 0);
4039b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    }
4049b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org    return new_width;
4059b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org}
4069b0d4d79f023ce91b53d9eaa47508b6722c246e6senorblanco@chromium.org
407c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.orgstatic void get_adjusted_radii(SkScalar passRadius, int *loRadius, int *hiRadius)
408c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org{
409c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org    *loRadius = *hiRadius = SkScalarCeil(passRadius);
410c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org    if (SkIntToScalar(*hiRadius) - passRadius > SkFloatToScalar(0.5f)) {
411c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org        *loRadius = *hiRadius - 1;
412c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org    }
413c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org}
414c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org
41501224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com// Unrolling the integer blur kernel seems to give us a ~15% speedup on Windows,
41601224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com// breakeven on Mac, and ~15% slowdown on Linux.
41701224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com// Reading a word at a time when bulding the sum buffer seems to give
41801224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com// us no appreciable speedup on Windows or Mac, and 2% slowdown on Linux.
419054ff1efa4f9187ce7fd20aaf3aed7cecf14e12btomhudson@google.com#if defined(SK_BUILD_FOR_WIN32)
42001224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com#define UNROLL_KERNEL_LOOP 1
42101224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com#endif
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4234560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com/** The sum buffer is an array of u32 to hold the accumulated sum of all of the
4244560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    src values at their position, plus all values above and to the left.
4254560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    When we sample into this buffer, we need an initial row and column of 0s,
4264560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    so we have an index correspondence as follows:
427fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4284560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    src[i, j] == sum[i+1, j+1]
4294560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    sum[0, j] == sum[i, 0] == 0
430fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4314560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    We assume that the sum buffer's stride == its width
4324560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com */
43303016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.comstatic void build_sum_buffer(uint32_t sum[], int srcW, int srcH,
43403016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                             const uint8_t src[], int srcRB) {
4354560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    int sumW = srcW + 1;
4364560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com
4374560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    SkASSERT(srcRB >= srcW);
4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // mod srcRB so we can apply it after each row
4394560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    srcRB -= srcW;
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int x, y;
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4434560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    // zero out the top row and column
4444560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    memset(sum, 0, sumW * sizeof(sum[0]));
4454560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    sum += sumW;
4464560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com
4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // special case first row
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t X = 0;
4494560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    *sum++ = 0; // initialze the first column to 0
45003016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com    for (x = srcW - 1; x >= 0; --x) {
4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        X = *src++ + X;
4524560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        *sum++ = X;
4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    src += srcRB;
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // now do the rest of the rows
45703016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com    for (y = srcH - 1; y > 0; --y) {
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        uint32_t L = 0;
4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        uint32_t C = 0;
4604560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        *sum++ = 0; // initialze the first column to 0
46101224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com
46201224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        for (x = srcW - 1; !SkIsAlign4((intptr_t) src) && x >= 0; x--) {
46301224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            uint32_t T = sum[-sumW];
46401224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            X = *src++ + L + T - C;
46501224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            *sum++ = X;
46601224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            L = X;
46701224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            C = T;
46801224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        }
46901224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com
47001224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        for (; x >= 4; x-=4) {
47101224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            uint32_t T = sum[-sumW];
47201224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            X = *src++ + L + T - C;
47301224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            *sum++ = X;
47401224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            L = X;
47501224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            C = T;
47601224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            T = sum[-sumW];
47701224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            X = *src++ + L + T - C;
47801224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            *sum++ = X;
47901224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            L = X;
48001224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            C = T;
48101224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            T = sum[-sumW];
48201224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            X = *src++ + L + T - C;
48301224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            *sum++ = X;
48401224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            L = X;
48501224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            C = T;
48601224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            T = sum[-sumW];
48701224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            X = *src++ + L + T - C;
48801224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            *sum++ = X;
48901224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            L = X;
49001224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            C = T;
49101224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        }
49201224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com
49301224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        for (; x >= 0; --x) {
4944560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com            uint32_t T = sum[-sumW];
4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            X = *src++ + L + T - C;
4964560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com            *sum++ = X;
4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            L = X;
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            C = T;
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        src += srcRB;
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
50403016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com/**
5058caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com * This is the path for apply_kernel() to be taken when the kernel
5068caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com * is wider than the source image.
5078caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com */
5088caac6447dd68655b57dfe876626a9733b191416tomhudson@google.comstatic void kernel_clamped(uint8_t dst[], int rx, int ry, const uint32_t sum[],
5098caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com                           int sw, int sh) {
5108caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    SkASSERT(2*rx > sw);
5118caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
5128caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    uint32_t scale = (1 << 24) / ((2*rx + 1)*(2*ry + 1));
5138caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
5148caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    int sumStride = sw + 1;
5158caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
5168caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    int dw = sw + 2*rx;
5178caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    int dh = sh + 2*ry;
5188caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
5198caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    int prev_y = -2*ry;
5208caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    int next_y = 1;
5218caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
522a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int y = 0; y < dh; ++y) {
5238caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int py = SkClampPos(prev_y) * sumStride;
5248caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int ny = SkFastMin32(next_y, sh) * sumStride;
5258caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
5268caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int prev_x = -2*rx;
5278caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int next_x = 1;
5288caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
529a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int x = 0; x < dw; ++x) {
5308caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int px = SkClampPos(prev_x);
5318caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int nx = SkFastMin32(next_x, sw);
5328caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
533a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            // TODO: should we be adding 1/2 (1 << 23) to round to the
534a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            // nearest integer here?
5358caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
5368caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            *dst++ = SkToU8(tmp * scale >> 24);
5378caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
5388caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            prev_x += 1;
5398caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            next_x += 1;
5408caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        }
5418caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
5428caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        prev_y += 1;
5438caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        next_y += 1;
5448caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    }
5458caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com}
5468caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com/**
54703016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com *  sw and sh are the width and height of the src. Since the sum buffer
54803016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com *  matches that, but has an extra row and col at the beginning (with zeros),
54903016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com *  we can just use sw and sh as our "max" values for pinning coordinates
55003016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com *  when sampling into sum[][]
5518caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com *
5528caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com *  The inner loop is conceptually simple; we break it into several sections
5538caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com *  to improve performance. Here's the original version:
554a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int x = 0; x < dw; ++x) {
5558caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int px = SkClampPos(prev_x);
5568caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int nx = SkFastMin32(next_x, sw);
5578caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
5588caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
5598caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            *dst++ = SkToU8(tmp * scale >> 24);
5608caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
5618caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            prev_x += 1;
5628caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            next_x += 1;
5638caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        }
56401224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *  The sections are:
56501224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *     left-hand section, where prev_x is clamped to 0
56601224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *     center section, where neither prev_x nor next_x is clamped
56701224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *     right-hand section, where next_x is clamped to sw
56801224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *  On some operating systems, the center section is unrolled for additional
56901224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *  speedup.
5708caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com*/
5714560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.comstatic void apply_kernel(uint8_t dst[], int rx, int ry, const uint32_t sum[],
5724560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com                         int sw, int sh) {
5738caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    if (2*rx > sw) {
5748caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        kernel_clamped(dst, rx, ry, sum, sw, sh);
5758caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        return;
5768caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    }
5778caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
5788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t scale = (1 << 24) / ((2*rx + 1)*(2*ry + 1));
5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5804560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    int sumStride = sw + 1;
5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int dw = sw + 2*rx;
5838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int dh = sh + 2*ry;
5848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5854560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    int prev_y = -2*ry;
5864560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    int next_y = 1;
5878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5888caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    SkASSERT(2*rx <= dw - 2*rx);
5898caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
590a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int y = 0; y < dh; ++y) {
5914560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        int py = SkClampPos(prev_y) * sumStride;
5924560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        int ny = SkFastMin32(next_y, sh) * sumStride;
5938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5944560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        int prev_x = -2*rx;
5954560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        int next_x = 1;
5968caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int x = 0;
5978caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
598a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (; x < 2*rx; ++x) {
5998caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(prev_x <= 0);
6008caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(next_x <= sw);
6018caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6028caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int px = 0;
6038caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int nx = next_x;
6048caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6058caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
6068caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            *dst++ = SkToU8(tmp * scale >> 24);
6078caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6088caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            prev_x += 1;
6098caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            next_x += 1;
6108caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        }
6118caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
61201224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i0 = prev_x + py;
61301224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i1 = next_x + ny;
61401224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i2 = next_x + py;
61501224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i3 = prev_x + ny;
61601224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com
61701224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com#if UNROLL_KERNEL_LOOP
61801224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        for (; x < dw - 2*rx - 4; x += 4) {
6198caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(prev_x >= 0);
6208caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(next_x <= sw);
6218caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
62201224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            uint32_t tmp = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
62301224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            *dst++ = SkToU8(tmp * scale >> 24);
62401224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            tmp = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
62501224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            *dst++ = SkToU8(tmp * scale >> 24);
62601224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            tmp = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
62701224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            *dst++ = SkToU8(tmp * scale >> 24);
62801224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            tmp = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
62901224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            *dst++ = SkToU8(tmp * scale >> 24);
6308caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
63101224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            prev_x += 4;
63201224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            next_x += 4;
63301224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        }
63401224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com#endif
63501224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com
636a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (; x < dw - 2*rx; ++x) {
63701224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            SkASSERT(prev_x >= 0);
63801224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            SkASSERT(next_x <= sw);
63901224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com
64001224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            uint32_t tmp = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
6418caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            *dst++ = SkToU8(tmp * scale >> 24);
6428caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6438caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            prev_x += 1;
6448caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            next_x += 1;
6458caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        }
6468caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
647a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (; x < dw; ++x) {
6488caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(prev_x >= 0);
6498caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(next_x > sw);
6508caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6518caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int px = prev_x;
6528caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int nx = sw;
6538caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6548caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
6558caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            *dst++ = SkToU8(tmp * scale >> 24);
6568caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6578caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            prev_x += 1;
6588caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            next_x += 1;
6598caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        }
6608caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6618caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        prev_y += 1;
6628caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        next_y += 1;
6638caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    }
6648caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com}
6658caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6668caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com/**
6678caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com * This is the path for apply_kernel_interp() to be taken when the kernel
6688caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com * is wider than the source image.
6698caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com */
6708caac6447dd68655b57dfe876626a9733b191416tomhudson@google.comstatic void kernel_interp_clamped(uint8_t dst[], int rx, int ry,
671a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                const uint32_t sum[], int sw, int sh, U8CPU outerWeight) {
6728caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    SkASSERT(2*rx > sw);
6738caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
674a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int innerWeight = 255 - outerWeight;
6758caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6768caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    // round these guys up if they're bigger than 127
677a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    outerWeight += outerWeight >> 7;
678a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    innerWeight += innerWeight >> 7;
6798caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
680a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    uint32_t outerScale = (outerWeight << 16) / ((2*rx + 1)*(2*ry + 1));
681a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    uint32_t innerScale = (innerWeight << 16) / ((2*rx - 1)*(2*ry - 1));
6828caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6838caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    int sumStride = sw + 1;
6848caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6858caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    int dw = sw + 2*rx;
6868caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    int dh = sh + 2*ry;
6878caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6888caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    int prev_y = -2*ry;
6898caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    int next_y = 1;
6908caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
691a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int y = 0; y < dh; ++y) {
6928caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int py = SkClampPos(prev_y) * sumStride;
6938caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int ny = SkFastMin32(next_y, sh) * sumStride;
6948caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6958caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int ipy = SkClampPos(prev_y + 1) * sumStride;
6968caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int iny = SkClampMax(next_y - 1, sh) * sumStride;
6978caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
6988caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int prev_x = -2*rx;
6998caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int next_x = 1;
7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
701a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int x = 0; x < dw; ++x) {
7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int px = SkClampPos(prev_x);
7038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int nx = SkFastMin32(next_x, sw);
7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7058caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int ipx = SkClampPos(prev_x + 1);
7068caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int inx = SkClampMax(next_x - 1, sw);
7078caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
708a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t outerSum = sum[px+py] + sum[nx+ny]
7098caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com                               - sum[nx+py] - sum[px+ny];
710a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t innerSum = sum[ipx+ipy] + sum[inx+iny]
7118caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com                               - sum[inx+ipy] - sum[ipx+iny];
712a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            *dst++ = SkToU8((outerSum * outerScale
713a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                           + innerSum * innerScale) >> 24);
7148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            prev_x += 1;
7168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            next_x += 1;
7178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
7188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prev_y += 1;
7198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        next_y += 1;
7208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
72303016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com/**
72403016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com *  sw and sh are the width and height of the src. Since the sum buffer
72503016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com *  matches that, but has an extra row and col at the beginning (with zeros),
72603016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com *  we can just use sw and sh as our "max" values for pinning coordinates
72703016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com *  when sampling into sum[][]
7288caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com *
7298caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com *  The inner loop is conceptually simple; we break it into several variants
7308caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com *  to improve performance. Here's the original version:
731a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int x = 0; x < dw; ++x) {
7328caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int px = SkClampPos(prev_x);
7338caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int nx = SkFastMin32(next_x, sw);
7348caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
7358caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int ipx = SkClampPos(prev_x + 1);
7368caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int inx = SkClampMax(next_x - 1, sw);
7378caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
738a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t outerSum = sum[px+py] + sum[nx+ny]
7398caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com                               - sum[nx+py] - sum[px+ny];
740a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t innerSum = sum[ipx+ipy] + sum[inx+iny]
7418caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com                               - sum[inx+ipy] - sum[ipx+iny];
742a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            *dst++ = SkToU8((outerSum * outerScale
743a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                           + innerSum * innerScale) >> 24);
7448caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
7458caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            prev_x += 1;
7468caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            next_x += 1;
7478caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        }
74801224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *  The sections are:
74901224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *     left-hand section, where prev_x is clamped to 0
75001224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *     center section, where neither prev_x nor next_x is clamped
75101224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *     right-hand section, where next_x is clamped to sw
75201224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *  On some operating systems, the center section is unrolled for additional
75301224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com *  speedup.
7548caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com*/
7554560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.comstatic void apply_kernel_interp(uint8_t dst[], int rx, int ry,
756a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                const uint32_t sum[], int sw, int sh, U8CPU outerWeight) {
7578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(rx > 0 && ry > 0);
758a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    SkASSERT(outerWeight <= 255);
7598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7608caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    if (2*rx > sw) {
761a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        kernel_interp_clamped(dst, rx, ry, sum, sw, sh, outerWeight);
7628caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        return;
7638caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    }
7648caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
765a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int innerWeight = 255 - outerWeight;
7668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // round these guys up if they're bigger than 127
768a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    outerWeight += outerWeight >> 7;
769a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    innerWeight += innerWeight >> 7;
7708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
771a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    uint32_t outerScale = (outerWeight << 16) / ((2*rx + 1)*(2*ry + 1));
772a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    uint32_t innerScale = (innerWeight << 16) / ((2*rx - 1)*(2*ry - 1));
7738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7744560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    int sumStride = sw + 1;
7758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int dw = sw + 2*rx;
7778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int dh = sh + 2*ry;
7788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7794560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    int prev_y = -2*ry;
7804560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com    int next_y = 1;
7818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7828caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com    SkASSERT(2*rx <= dw - 2*rx);
7838caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
784a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int y = 0; y < dh; ++y) {
7854560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        int py = SkClampPos(prev_y) * sumStride;
7864560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        int ny = SkFastMin32(next_y, sh) * sumStride;
7878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7884560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        int ipy = SkClampPos(prev_y + 1) * sumStride;
7894560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        int iny = SkClampMax(next_y - 1, sh) * sumStride;
7908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7914560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        int prev_x = -2*rx;
7924560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com        int next_x = 1;
7938caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        int x = 0;
7948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
795a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (; x < 2*rx; ++x) {
7968caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(prev_x < 0);
7978caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(next_x <= sw);
7988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7998caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int px = 0;
8008caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int nx = next_x;
8018caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
8028caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int ipx = 0;
8038caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int inx = next_x - 1;
8048caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
805a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t outerSum = sum[px+py] + sum[nx+ny]
8068caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com                               - sum[nx+py] - sum[px+ny];
807a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t innerSum = sum[ipx+ipy] + sum[inx+iny]
8088caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com                               - sum[inx+ipy] - sum[ipx+iny];
809a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            *dst++ = SkToU8((outerSum * outerScale
810a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                           + innerSum * innerScale) >> 24);
8118caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
8128caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            prev_x += 1;
8138caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            next_x += 1;
8148caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        }
8158caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
81601224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i0 = prev_x + py;
81701224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i1 = next_x + ny;
81801224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i2 = next_x + py;
81901224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i3 = prev_x + ny;
82001224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i4 = prev_x + 1 + ipy;
82101224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i5 = next_x - 1 + iny;
82201224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i6 = next_x - 1 + ipy;
82301224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        int i7 = prev_x + 1 + iny;
82401224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com
82501224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com#if UNROLL_KERNEL_LOOP
82601224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        for (; x < dw - 2*rx - 4; x += 4) {
8278caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(prev_x >= 0);
8288caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(next_x <= sw);
8298caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
830a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t outerSum = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
831a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t innerSum = sum[i4++] + sum[i5++] - sum[i6++] - sum[i7++];
832a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            *dst++ = SkToU8((outerSum * outerScale
833a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                           + innerSum * innerScale) >> 24);
834a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            outerSum = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
835a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            innerSum = sum[i4++] + sum[i5++] - sum[i6++] - sum[i7++];
836a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            *dst++ = SkToU8((outerSum * outerScale
837a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                           + innerSum * innerScale) >> 24);
838a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            outerSum = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
839a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            innerSum = sum[i4++] + sum[i5++] - sum[i6++] - sum[i7++];
840a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            *dst++ = SkToU8((outerSum * outerScale
841a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                           + innerSum * innerScale) >> 24);
842a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            outerSum = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
843a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            innerSum = sum[i4++] + sum[i5++] - sum[i6++] - sum[i7++];
844a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            *dst++ = SkToU8((outerSum * outerScale
845a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                           + innerSum * innerScale) >> 24);
8468caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
84701224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            prev_x += 4;
84801224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            next_x += 4;
84901224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com        }
85001224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com#endif
8518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
852a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (; x < dw - 2*rx; ++x) {
85301224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            SkASSERT(prev_x >= 0);
85401224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com            SkASSERT(next_x <= sw);
85501224d5d0a3228fe47e63d8346e0e433a87563a8tomhudson@google.com
856a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t outerSum = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
857a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t innerSum = sum[i4++] + sum[i5++] - sum[i6++] - sum[i7++];
858a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            *dst++ = SkToU8((outerSum * outerScale
859a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                           + innerSum * innerScale) >> 24);
8608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            prev_x += 1;
8628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            next_x += 1;
8638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
8648caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
865a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (; x < dw; ++x) {
8668caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(prev_x >= 0);
8678caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            SkASSERT(next_x > sw);
8688caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
8698caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int px = prev_x;
8708caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int nx = sw;
8718caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
8728caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int ipx = prev_x + 1;
8738caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            int inx = sw;
8748caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
875a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t outerSum = sum[px+py] + sum[nx+ny]
8768caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com                               - sum[nx+py] - sum[px+ny];
877a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint32_t innerSum = sum[ipx+ipy] + sum[inx+iny]
8788caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com                               - sum[inx+ipy] - sum[ipx+iny];
879a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            *dst++ = SkToU8((outerSum * outerScale
880a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                           + innerSum * innerScale) >> 24);
8818caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
8828caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            prev_x += 1;
8838caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com            next_x += 1;
8848caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com        }
8858caac6447dd68655b57dfe876626a9733b191416tomhudson@google.com
8868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prev_y += 1;
8878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        next_y += 1;
8888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
8928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8930e3c664250f561ec9f7107b92136517a72d03afdreed@android.comstatic void merge_src_with_blur(uint8_t dst[], int dstRB,
8940e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                                const uint8_t src[], int srcRB,
8950e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                                const uint8_t blur[], int blurRB,
8960e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                                int sw, int sh) {
8970e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    dstRB -= sw;
8980e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    srcRB -= sw;
8990e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    blurRB -= sw;
9000e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    while (--sh >= 0) {
9010e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        for (int x = sw - 1; x >= 0; --x) {
9028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *dst = SkToU8(SkAlphaMul(*blur, SkAlpha255To256(*src)));
9038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst += 1;
9048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            src += 1;
9058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            blur += 1;
9068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
9070e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        dst += dstRB;
9080e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        src += srcRB;
9090e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        blur += blurRB;
9108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void clamp_with_orig(uint8_t dst[], int dstRowBytes,
9140e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                            const uint8_t src[], int srcRowBytes,
9150e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                            int sw, int sh,
9164560767bb0b3db530d48e2b0c1c11e28f3692984reed@android.com                            SkBlurMask::Style style) {
9178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int x;
9180e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    while (--sh >= 0) {
9198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        switch (style) {
9208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkBlurMask::kSolid_Style:
9210e3c664250f561ec9f7107b92136517a72d03afdreed@android.com            for (x = sw - 1; x >= 0; --x) {
9220e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                int s = *src;
9230e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                int d = *dst;
9240e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                *dst = SkToU8(s + d - SkMulDiv255Round(s, d));
9258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                dst += 1;
9268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                src += 1;
9278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
9288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
9298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkBlurMask::kOuter_Style:
9300e3c664250f561ec9f7107b92136517a72d03afdreed@android.com            for (x = sw - 1; x >= 0; --x) {
9310e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                if (*src) {
9328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src)));
9330e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                }
9348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                dst += 1;
9358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                src += 1;
9368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
9378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
9388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        default:
9390c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com            SkDEBUGFAIL("Unexpected blur style here");
9408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
9418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
9428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst += dstRowBytes - sw;
9430e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        src += srcRowBytes - sw;
9448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
94703016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com///////////////////////////////////////////////////////////////////////////////
9488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
94933cdbdea3ddcec9323b65eace86e10557312ae9bbsalomon@google.com// we use a local function to wrap the class static method to work around
9508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// a bug in gcc98
9518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMask_FreeImage(uint8_t* image);
95203016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.comvoid SkMask_FreeImage(uint8_t* image) {
9538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMask::FreeImage(image);
9548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
9575af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                      SkScalar radius, Style style, Quality quality,
95871f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org                      SkIPoint* margin, bool separable)
9595af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com{
960a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
96103016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com    if (src.fFormat != SkMask::kA8_Format) {
9628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
96303016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com    }
9648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9654868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    // Force high quality off for small radii (performance)
96691f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org    if (radius < SkIntToScalar(3)) {
96791f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org        quality = kLow_Quality;
96891f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org    }
969d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
970d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com    // highQuality: use three box blur passes as a cheap way
971a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // to approximate a Gaussian blur
97291f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org    int passCount = (kHigh_Quality == quality) ? 3 : 1;
973d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com    SkScalar passRadius = (kHigh_Quality == quality) ?
974d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com                          SkScalarMul( radius, kBlurRadiusFudgeFactor):
975a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                          radius;
976a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
9774868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    int rx = SkScalarCeil(passRadius);
978a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int outerWeight = 255 - SkScalarRound((SkIntToScalar(rx) - passRadius) * 255);
9798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(rx >= 0);
981a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    SkASSERT((unsigned)outerWeight <= 255);
9820e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    if (rx <= 0) {
9838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
9840e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    }
9858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int ry = rx;    // only do square blur for now
9878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9884868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    int padx = passCount * rx;
9894868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    int pady = passCount * ry;
990d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
9915af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    if (margin) {
9925af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        margin->set(padx, pady);
9935af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    }
9944868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady,
9954868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org        src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
996d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
99749f0ff25a046d6001dc2d095b6fa3c30f0f46b6areed@android.com    dst->fRowBytes = dst->fBounds.width();
9988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fFormat = SkMask::kA8_Format;
9998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fImage = NULL;
10008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10010e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    if (src.fImage) {
1002543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        size_t dstSize = dst->computeImageSize();
1003543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        if (0 == dstSize) {
1004543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            return false;   // too big to allocate, abort
1005543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        }
1006543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com
10078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int             sw = src.fBounds.width();
10088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int             sh = src.fBounds.height();
10098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const uint8_t*  sp = src.fImage;
1010543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        uint8_t*        dp = SkMask::AllocImage(dstSize);
10118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp);
10128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // build the blurry destination
101471f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        if (separable) {
101571f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org            SkAutoTMalloc<uint8_t>  tmpBuffer(dstSize);
101671f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org            uint8_t*                tp = tmpBuffer.get();
101771f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org            int w = sw, h = sh;
1018d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1019a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            if (outerWeight == 255) {
1020c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org                int loRadius, hiRadius;
1021c4381309649c5cf338dcf6a7fc8296451a686d6bsenorblanco@chromium.org                get_adjusted_radii(passRadius, &loRadius, &hiRadius);
102291f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                if (kHigh_Quality == quality) {
102391f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    // Do three X blurs, with a transpose on the final one.
102491f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    w = boxBlur(sp, src.fRowBytes, tp, loRadius, hiRadius, w, h, false);
102591f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    w = boxBlur(tp, w,             dp, hiRadius, loRadius, w, h, false);
102691f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    w = boxBlur(dp, w,             tp, hiRadius, hiRadius, w, h, true);
102791f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    // Do three Y blurs, with a transpose on the final one.
102891f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    h = boxBlur(tp, h,             dp, loRadius, hiRadius, h, w, false);
102991f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    h = boxBlur(dp, h,             tp, hiRadius, loRadius, h, w, false);
103091f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    h = boxBlur(tp, h,             dp, hiRadius, hiRadius, h, w, true);
103191f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                } else {
103291f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    w = boxBlur(sp, src.fRowBytes, tp, rx, rx, w, h, true);
103391f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    h = boxBlur(tp, h,             dp, ry, ry, h, w, true);
103491f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                }
1035908276b3969cf8f8eec28026363897134c0e54e0senorblanco@chromium.org            } else {
103691f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                if (kHigh_Quality == quality) {
103791f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    // Do three X blurs, with a transpose on the final one.
1038a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, false, outerWeight);
1039a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    w = boxBlurInterp(tp, w,             dp, rx, w, h, false, outerWeight);
1040a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    w = boxBlurInterp(dp, w,             tp, rx, w, h, true, outerWeight);
104191f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                    // Do three Y blurs, with a transpose on the final one.
1042a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    h = boxBlurInterp(tp, h,             dp, ry, h, w, false, outerWeight);
1043a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    h = boxBlurInterp(dp, h,             tp, ry, h, w, false, outerWeight);
1044a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    h = boxBlurInterp(tp, h,             dp, ry, h, w, true, outerWeight);
104591f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                } else {
1046a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, true, outerWeight);
1047a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    h = boxBlurInterp(tp, h,             dp, ry, h, w, true, outerWeight);
104891f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org                }
104971f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org            }
105071f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org        } else {
105103016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com            const size_t storageW = sw + 2 * (passCount - 1) * rx + 1;
105203016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com            const size_t storageH = sh + 2 * (passCount - 1) * ry + 1;
105303016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com            SkAutoTMalloc<uint32_t> storage(storageW * storageH);
10548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            uint32_t*               sumBuffer = storage.get();
10558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10564868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org            //pass1: sp is source, dp is destination
10578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            build_sum_buffer(sumBuffer, sw, sh, sp, src.fRowBytes);
1058a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            if (outerWeight == 255) {
10598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                apply_kernel(dp, rx, ry, sumBuffer, sw, sh);
106003016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com            } else {
1061a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                apply_kernel_interp(dp, rx, ry, sumBuffer, sw, sh, outerWeight);
106203016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com            }
10634868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org
106491f489a65d436d36c7fe580af2775cd0cd13c8d2senorblanco@chromium.org            if (kHigh_Quality == quality) {
10654868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                //pass2: dp is source, tmpBuffer is destination
10664868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                int tmp_sw = sw + 2 * rx;
10674868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                int tmp_sh = sh + 2 * ry;
10684868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                SkAutoTMalloc<uint8_t>  tmpBuffer(dstSize);
10694868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                build_sum_buffer(sumBuffer, tmp_sw, tmp_sh, dp, tmp_sw);
1070a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                if (outerWeight == 255)
10714868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                    apply_kernel(tmpBuffer.get(), rx, ry, sumBuffer, tmp_sw, tmp_sh);
10724868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                else
107303016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                    apply_kernel_interp(tmpBuffer.get(), rx, ry, sumBuffer,
1074a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                                        tmp_sw, tmp_sh, outerWeight);
10754868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org
10764868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                //pass3: tmpBuffer is source, dp is destination
10774868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                tmp_sw += 2 * rx;
10784868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                tmp_sh += 2 * ry;
10794868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                build_sum_buffer(sumBuffer, tmp_sw, tmp_sh, tmpBuffer.get(), tmp_sw);
1080a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                if (outerWeight == 255)
10814868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                    apply_kernel(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh);
10824868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org                else
108303016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                    apply_kernel_interp(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh,
1084a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                                        outerWeight);
10854868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org            }
10868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
10878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst->fImage = dp;
10898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // if need be, alloc the "real" dst (same size as src) and copy/merge
10908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // the blur into it (applying the src)
10910e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        if (style == kInner_Style) {
10920e3c664250f561ec9f7107b92136517a72d03afdreed@android.com            // now we allocate the "real" dst, mirror the size of src
1093543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            size_t srcSize = src.computeImageSize();
1094543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            if (0 == srcSize) {
1095543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com                return false;   // too big to allocate, abort
1096543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            }
1097543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            dst->fImage = SkMask::AllocImage(srcSize);
10980e3c664250f561ec9f7107b92136517a72d03afdreed@android.com            merge_src_with_blur(dst->fImage, src.fRowBytes,
10990e3c664250f561ec9f7107b92136517a72d03afdreed@android.com                                sp, src.fRowBytes,
110003016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                                dp + passCount * (rx + ry * dst->fRowBytes),
110103016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                                dst->fRowBytes, sw, sh);
11028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkMask::FreeImage(dp);
11030e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        } else if (style != kNormal_Style) {
110403016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com            clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes),
110503016a36206be42e91e8e0eb62fe8fb95da97b38reed@google.com                            dst->fRowBytes, sp, src.fRowBytes, sw, sh, style);
11068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
11078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        (void)autoCall.detach();
11088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
11098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11100e3c664250f561ec9f7107b92136517a72d03afdreed@android.com    if (style == kInner_Style) {
11118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst->fBounds = src.fBounds; // restore trimmed bounds
11120e3c664250f561ec9f7107b92136517a72d03afdreed@android.com        dst->fRowBytes = src.fRowBytes;
11138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
11148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
11168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
111871f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.orgbool SkBlurMask::BlurSeparable(SkMask* dst, const SkMask& src,
111971f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org                               SkScalar radius, Style style, Quality quality,
112071f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org                               SkIPoint* margin)
112171f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org{
112271f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org    return SkBlurMask::Blur(dst, src, radius, style, quality, margin, true);
112371f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org}
112471f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org
112571f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.orgbool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
112671f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org                     SkScalar radius, Style style, Quality quality,
112771f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org                     SkIPoint* margin)
112871f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org{
112971f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org    return SkBlurMask::Blur(dst, src, radius, style, quality, margin, false);
113071f0f34f7d8e80fe760f318f29ba88ab58baff7dsenorblanco@chromium.org}
11317c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
11327c7292c6071898d73dc935c3b66b9816183806f0humper@google.com/* Convolving a box with itself three times results in a piecewise
11337c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   quadratic function:
11348ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
11357c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   0                              x <= -1.5
1136a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   9/8 + 3/2 x + 1/2 x^2   -1.5 < x <= -.5
11377c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   3/4 - x^2                -.5 < x <= .5
11387c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   9/8 - 3/2 x + 1/2 x^2    0.5 < x <= 1.5
11397c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   0                        1.5 < x
1140d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1141a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   Mathematica:
1142d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1143a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   g[x_] := Piecewise [ {
1144a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     {9/8 + 3/2 x + 1/2 x^2 ,  -1.5 < x <= -.5},
1145a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     {3/4 - x^2             ,   -.5 < x <= .5},
1146a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     {9/8 - 3/2 x + 1/2 x^2 ,   0.5 < x <= 1.5}
1147a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   }, 0]
11488ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
11497c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   To get the profile curve of the blurred step function at the rectangle
11507c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   edge, we evaluate the indefinite integral, which is piecewise cubic:
11518ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
11527c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   0                                        x <= -1.5
1153a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3   -1.5 < x <= -0.5
11547c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   1/2 + 3/4 x - 1/3 x^3              -.5 < x <= .5
1155a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3     .5 < x <= 1.5
11567c7292c6071898d73dc935c3b66b9816183806f0humper@google.com   1                                  1.5 < x
1157d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1158a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   in Mathematica code:
1159d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1160a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   gi[x_] := Piecewise[ {
1161a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     { 0 , x <= -1.5 },
1162a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     { 9/16 + 9/8 x + 3/4 x^2 + 1/6 x^3, -1.5 < x <= -0.5 },
1163a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     { 1/2 + 3/4 x - 1/3 x^3          ,  -.5 < x <= .5},
1164a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com     { 7/16 + 9/8 x - 3/4 x^2 + 1/6 x^3,   .5 < x <= 1.5}
1165a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com   },1]
11667c7292c6071898d73dc935c3b66b9816183806f0humper@google.com*/
11677c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
1168a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.comstatic float gaussianIntegral(float x) {
1169a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (x > 1.5f) {
11707c7292c6071898d73dc935c3b66b9816183806f0humper@google.com        return 0.0f;
11717c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
1172a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (x < -1.5f) {
11737c7292c6071898d73dc935c3b66b9816183806f0humper@google.com        return 1.0f;
11747c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
11757c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
11767c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    float x2 = x*x;
11777c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    float x3 = x2*x;
11787c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
11799c4e5ac5b7d32151d4d8ab1fb7ed443b35eb1254jvanverth@google.com    if ( x > 0.5f ) {
1180a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        return 0.5625f - (x3 / 6.0f - 3.0f * x2 * 0.25f + 1.125f * x);
11817c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
11829c4e5ac5b7d32151d4d8ab1fb7ed443b35eb1254jvanverth@google.com    if ( x > -0.5f ) {
11839c4e5ac5b7d32151d4d8ab1fb7ed443b35eb1254jvanverth@google.com        return 0.5f - (0.75f * x - x3 / 3.0f);
11847c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
11859c4e5ac5b7d32151d4d8ab1fb7ed443b35eb1254jvanverth@google.com    return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x);
11867c7292c6071898d73dc935c3b66b9816183806f0humper@google.com}
11877c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
11887c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com// Compute the size of the array allocated for the profile.
11897c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com
11907c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.comstatic int compute_profile_size(SkScalar radius) {
11917c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    return SkScalarRoundToInt(radius * 3);
11922e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
11932e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com}
11947c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com
11957c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com/*  compute_profile allocates and fills in an array of floating
11968ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com    point values between 0 and 255 for the profile signature of
11977c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    a blurred half-plane with the given blur radius.  Since we're
11987c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    going to be doing screened multiplications (i.e., 1 - (1-x)(1-y))
11997c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    all the time, we actually fill in the profile pre-inverted
12007c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    (already done 255-x).
12018ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
12027c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    It's the responsibility of the caller to delete the
12037c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    memory returned in profile_out.
12047c7292c6071898d73dc935c3b66b9816183806f0humper@google.com*/
12057c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
12067c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.comstatic void compute_profile(SkScalar radius, unsigned int **profile_out) {
12077c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    int size = compute_profile_size(radius);
12082e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
12097c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    int center = size >> 1;
121033cdbdea3ddcec9323b65eace86e10557312ae9bbsalomon@google.com    unsigned int *profile = SkNEW_ARRAY(unsigned int, size);
12117c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
1212a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    float invr = 1.f/radius;
12137c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
12147c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    profile[0] = 255;
1215a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int x = 1 ; x < size ; ++x) {
1216d98df1a3c468a2a7a5fff5efbf6dbdaf077d1abejvanverth@google.com        float scaled_x = (center - x - .5f) * invr;
1217a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        float gi = gaussianIntegral(scaled_x);
1218a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        profile[x] = 255 - (uint8_t) (255.f * gi);
12197c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
12207c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
12217c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    *profile_out = profile;
12227c7292c6071898d73dc935c3b66b9816183806f0humper@google.com}
12237c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
12248ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com// TODO MAYBE: Maintain a profile cache to avoid recomputing this for
12257c7292c6071898d73dc935c3b66b9816183806f0humper@google.com// commonly used radii.  Consider baking some of the most common blur radii
12267c7292c6071898d73dc935c3b66b9816183806f0humper@google.com// directly in as static data?
12277c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
12287c7292c6071898d73dc935c3b66b9816183806f0humper@google.com// Implementation adapted from Michael Herf's approach:
12297c7292c6071898d73dc935c3b66b9816183806f0humper@google.com// http://stereopsis.com/shadowrect/
12307c7292c6071898d73dc935c3b66b9816183806f0humper@google.com
1231a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.comstatic inline unsigned int profile_lookup( unsigned int *profile, int loc, int blurred_width, int sharp_width ) {
1232a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int dx = SkAbs32(((loc << 1) + 1) - blurred_width) - sharp_width; // how far are we from the original edge?
1233a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int ox = dx >> 1;
1234a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (ox < 0) {
1235a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        ox = 0;
1236a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
1237d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1238a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    return profile[ox];
1239a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com}
1240a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
12417c7292c6071898d73dc935c3b66b9816183806f0humper@google.combool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
1242a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                          SkScalar provided_radius, Style style,
12437c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com                          SkIPoint *margin, SkMask::CreateMode createMode) {
12447c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    int profile_size;
12452e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
12467c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    float radius = SkScalarToFloat(SkScalarMul(provided_radius, kBlurRadiusFudgeFactor));
1247d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
12481e1a24e2cae6a6b2536d158294c874300ef822b1humper@google.com    // adjust blur radius to match interpretation from boxfilter code
12497c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    radius = (radius + .5f) * 2.f;
12508ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
12517c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    profile_size = compute_profile_size(radius);
12522e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
1253a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int pad = profile_size/2;
12547c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    if (margin) {
12557c7292c6071898d73dc935c3b66b9816183806f0humper@google.com        margin->set( pad, pad );
12567c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
1257d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
12582e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com    dst->fBounds.set(SkScalarRoundToInt(src.fLeft - pad),
12592e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                     SkScalarRoundToInt(src.fTop - pad),
12602e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                     SkScalarRoundToInt(src.fRight + pad),
126168a690cb05d78060a95b1c8af0e60467740730a4humper@google.com                     SkScalarRoundToInt(src.fBottom + pad));
12628ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
12637c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    dst->fRowBytes = dst->fBounds.width();
12647c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    dst->fFormat = SkMask::kA8_Format;
12657c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    dst->fImage = NULL;
12662e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
12677c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    int             sw = SkScalarFloorToInt(src.width());
12687c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    int             sh = SkScalarFloorToInt(src.height());
12692e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
12707c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    if (createMode == SkMask::kJustComputeBounds_CreateMode) {
12717c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        if (style == kInner_Style) {
12722e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com            dst->fBounds.set(SkScalarRoundToInt(src.fLeft),
12732e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                             SkScalarRoundToInt(src.fTop),
12742e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                             SkScalarRoundToInt(src.fRight),
127568a690cb05d78060a95b1c8af0e60467740730a4humper@google.com                             SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds
12767c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com            dst->fRowBytes = sw;
12777c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        }
12787c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com        return true;
12797c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    }
12807c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    unsigned int *profile = NULL;
12812e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
12827c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    compute_profile(radius, &profile);
12837c5d7b781385c47e5be9a343d60c5b7d33b5b8cdhumper@google.com    SkAutoTDeleteArray<unsigned int> ada(profile);
12842e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com
12857c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    size_t dstSize = dst->computeImageSize();
12867c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    if (0 == dstSize) {
12877c7292c6071898d73dc935c3b66b9816183806f0humper@google.com        return false;   // too big to allocate, abort
12887c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
12898ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
12907c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    uint8_t*        dp = SkMask::AllocImage(dstSize);
12918ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
12927c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    dst->fImage = dp;
12938ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
1294a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int dstHeight = dst->fBounds.height();
1295a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int dstWidth = dst->fBounds.width();
12968ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
12977c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    // nearest odd number less than the profile size represents the center
12987c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    // of the (2x scaled) profile
12997c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    int center = ( profile_size & ~1 ) - 1;
13008ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
13017c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    int w = sw - center;
13027c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    int h = sh - center;
13038ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
13047c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    uint8_t *outptr = dp;
1305d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1306a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth);
13078ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
1308a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int x = 0 ; x < dstWidth ; ++x) {
1309a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        if (profile_size <= sw) {
1310a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            horizontalScanline[x] = profile_lookup(profile, x, dstWidth, w);
1311a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        } else {
1312a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            float span = float(sw)/radius;
1313d98df1a3c468a2a7a5fff5efbf6dbdaf077d1abejvanverth@google.com            float giX = 1.5f - (x+.5f)/radius;
1314a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span)));
1315a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
1316a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
1317d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1318a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int y = 0 ; y < dstHeight ; ++y) {
1319a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        unsigned int profile_y;
1320a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        if (profile_size <= sh) {
1321a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            profile_y = profile_lookup(profile, y, dstHeight, h);
1322a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        } else {
1323a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            float span = float(sh)/radius;
1324d98df1a3c468a2a7a5fff5efbf6dbdaf077d1abejvanverth@google.com            float giY = 1.5f - (y+.5f)/radius;
1325a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIntegral(giY + span)));
1326a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
13278ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
1328a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int x = 0 ; x < dstWidth ; x++) {
1329a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], profile_y);
1330a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            *(outptr++) = maskval;
1331a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
1332a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
1333d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1334a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (style == kInner_Style) {
1335a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // now we allocate the "real" dst, mirror the size of src
1336d98df1a3c468a2a7a5fff5efbf6dbdaf077d1abejvanverth@google.com        size_t srcSize = (size_t)(src.width() * src.height());
1337a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        if (0 == srcSize) {
1338a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            return false;   // too big to allocate, abort
1339a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
1340a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        dst->fImage = SkMask::AllocImage(srcSize);
1341a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int y = 0 ; y < sh ; y++) {
1342a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad;
1343a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint8_t *inner_scanline = dst->fImage + y*sw;
1344a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            memcpy(inner_scanline, blur_scanline, sw);
1345a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
1346a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        SkMask::FreeImage(dp);
1347a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
13482e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com        dst->fBounds.set(SkScalarRoundToInt(src.fLeft),
13492e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                         SkScalarRoundToInt(src.fTop),
13502e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com                         SkScalarRoundToInt(src.fRight),
135168a690cb05d78060a95b1c8af0e60467740730a4humper@google.com                         SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds
1352a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        dst->fRowBytes = sw;
1353d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1354a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    } else if (style == kOuter_Style) {
1355a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int y = pad ; y < dstHeight-pad ; y++) {
1356a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint8_t *dst_scanline = dp + y*dstWidth + pad;
1357a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            memset(dst_scanline, 0, sw);
1358a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
1359d4d573057ee126bae354934b8d31f5695af387b6humper@google.com    } else if (style == kSolid_Style) {
1360d4d573057ee126bae354934b8d31f5695af387b6humper@google.com        for (int y = pad ; y < dstHeight-pad ; y++) {
1361d4d573057ee126bae354934b8d31f5695af387b6humper@google.com            uint8_t *dst_scanline = dp + y*dstWidth + pad;
1362d4d573057ee126bae354934b8d31f5695af387b6humper@google.com            memset(dst_scanline, 0xff, sw);
13632e71f1619d9a2c51c1292e618f42a56ad2da1de8skia.committer@gmail.com        }
1364a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
1365a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // normal and solid styles are the same for analytic rect blurs, so don't
1366a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // need to handle solid specially.
13678ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
1368a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    return true;
1369a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com}
13708ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
1371a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com// The "simple" blur is a direct implementation of separable convolution with a discrete
1372a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com// gaussian kernel.  It's "ground truth" in a sense; too slow to be used, but very
1373a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com// useful for correctness comparisons.
13748ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
1375d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.combool SkBlurMask::BlurGroundTruth(SkMask* dst, const SkMask& src, SkScalar provided_radius,
1376a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                            Style style, SkIPoint* margin) {
1377d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1378a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (src.fFormat != SkMask::kA8_Format) {
1379a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        return false;
1380a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
13818ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
1382a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    float radius = SkScalarToFloat(SkScalarMul(provided_radius, kBlurRadiusFudgeFactor));
1383a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    float stddev = SkScalarToFloat(radius) /2.0f;
1384a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    float variance = stddev * stddev;
1385a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1386a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int windowSize = SkScalarCeil(stddev*4);
1387a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // round window size up to nearest odd number
1388a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    windowSize |= 1;
1389a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1390a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    SkAutoTMalloc<float> gaussWindow(windowSize);
1391a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1392a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int halfWindow = windowSize >> 1;
1393d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1394a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    gaussWindow[halfWindow] = 1;
1395d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1396a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    float windowSum = 1;
1397a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    for (int x = 1 ; x <= halfWindow ; ++x) {
1398a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        float gaussian = expf(-x*x / variance);
1399a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        gaussWindow[halfWindow + x] = gaussWindow[halfWindow-x] = gaussian;
1400a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        windowSum += 2*gaussian;
1401a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
1402a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1403a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // leave the filter un-normalized for now; we will divide by the normalization
1404a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    // sum later;
1405d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1406a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    int pad = halfWindow;
1407a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (margin) {
1408a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        margin->set( pad, pad );
1409a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
1410a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1411a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    dst->fBounds = src.fBounds;
1412a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    dst->fBounds.outset(pad, pad);
1413a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1414a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    dst->fRowBytes = dst->fBounds.width();
1415a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    dst->fFormat = SkMask::kA8_Format;
1416a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    dst->fImage = NULL;
1417a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1418a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (src.fImage) {
1419a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1420a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        size_t dstSize = dst->computeImageSize();
1421a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        if (0 == dstSize) {
1422a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            return false;   // too big to allocate, abort
1423a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
1424d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1425a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int             srcWidth = src.fBounds.width();
1426a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int             srcHeight = src.fBounds.height();
1427a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int             dstWidth = dst->fBounds.width();
1428d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1429a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        const uint8_t*  srcPixels = src.fImage;
1430a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        uint8_t*        dstPixels = SkMask::AllocImage(dstSize);
1431a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dstPixels);
1432a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1433a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // do the actual blur.  First, make a padded copy of the source.
1434a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // use double pad so we never have to check if we're outside anything
1435d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1436a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int padWidth = srcWidth + 4*pad;
1437a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int padHeight = srcHeight;
1438a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int padSize = padWidth * padHeight;
1439d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1440a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        SkAutoTMalloc<uint8_t> padPixels(padSize);
1441a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        memset(padPixels, 0, padSize);
1442d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1443a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int y = 0 ; y < srcHeight; ++y) {
1444a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint8_t* padptr = padPixels + y * padWidth + 2*pad;
1445a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            const uint8_t* srcptr = srcPixels + y * srcWidth;
1446a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            memcpy(padptr, srcptr, srcWidth);
1447a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
1448d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1449a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // blur in X, transposing the result into a temporary floating point buffer.
1450a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // also double-pad the intermediate result so that the second blur doesn't
1451a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // have to do extra conditionals.
1452d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1453a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int tmpWidth = padHeight + 4*pad;
1454a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int tmpHeight = padWidth - 2*pad;
1455a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        int tmpSize = tmpWidth * tmpHeight;
1456d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1457a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        SkAutoTMalloc<float> tmpImage(tmpSize);
1458a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        memset(tmpImage, 0, tmpSize*sizeof(tmpImage[0]));
1459a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1460a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int y = 0 ; y < padHeight ; ++y) {
1461a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            uint8_t *srcScanline = padPixels + y*padWidth;
1462a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            for (int x = pad ; x < padWidth - pad ; ++x) {
1463a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                float *outPixel = tmpImage + (x-pad)*tmpWidth + y + 2*pad; // transposed output
1464a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                uint8_t *windowCenter = srcScanline + x;
1465a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                for (int i = -pad ; i <= pad ; ++i) {
1466a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    *outPixel += gaussWindow[pad+i]*windowCenter[i];
1467a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                }
1468a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                *outPixel /= windowSum;
1469d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com            }
1470a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
1471d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1472a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // blur in Y; now filling in the actual desired destination.  We have to do
1473d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com        // the transpose again; these transposes guarantee that we read memory in
1474a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // linear order.
1475d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1476a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        for (int y = 0 ; y < tmpHeight ; ++y) {
1477a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            float *srcScanline = tmpImage + y*tmpWidth;
1478a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            for (int x = pad ; x < tmpWidth - pad ; ++x) {
1479a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                float *windowCenter = srcScanline + x;
1480a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                float finalValue = 0;
1481a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                for (int i = -pad ; i <= pad ; ++i) {
1482a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                    finalValue += gaussWindow[pad+i]*windowCenter[i];
1483a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                }
1484a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                finalValue /= windowSum;
1485a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                uint8_t *outPixel = dstPixels + (x-pad)*dstWidth + y; // transposed output
1486a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                int integerPixel = int(finalValue + 0.5f);
1487a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                *outPixel = SkClampMax( SkClampPos(integerPixel), 255 );
1488a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            }
1489a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        }
1490d454ec135eeef48edea7ebc47a61ff39bd654576skia.committer@gmail.com
1491a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        dst->fImage = dstPixels;
1492a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // if need be, alloc the "real" dst (same size as src) and copy/merge
1493a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        // the blur into it (applying the src)
1494a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        if (style == kInner_Style) {
1495a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            // now we allocate the "real" dst, mirror the size of src
1496a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            size_t srcSize = src.computeImageSize();
1497a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            if (0 == srcSize) {
1498a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                return false;   // too big to allocate, abort
1499a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            }
1500a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            dst->fImage = SkMask::AllocImage(srcSize);
1501a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            merge_src_with_blur(dst->fImage, src.fRowBytes,
1502a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                srcPixels, src.fRowBytes,
1503a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                dstPixels + pad*dst->fRowBytes + pad,
1504a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                dst->fRowBytes, srcWidth, srcHeight);
1505a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            SkMask::FreeImage(dstPixels);
1506a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        } else if (style != kNormal_Style) {
1507a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com            clamp_with_orig(dstPixels + pad*dst->fRowBytes + pad,
1508a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com                dst->fRowBytes, srcPixels, src.fRowBytes, srcWidth, srcHeight, style);
15097c7292c6071898d73dc935c3b66b9816183806f0humper@google.com        }
1510a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        (void)autoCall.detach();
1511a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    }
1512a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com
1513a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com    if (style == kInner_Style) {
1514a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        dst->fBounds = src.fBounds; // restore trimmed bounds
1515a99a92cebaa46cf792cf86eaad1a4c3f9d6162f7humper@google.com        dst->fRowBytes = src.fRowBytes;
15167c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    }
15178ae714b186ae5f4eaddee239281fbfe7282320c9skia.committer@gmail.com
15187c7292c6071898d73dc935c3b66b9816183806f0humper@google.com    return true;
15197c7292c6071898d73dc935c3b66b9816183806f0humper@google.com}
1520