15bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org/*
25bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org * Copyright 2012 The Android Open Source Project
35bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org *
45bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org * Use of this source code is governed by a BSD-style license that can be
55bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org * found in the LICENSE file.
65bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org */
75bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
85bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org#include "SkMorphologyImageFilter.h"
944b93a06ef9f00cceaede2ffc0fed971fa018e38djsollen@google.com#include "SkBitmap.h"
105bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org#include "SkColorPriv.h"
119ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com#include "SkFlattenableBuffers.h"
129ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com#include "SkRect.h"
133515569a78b58fbb57f20ec909fffde8f945c19cbsalomon@google.com#if SK_SUPPORT_GPU
1451f8f47eb816bf6f153971f1fe242aec4a078714senorblanco@chromium.org#include "GrContext.h"
1551f8f47eb816bf6f153971f1fe242aec4a078714senorblanco@chromium.org#include "GrTexture.h"
168780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com#include "GrTBackendEffectFactory.h"
17aab3f0a5176fa13f1f0452386651dc5c8676ba68bsalomon@google.com#include "gl/GrGLEffect.h"
18bc7f7b134d013466fc237434468d758c7d025e99bsalomon@google.com#include "gl/GrGLEffectMatrix.h"
19bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org#include "effects/Gr1DKernelEffect.h"
20868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org#include "SkImageFilterUtils.h"
213515569a78b58fbb57f20ec909fffde8f945c19cbsalomon@google.com#endif
225bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
235bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.orgSkMorphologyImageFilter::SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer)
245bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org  : INHERITED(buffer) {
250617a3cc12d399f60e4283cec051c47847c07c11tomhudson@google.com    fRadius.fWidth = buffer.readInt();
260617a3cc12d399f60e4283cec051c47847c07c11tomhudson@google.com    fRadius.fHeight = buffer.readInt();
275bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
285bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
29d1e690d99102d222364d2efa3eb7c881ff017446senorblanco@chromium.orgSkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input)
30d1e690d99102d222364d2efa3eb7c881ff017446senorblanco@chromium.org    : INHERITED(input), fRadius(SkISize::Make(radiusX, radiusY)) {
315bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
325bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
335bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
34cd2e444e946f5cfec4723f5bc46e9487d82e8e54djsollen@google.comvoid SkMorphologyImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
355bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    this->INHERITED::flatten(buffer);
360617a3cc12d399f60e4283cec051c47847c07c11tomhudson@google.com    buffer.writeInt(fRadius.fWidth);
370617a3cc12d399f60e4283cec051c47847c07c11tomhudson@google.com    buffer.writeInt(fRadius.fHeight);
385bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
395bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
405bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.orgstatic void erode(const SkPMColor* src, SkPMColor* dst,
415bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                  int radius, int width, int height,
425bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                  int srcStrideX, int srcStrideY,
435bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                  int dstStrideX, int dstStrideY)
445bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org{
45b2b48fed0305cc371b799519110051e2d4ce17c7senorblanco@chromium.org    radius = SkMin32(radius, width - 1);
46b2b48fed0305cc371b799519110051e2d4ce17c7senorblanco@chromium.org    const SkPMColor* upperSrc = src + radius * srcStrideX;
475bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    for (int x = 0; x < width; ++x) {
485bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        const SkPMColor* lp = src;
495bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        const SkPMColor* up = upperSrc;
505bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        SkPMColor* dptr = dst;
515bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        for (int y = 0; y < height; ++y) {
525bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            int minB = 255, minG = 255, minR = 255, minA = 255;
535bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
545bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                int b = SkGetPackedB32(*p);
555bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                int g = SkGetPackedG32(*p);
565bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                int r = SkGetPackedR32(*p);
575bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                int a = SkGetPackedA32(*p);
585bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                if (b < minB) minB = b;
595bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                if (g < minG) minG = g;
605bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                if (r < minR) minR = r;
615bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                if (a < minA) minA = a;
625bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            }
635bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            *dptr = SkPackARGB32(minA, minR, minG, minB);
645bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            dptr += dstStrideY;
655bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            lp += srcStrideY;
665bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            up += srcStrideY;
675bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        }
685bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        if (x >= radius) src += srcStrideX;
695bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        if (x + radius < width - 1) upperSrc += srcStrideX;
705bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        dst += dstStrideX;
715bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
725bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
735bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
745bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.orgstatic void erodeX(const SkBitmap& src, SkBitmap* dst, int radiusX)
755bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org{
765bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    erode(src.getAddr32(0, 0), dst->getAddr32(0, 0),
775bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org          radiusX, src.width(), src.height(),
785bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org          1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels());
795bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
805bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
815bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.orgstatic void erodeY(const SkBitmap& src, SkBitmap* dst, int radiusY)
825bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org{
835bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    erode(src.getAddr32(0, 0), dst->getAddr32(0, 0),
845bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org          radiusY, src.height(), src.width(),
855bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org          src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1);
865bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
875bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
885bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.orgstatic void dilate(const SkPMColor* src, SkPMColor* dst,
895bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                   int radius, int width, int height,
905bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                   int srcStrideX, int srcStrideY,
915bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                   int dstStrideX, int dstStrideY)
925bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org{
93b2b48fed0305cc371b799519110051e2d4ce17c7senorblanco@chromium.org    radius = SkMin32(radius, width - 1);
94b2b48fed0305cc371b799519110051e2d4ce17c7senorblanco@chromium.org    const SkPMColor* upperSrc = src + radius * srcStrideX;
955bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    for (int x = 0; x < width; ++x) {
965bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        const SkPMColor* lp = src;
975bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        const SkPMColor* up = upperSrc;
985bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        SkPMColor* dptr = dst;
995bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        for (int y = 0; y < height; ++y) {
1005bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            int maxB = 0, maxG = 0, maxR = 0, maxA = 0;
1015bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
1025bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                int b = SkGetPackedB32(*p);
1035bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                int g = SkGetPackedG32(*p);
1045bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                int r = SkGetPackedR32(*p);
1055bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                int a = SkGetPackedA32(*p);
1065bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                if (b > maxB) maxB = b;
1075bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                if (g > maxG) maxG = g;
1085bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                if (r > maxR) maxR = r;
1095bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org                if (a > maxA) maxA = a;
1105bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            }
1115bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            *dptr = SkPackARGB32(maxA, maxR, maxG, maxB);
1125bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            dptr += dstStrideY;
1135bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            lp += srcStrideY;
1145bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org            up += srcStrideY;
1155bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        }
1165bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        if (x >= radius) src += srcStrideX;
1175bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        if (x + radius < width - 1) upperSrc += srcStrideX;
1185bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        dst += dstStrideX;
1195bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
1205bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
1215bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
1225bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.orgstatic void dilateX(const SkBitmap& src, SkBitmap* dst, int radiusX)
1235bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org{
1245bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0),
1255bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org           radiusX, src.width(), src.height(),
1265bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org           1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels());
1275bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
1285bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
1295bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.orgstatic void dilateY(const SkBitmap& src, SkBitmap* dst, int radiusY)
1305bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org{
1315bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0),
1325bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org           radiusY, src.height(), src.width(),
1335bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org           src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1);
1345bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
1355bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
136d1e690d99102d222364d2efa3eb7c881ff017446senorblanco@chromium.orgbool SkErodeImageFilter::onFilterImage(Proxy* proxy,
137d1e690d99102d222364d2efa3eb7c881ff017446senorblanco@chromium.org                                       const SkBitmap& source, const SkMatrix& ctm,
138d1e690d99102d222364d2efa3eb7c881ff017446senorblanco@chromium.org                                       SkBitmap* dst, SkIPoint* offset) {
1393367b085856c70225f016ed90fd15ed393aeaed2senorblanco@chromium.org    SkBitmap src = source;
1403367b085856c70225f016ed90fd15ed393aeaed2senorblanco@chromium.org    if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctm, &src, offset)) {
1413367b085856c70225f016ed90fd15ed393aeaed2senorblanco@chromium.org        return false;
1423367b085856c70225f016ed90fd15ed393aeaed2senorblanco@chromium.org    }
1433367b085856c70225f016ed90fd15ed393aeaed2senorblanco@chromium.org
1445bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (src.config() != SkBitmap::kARGB_8888_Config) {
1455bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        return false;
1465bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
1475bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
1485bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    SkAutoLockPixels alp(src);
1495bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (!src.getPixels()) {
1505bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        return false;
1515bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
1525bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
1535bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    dst->setConfig(src.config(), src.width(), src.height());
1545bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    dst->allocPixels();
1555bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
1565bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    int width = radius().width();
1575bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    int height = radius().height();
1585bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
1595bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (width < 0 || height < 0) {
1605bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        return false;
1615bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
1625bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
1635bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (width == 0 && height == 0) {
1645bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        src.copyTo(dst, dst->config());
1655bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        return true;
1665bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
1675bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
1685bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    SkBitmap temp;
1695bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    temp.setConfig(dst->config(), dst->width(), dst->height());
1705bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (!temp.allocPixels()) {
1715bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        return false;
1725bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
1735bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
1745bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (width > 0 && height > 0) {
1755bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        erodeX(src, &temp, width);
1765bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        erodeY(temp, dst, height);
1775bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    } else if (width > 0) {
1785bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        erodeX(src, dst, width);
1795bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    } else if (height > 0) {
1805bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        erodeY(src, dst, height);
1815bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
1825bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    return true;
1835bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
1845bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
185d1e690d99102d222364d2efa3eb7c881ff017446senorblanco@chromium.orgbool SkDilateImageFilter::onFilterImage(Proxy* proxy,
186d1e690d99102d222364d2efa3eb7c881ff017446senorblanco@chromium.org                                        const SkBitmap& source, const SkMatrix& ctm,
187d1e690d99102d222364d2efa3eb7c881ff017446senorblanco@chromium.org                                        SkBitmap* dst, SkIPoint* offset) {
1883367b085856c70225f016ed90fd15ed393aeaed2senorblanco@chromium.org    SkBitmap src = source;
1893367b085856c70225f016ed90fd15ed393aeaed2senorblanco@chromium.org    if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctm, &src, offset)) {
1903367b085856c70225f016ed90fd15ed393aeaed2senorblanco@chromium.org        return false;
1913367b085856c70225f016ed90fd15ed393aeaed2senorblanco@chromium.org    }
1925bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (src.config() != SkBitmap::kARGB_8888_Config) {
1935bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        return false;
1945bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
1955bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
1965bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    SkAutoLockPixels alp(src);
1975bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (!src.getPixels()) {
1985bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        return false;
1995bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
2005bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
2015bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    dst->setConfig(src.config(), src.width(), src.height());
2025bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    dst->allocPixels();
2035bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
2045bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    int width = radius().width();
2055bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    int height = radius().height();
2065bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
2075bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (width < 0 || height < 0) {
2085bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        return false;
2095bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
2105bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
2115bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (width == 0 && height == 0) {
2125bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        src.copyTo(dst, dst->config());
2135bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        return true;
2145bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
2155bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
2165bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    SkBitmap temp;
2175bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    temp.setConfig(dst->config(), dst->width(), dst->height());
2185bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (!temp.allocPixels()) {
2195bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        return false;
2205bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
2215bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
2225bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    if (width > 0 && height > 0) {
2235bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        dilateX(src, &temp, width);
2245bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        dilateY(temp, dst, height);
2255bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    } else if (width > 0) {
2265bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        dilateX(src, dst, width);
2275bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    } else if (height > 0) {
2285bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org        dilateY(src, dst, height);
2295bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    }
2305bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org    return true;
2315bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
2325bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
2333515569a78b58fbb57f20ec909fffde8f945c19cbsalomon@google.com#if SK_SUPPORT_GPU
234bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
235bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
236bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
237bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgclass GrGLMorphologyEffect;
238bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
239bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org/**
240bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org * Morphology effects. Depending upon the type of morphology, either the
241bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org * component-wise min (Erode_Type) or max (Dilate_Type) of all pixels in the
242bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org * kernel is selected as the new color. The new color is modulated by the input
243bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org * color.
244bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org */
245bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgclass GrMorphologyEffect : public Gr1DKernelEffect {
246bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
247bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgpublic:
248bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
249bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    enum MorphologyType {
250bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        kErode_MorphologyType,
251bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        kDilate_MorphologyType,
252bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    };
253bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
25438b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com    static GrEffectRef* Create(GrTexture* tex, Direction dir, int radius, MorphologyType type) {
255ba8399f132a172950b49dec019e910ff681928f6bsalomon@google.com        AutoEffectUnref effect(SkNEW_ARGS(GrMorphologyEffect, (tex, dir, radius, type)));
25686e2faff92b4e897e1e38e8728f098a5d9d22034bsalomon@google.com        return CreateEffectRef(effect);
25738b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com    }
25838b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com
259bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    virtual ~GrMorphologyEffect();
260bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
261bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    MorphologyType type() const { return fType; }
262bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
263bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    static const char* Name() { return "Morphology"; }
264bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
265ca5e87e973b87209b5ffa298b8bc6ce0c512a204bsalomon@google.com    typedef GrGLMorphologyEffect GLEffect;
266bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
2671f64de790a624dc250d3da0789b3ada6251facb7bsalomon@google.com    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
268c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
269bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
270bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgprotected:
271bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
272bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    MorphologyType fType;
273bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
274bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgprivate:
2756a2cef0e27af0600fe1afcc0fcda2f3011371be9bsalomon@google.com    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
276c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com
27738b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com    GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType);
27838b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com
2797e0b48a766909be86a2923d909b85c111de4d237bsalomon@google.com    GR_DECLARE_EFFECT_TEST;
280bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
281bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    typedef Gr1DKernelEffect INHERITED;
282bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org};
283bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
284bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
285bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
286868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.orgclass GrGLMorphologyEffect : public GrGLEffect {
287bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgpublic:
2888bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    GrGLMorphologyEffect (const GrBackendEffectFactory&, const GrDrawEffect&);
289bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
2908780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com    virtual void emitCode(GrGLShaderBuilder*,
2918bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                          const GrDrawEffect&,
2928780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                          EffectKey,
2938780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                          const char* outputColor,
2948780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                          const char* inputColor,
2958780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                          const TextureSamplerArray&) SK_OVERRIDE;
296bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
2978bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
298bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
2998bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
300bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
301bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgprivate:
302bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    int width() const { return GrMorphologyEffect::WidthFromRadius(fRadius); }
303bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
304bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    int                                 fRadius;
305bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    GrMorphologyEffect::MorphologyType  fType;
306bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    GrGLUniformManager::UniformHandle   fImageIncrementUni;
307bc7f7b134d013466fc237434468d758c7d025e99bsalomon@google.com    GrGLEffectMatrix                    fEffectMatrix;
308bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
3098780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com    typedef GrGLEffect INHERITED;
310bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org};
311bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
3121f64de790a624dc250d3da0789b3ada6251facb7bsalomon@google.comGrGLMorphologyEffect::GrGLMorphologyEffect(const GrBackendEffectFactory& factory,
3138bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                                           const GrDrawEffect& drawEffect)
31416d2ef4cfb3ded1a3424a372b37c641845095ff3bsalomon@google.com    : INHERITED(factory)
3158bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle)
3168bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    , fEffectMatrix(drawEffect.castEffect<GrMorphologyEffect>().coordsType()) {
3178bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    const GrMorphologyEffect& m = drawEffect.castEffect<GrMorphologyEffect>();
318bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    fRadius = m.radius();
319bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    fType = m.type();
320bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org}
321bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
3228780f037626b5196962a39ab76afd51f094a7765bsalomon@google.comvoid GrGLMorphologyEffect::emitCode(GrGLShaderBuilder* builder,
3238bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                                    const GrDrawEffect&,
324bc7f7b134d013466fc237434468d758c7d025e99bsalomon@google.com                                    EffectKey key,
3258780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                                    const char* outputColor,
3268780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                                    const char* inputColor,
3278780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                                    const TextureSamplerArray& samplers) {
328bc7f7b134d013466fc237434468d758c7d025e99bsalomon@google.com    const char* coords;
3298bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
330bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
331bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                                             kVec2f_GrSLType, "ImageIncrement");
332bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
333bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    const char* func;
334bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    switch (fType) {
335bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        case GrMorphologyEffect::kErode_MorphologyType:
336093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com            builder->fsCodeAppendf("\t\t%s = vec4(1, 1, 1, 1);\n", outputColor);
337bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            func = "min";
338bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            break;
339bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        case GrMorphologyEffect::kDilate_MorphologyType:
340093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com            builder->fsCodeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
341bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            func = "max";
342bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            break;
343bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        default:
344bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            GrCrash("Unexpected type");
345bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            func = ""; // suppress warning
346bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            break;
347bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    }
348bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
349bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
350093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com    builder->fsCodeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords, fRadius, imgInc);
351093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com    builder->fsCodeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
352093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com    builder->fsCodeAppendf("\t\t\t%s = %s(%s, ", outputColor, func, outputColor);
353093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "coord");
354093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com    builder->fsCodeAppend(");\n");
355093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com    builder->fsCodeAppendf("\t\t\tcoord += %s;\n", imgInc);
356093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com    builder->fsCodeAppend("\t\t}\n");
357093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com    SkString modulate;
358093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com    GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
359093bc9ad71adeb7a2a6a2aa3d123e846f2f6f8f4bsalomon@google.com    builder->fsCodeAppend(modulate.c_str());
360bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org}
361bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
3628bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.comGrGLEffect::EffectKey GrGLMorphologyEffect::GenKey(const GrDrawEffect& drawEffect,
3638bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                                                   const GrGLCaps&) {
3648bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    const GrMorphologyEffect& m = drawEffect.castEffect<GrMorphologyEffect>();
3659ae086cba571945957b4ea066bf0699862e5ece3bsalomon@google.com    EffectKey key = static_cast<EffectKey>(m.radius());
366bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    key |= (m.type() << 8);
367bc7f7b134d013466fc237434468d758c7d025e99bsalomon@google.com    key <<= GrGLEffectMatrix::kKeyBits;
368bc7f7b134d013466fc237434468d758c7d025e99bsalomon@google.com    EffectKey matrixKey = GrGLEffectMatrix::GenKey(m.getMatrix(),
3698bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                                                   drawEffect,
3708bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                                                   m.coordsType(),
371bc7f7b134d013466fc237434468d758c7d025e99bsalomon@google.com                                                   m.texture(0));
372bc7f7b134d013466fc237434468d758c7d025e99bsalomon@google.com    return key | matrixKey;
373bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org}
374bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
3758bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.comvoid GrGLMorphologyEffect::setData(const GrGLUniformManager& uman,
3768bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                                   const GrDrawEffect& drawEffect) {
3778bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    const Gr1DKernelEffect& kern = drawEffect.castEffect<Gr1DKernelEffect>();
3788780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com    GrTexture& texture = *kern.texture(0);
379bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    // the code we generated was for a specific kernel radius
380bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    GrAssert(kern.radius() == fRadius);
381bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    float imageIncrement[2] = { 0 };
382bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    switch (kern.direction()) {
383bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        case Gr1DKernelEffect::kX_Direction:
384bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            imageIncrement[0] = 1.0f / texture.width();
385bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            break;
386bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        case Gr1DKernelEffect::kY_Direction:
387bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            imageIncrement[1] = 1.0f / texture.height();
388bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            break;
389bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        default:
390bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            GrCrash("Unknown filter direction.");
391bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    }
392bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
3938bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    fEffectMatrix.setData(uman, kern.getMatrix(), drawEffect, kern.texture(0));
394bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org}
395bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
396bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
397bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
398bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgGrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
399bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                                       Direction direction,
400bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                                       int radius,
401bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                                       MorphologyType type)
402bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    : Gr1DKernelEffect(texture, direction, radius)
403bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    , fType(type) {
404bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org}
405bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
406bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgGrMorphologyEffect::~GrMorphologyEffect() {
407bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org}
408bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
4091f64de790a624dc250d3da0789b3ada6251facb7bsalomon@google.comconst GrBackendEffectFactory& GrMorphologyEffect::getFactory() const {
4101f64de790a624dc250d3da0789b3ada6251facb7bsalomon@google.com    return GrTBackendEffectFactory<GrMorphologyEffect>::getInstance();
411bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org}
412bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
4136a2cef0e27af0600fe1afcc0fcda2f3011371be9bsalomon@google.combool GrMorphologyEffect::onIsEqual(const GrEffect& sBase) const {
414ba8399f132a172950b49dec019e910ff681928f6bsalomon@google.com    const GrMorphologyEffect& s = CastEffect<GrMorphologyEffect>(sBase);
415c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com    return (this->texture(0) == s.texture(0) &&
416bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            this->radius() == s.radius() &&
417bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            this->direction() == s.direction() &&
418bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org            this->type() == s.type());
419bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org}
420bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
421c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.comvoid GrMorphologyEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
422c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com    // This is valid because the color components of the result of the kernel all come
423c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com    // exactly from existing values in the source texture.
424c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com    this->updateConstantColorComponentsForModulation(color, validFlags);
425c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com}
426c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com
427bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
428bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
4297e0b48a766909be86a2923d909b85c111de4d237bsalomon@google.comGR_DEFINE_EFFECT_TEST(GrMorphologyEffect);
430bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
431f95aaa03702b16aea2251b6f812f7afeae4b8bbebsalomon@google.comGrEffectRef* GrMorphologyEffect::TestCreate(SkMWCRandom* random,
43285f3b52a22c623fc8846d920660fc0b0a4b7afa7sugoi@google.com                                            GrContext*,
433516b4c312ba95ab60863c325482ee6c36618f706bsalomon@google.com                                            const GrDrawTargetCaps&,
43438b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com                                            GrTexture* textures[]) {
43598b366d6fbbc21f44dfb41fd7fd27ce0a603c12cbsalomon@google.com    int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
43698b366d6fbbc21f44dfb41fd7fd27ce0a603c12cbsalomon@google.com                                      GrEffectUnitTest::kAlphaTextureIdx;
437bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    Direction dir = random->nextBool() ? kX_Direction : kY_Direction;
438bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    static const int kMaxRadius = 10;
439bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    int radius = random->nextRangeU(1, kMaxRadius);
440bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    MorphologyType type = random->nextBool() ? GrMorphologyEffect::kErode_MorphologyType :
441bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                                               GrMorphologyEffect::kDilate_MorphologyType;
442bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
44338b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com    return GrMorphologyEffect::Create(textures[texIdx], dir, radius, type);
444bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org}
445bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
446bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgnamespace {
447bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
448bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgvoid apply_morphology_pass(GrContext* context,
449bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                           GrTexture* texture,
450868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org                           const SkIRect& rect,
451bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                           int radius,
452bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                           GrMorphologyEffect::MorphologyType morphType,
453bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                           Gr1DKernelEffect::Direction direction) {
454bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    GrPaint paint;
4554de2cfb9a63682aa6624f781a7454956ef6619a7commit-bot@chromium.org    paint.addColorEffect(GrMorphologyEffect::Create(texture,
4564de2cfb9a63682aa6624f781a7454956ef6619a7commit-bot@chromium.org                                                    direction,
4574de2cfb9a63682aa6624f781a7454956ef6619a7commit-bot@chromium.org                                                    radius,
4584de2cfb9a63682aa6624f781a7454956ef6619a7commit-bot@chromium.org                                                    morphType))->unref();
459868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    context->drawRect(paint, SkRect::MakeFromIRect(rect));
460bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org}
461bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
462bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.orgGrTexture* apply_morphology(GrTexture* srcTexture,
463868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org                            const SkIRect& rect,
464bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                            GrMorphologyEffect::MorphologyType morphType,
465bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                            SkISize radius) {
466bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    GrContext* context = srcTexture->getContext();
467bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    srcTexture->ref();
4684a8cc154cd99f8c03d606d62685a21a9264272a0bsalomon@google.com
4694a8cc154cd99f8c03d606d62685a21a9264272a0bsalomon@google.com    GrContext::AutoMatrix am;
4704a8cc154cd99f8c03d606d62685a21a9264272a0bsalomon@google.com    am.setIdentity(context);
4714a8cc154cd99f8c03d606d62685a21a9264272a0bsalomon@google.com
472a8cbc57c2d74f8024d149370377bd7dcbd8d204ccommit-bot@chromium.org    GrContext::AutoClip acs(context, SkRect::MakeWH(SkIntToScalar(srcTexture->width()),
473bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                                                    SkIntToScalar(srcTexture->height())));
4744a8cc154cd99f8c03d606d62685a21a9264272a0bsalomon@google.com
475bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    GrTextureDesc desc;
476bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
477868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    desc.fWidth = rect.width();
478868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    desc.fHeight = rect.height();
479868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    desc.fConfig = kSkia8888_GrPixelConfig;
4804a8cc154cd99f8c03d606d62685a21a9264272a0bsalomon@google.com
481bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    if (radius.fWidth > 0) {
482bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        GrAutoScratchTexture ast(context, desc);
483bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget());
484bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        apply_morphology_pass(context, srcTexture, rect, radius.fWidth,
485bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                              morphType, Gr1DKernelEffect::kX_Direction);
486868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org        SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
487868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org                                              rect.width(), radius.fHeight);
488bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        context->clear(&clearRect, 0x0);
489bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        srcTexture->unref();
490bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        srcTexture = ast.detach();
491bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    }
492bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    if (radius.fHeight > 0) {
493bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        GrAutoScratchTexture ast(context, desc);
494bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget());
495bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        apply_morphology_pass(context, srcTexture, rect, radius.fHeight,
496bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org                              morphType, Gr1DKernelEffect::kY_Direction);
497bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        srcTexture->unref();
498bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org        srcTexture = ast.detach();
499bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    }
500bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org    return srcTexture;
501bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org}
502bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
503bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org};
504bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org
5056bdc8c54bc474b0a2abe4c0d9bdd47b8e3d29ef6commit-bot@chromium.orgbool SkDilateImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
5066bdc8c54bc474b0a2abe4c0d9bdd47b8e3d29ef6commit-bot@chromium.org                                         SkBitmap* result, SkIPoint* offset) {
507868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    SkBitmap inputBM;
5086bdc8c54bc474b0a2abe4c0d9bdd47b8e3d29ef6commit-bot@chromium.org    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &inputBM, offset)) {
509868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org        return false;
510868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    }
51187816f8e3e4e8633221d6e2c20c2ecdab3b6b6fccommit-bot@chromium.org    GrTexture* input = inputBM.getTexture();
512868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    SkIRect bounds;
513868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    src.getBounds(&bounds);
514868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    SkAutoTUnref<GrTexture> resultTex(apply_morphology(input, bounds,
515868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org        GrMorphologyEffect::kDilate_MorphologyType, radius()));
516868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    return SkImageFilterUtils::WrapTexture(resultTex, src.width(), src.height(), result);
5175bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
5185bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
5196bdc8c54bc474b0a2abe4c0d9bdd47b8e3d29ef6commit-bot@chromium.orgbool SkErodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
5206bdc8c54bc474b0a2abe4c0d9bdd47b8e3d29ef6commit-bot@chromium.org                                        SkBitmap* result, SkIPoint* offset) {
521868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    SkBitmap inputBM;
5226bdc8c54bc474b0a2abe4c0d9bdd47b8e3d29ef6commit-bot@chromium.org    if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &inputBM, offset)) {
523868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org        return false;
524868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    }
52587816f8e3e4e8633221d6e2c20c2ecdab3b6b6fccommit-bot@chromium.org    GrTexture* input = inputBM.getTexture();
526868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    SkIRect bounds;
527868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    src.getBounds(&bounds);
528868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    SkAutoTUnref<GrTexture> resultTex(apply_morphology(input, bounds,
529868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org        GrMorphologyEffect::kErode_MorphologyType, radius()));
530868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    return SkImageFilterUtils::WrapTexture(resultTex, src.width(), src.height(), result);
5315bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org}
5325bd4c4bdde0062e3c31d667bfcaf54bb0df5e6d6senorblanco@chromium.org
533bf5364aea54e626e8fd8523608f85081152633f8senorblanco@chromium.org#endif
534