SkBlurMask.cpp revision 543ed9352c7dfd93071c08b14930cca2e82a08d4
18a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* libs/graphics/effects/SkBlurMask.cpp
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
38a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** Copyright 2006, The Android Open Source Project
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
58a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** Licensed under the Apache License, Version 2.0 (the "License");
68a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** you may not use this file except in compliance with the License.
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** You may obtain a copy of the License at
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**     http://www.apache.org/licenses/LICENSE-2.0
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** Unless required by applicable law or agreed to in writing, software
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** distributed under the License is distributed on an "AS IS" BASIS,
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** See the License for the specific language governing permissions and
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** limitations under the License.
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurMask.h"
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTemplates.h"
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void build_sum_buffer(uint32_t dst[], int w, int h, const uint8_t src[], int srcRB)
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(srcRB >= w);
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // mod srcRB so we can apply it after each row
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    srcRB -= w;
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int x, y;
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // special case first row
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t X = 0;
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (x = w - 1; x >= 0; --x)
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        X = *src++ + X;
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *dst++ = X;
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    src += srcRB;
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // now do the rest of the rows
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (y = h - 1; y > 0; --y)
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        uint32_t L = 0;
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        uint32_t C = 0;
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (x = w - 1; x >= 0; --x)
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            uint32_t T = dst[-w];
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            X = *src++ + L + T - C;
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *dst++ = X;
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            L = X;
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            C = T;
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        src += srcRB;
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void apply_kernel(uint8_t dst[], int rx, int ry, const uint32_t src[], int sw, int sh)
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t scale = (1 << 24) / ((2*rx + 1)*(2*ry + 1));
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int rowBytes = sw;
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int dw = sw + 2*rx;
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int dh = sh + 2*ry;
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sw -= 1;    // now it is max_x
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sh -= 1;    // now it is max_y
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int prev_y = -ry - 1    -ry;
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int next_y = ry         -ry;
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int y = 0; y < dh; y++)
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int py = SkClampPos(prev_y) * rowBytes;
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int ny = SkFastMin32(next_y, sh) * rowBytes;
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int prev_x = -rx - 1    -rx;
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int next_x = rx         -rx;
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (int x = 0; x < dw; x++)
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int px = SkClampPos(prev_x);
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int nx = SkFastMin32(next_x, sw);
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            uint32_t sum = src[px+py] + src[nx+ny] - src[nx+py] - src[px+ny];
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *dst++ = SkToU8(sum * scale >> 24);
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            prev_x += 1;
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            next_x += 1;
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prev_y += 1;
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        next_y += 1;
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void apply_kernel_interp(uint8_t dst[], int rx, int ry, const uint32_t src[], int sw, int sh, U8CPU outer_weight)
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(rx > 0 && ry > 0);
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(outer_weight <= 255);
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int inner_weight = 255 - outer_weight;
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // round these guys up if they're bigger than 127
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    outer_weight += outer_weight >> 7;
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    inner_weight += inner_weight >> 7;
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t outer_scale = (outer_weight << 16) / ((2*rx + 1)*(2*ry + 1));
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t inner_scale = (inner_weight << 16) / ((2*rx - 1)*(2*ry - 1));
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int rowBytes = sw;
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int dw = sw + 2*rx;
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int dh = sh + 2*ry;
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sw -= 1;    // now it is max_x
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sh -= 1;    // now it is max_y
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int prev_y = -ry - 1    -ry;
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int next_y = ry         -ry;
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int y = 0; y < dh; y++)
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int py = SkClampPos(prev_y) * rowBytes;
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int ny = SkFastMin32(next_y, sh) * rowBytes;
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int ipy = SkClampPos(prev_y + 1) * rowBytes;
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int iny = SkClampMax(next_y - 1, sh) * rowBytes;
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int prev_x = -rx - 1    -rx;
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int next_x = rx         -rx;
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (int x = 0; x < dw; x++)
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int px = SkClampPos(prev_x);
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int nx = SkFastMin32(next_x, sw);
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int ipx = SkClampPos(prev_x + 1);
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int inx = SkClampMax(next_x - 1, sw);
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            uint32_t outer_sum = src[px+py] + src[nx+ny] - src[nx+py] - src[px+ny];
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            uint32_t inner_sum = src[ipx+ipy] + src[inx+iny] - src[inx+ipy] - src[ipx+iny];
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *dst++ = SkToU8((outer_sum * outer_scale + inner_sum * inner_scale) >> 24);
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            prev_x += 1;
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            next_x += 1;
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prev_y += 1;
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        next_y += 1;
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void merge_src_with_blur(uint8_t dst[],
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                const uint8_t src[], int sw, int sh,
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                const uint8_t blur[], int blurRowBytes)
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (--sh >= 0)
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (int x = sw - 1; x >= 0; --x)
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *dst = SkToU8(SkAlphaMul(*blur, SkAlpha255To256(*src)));
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst += 1;
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            src += 1;
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            blur += 1;
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        blur += blurRowBytes - sw;
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void clamp_with_orig(uint8_t dst[], int dstRowBytes,
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const uint8_t src[], int sw, int sh,
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            SkBlurMask::Style style)
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int x;
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (--sh >= 0)
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        switch (style) {
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkBlurMask::kSolid_Style:
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            for (x = sw - 1; x >= 0; --x)
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            {
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                *dst = SkToU8(*src + SkAlphaMul(*dst, SkAlpha255To256(255 - *src)));
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                dst += 1;
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                src += 1;
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkBlurMask::kOuter_Style:
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            for (x = sw - 1; x >= 0; --x)
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            {
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (*src)
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src)));
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                dst += 1;
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                src += 1;
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        default:
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(!"Unexpected blur style here");
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst += dstRowBytes - sw;
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// we use a local funciton to wrap the class static method to work around
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// a bug in gcc98
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMask_FreeImage(uint8_t* image);
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMask_FreeImage(uint8_t* image)
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMask::FreeImage(image);
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                      SkScalar radius, Style style)
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (src.fFormat != SkMask::kA8_Format)
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int rx = SkScalarCeil(radius);
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int outer_weight = 255 - SkScalarRound((SkIntToScalar(rx) - radius) * 255);
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(rx >= 0);
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((unsigned)outer_weight <= 255);
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rx == 0)
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int ry = rx;    // only do square blur for now
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fBounds.set(src.fBounds.fLeft - rx, src.fBounds.fTop - ry,
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        src.fBounds.fRight + rx, src.fBounds.fBottom + ry);
23149f0ff25a046d6001dc2d095b6fa3c30f0f46b6areed@android.com    dst->fRowBytes = dst->fBounds.width();
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fFormat = SkMask::kA8_Format;
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fImage = NULL;
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (src.fImage)
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
237543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        size_t dstSize = dst->computeImageSize();
238543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        if (0 == dstSize) {
239543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            return false;   // too big to allocate, abort
240543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        }
241543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int             sw = src.fBounds.width();
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int             sh = src.fBounds.height();
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const uint8_t*  sp = src.fImage;
245543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com        uint8_t*        dp = SkMask::AllocImage(dstSize);
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp);
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // build the blurry destination
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkAutoTMalloc<uint32_t> storage(sw * sh);
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            uint32_t*               sumBuffer = storage.get();
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            build_sum_buffer(sumBuffer, sw, sh, sp, src.fRowBytes);
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (outer_weight == 255)
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                apply_kernel(dp, rx, ry, sumBuffer, sw, sh);
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            else
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                apply_kernel_interp(dp, rx, ry, sumBuffer, sw, sh, outer_weight);
2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst->fImage = dp;
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // if need be, alloc the "real" dst (same size as src) and copy/merge
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // the blur into it (applying the src)
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (style == kInner_Style)
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
266543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            size_t srcSize = src.computeImageSize();
267543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            if (0 == srcSize) {
268543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com                return false;   // too big to allocate, abort
269543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            }
270543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com            dst->fImage = SkMask::AllocImage(srcSize);
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            merge_src_with_blur(dst->fImage, sp, sw, sh,
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                dp + rx + ry*dst->fBounds.width(),
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                dst->fBounds.width());
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkMask::FreeImage(dp);
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        else if (style != kNormal_Style)
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            clamp_with_orig(dp + rx + ry*dst->fBounds.width(),
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            dst->fBounds.width(),
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            sp, sw, sh,
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            style);
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        (void)autoCall.detach();
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (style == kInner_Style)
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
2888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst->fBounds = src.fBounds; // restore trimmed bounds
28949f0ff25a046d6001dc2d095b6fa3c30f0f46b6areed@android.com        dst->fRowBytes = dst->fBounds.width();
2908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if 0
2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (gamma && dst->fImage)
2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        uint8_t*    image = dst->fImage;
2968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        uint8_t*    stop = image + dst->computeImageSize();
2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (; image < stop; image += 1)
2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *image = gamma[*image];
3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if 0
3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkBlurMask::BuildSqrtGamma(uint8_t gamma[256], SkScalar percent)
3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(gamma);
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(percent >= 0 && percent <= SK_Scalar1);
3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int scale = SkScalarRound(percent * 256);
3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int i = 0; i < 256; i++)
3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkFixed n = i * 257;
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        n += n >> 15;
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(n >= 0 && n <= SK_Fixed1);
3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        n = SkFixedSqrt(n);
3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        n = n * 255 >> 16;
3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        n = SkAlphaBlend(n, i, scale);
3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        gamma[i] = SkToU8(n);
3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkBlurMask::BuildSqrGamma(uint8_t gamma[256], SkScalar percent)
3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
3278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(gamma);
3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(percent >= 0 && percent <= SK_Scalar1);
3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int     scale = SkScalarRound(percent * 256);
3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed div255 = SK_Fixed1 / 255;
3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int i = 0; i < 256; i++)
3348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
3358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int square = i * i;
3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int linear = i * 255;
3378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int n = SkAlphaBlend(square, linear, scale);
3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        gamma[i] = SkToU8(n * div255 >> 16);
3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
342