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