105054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org/*
205054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org * Copyright 2012 The Android Open Source Project
305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org *
405054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org * Use of this source code is governed by a BSD-style license that can be
505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org * found in the LICENSE file.
605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org */
705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
805054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org#include "SkMorphologyImageFilter.h"
964a0ec36555352ec31aa7c5a7630a5d042b010badjsollen@google.com#include "SkBitmap.h"
1005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org#include "SkColorPriv.h"
118b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
13c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com#include "SkRect.h"
147a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org#include "SkMorphology_opts.h"
15cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#if SK_SUPPORT_GPU
16302cffba86a188373c99833d83392f33e6014542senorblanco@chromium.org#include "GrContext.h"
17605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdaniel#include "GrInvariantOutput.h"
18302cffba86a188373c99833d83392f33e6014542senorblanco@chromium.org#include "GrTexture.h"
19eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "effects/Gr1DKernelEffect.h"
20b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "gl/GrGLProcessor.h"
2130ba436f04e61d4505fb854d5fc56079636e0788joshualitt#include "gl/builders/GrGLProgramBuilder.h"
22cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#endif
2305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
242bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.orgSkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX,
252bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org                                                 int radiusY,
262bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org                                                 SkImageFilter* input,
2724e06d5244ae96e440410e1d76e039983b2efac9senorblanco                                                 const CropRect* cropRect)
2824e06d5244ae96e440410e1d76e039983b2efac9senorblanco    : INHERITED(1, &input, cropRect), fRadius(SkISize::Make(radiusX, radiusY)) {
2905054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org}
3005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
318b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkMorphologyImageFilter::flatten(SkWriteBuffer& buffer) const {
3205054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    this->INHERITED::flatten(buffer);
3375589257c6ac7fc55a66502b74b8bc09c0212featomhudson@google.com    buffer.writeInt(fRadius.fWidth);
3475589257c6ac7fc55a66502b74b8bc09c0212featomhudson@google.com    buffer.writeInt(fRadius.fHeight);
3505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org}
3605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
377a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.orgenum MorphDirection {
387a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org    kX, kY
397a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org};
407a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org
417a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.orgtemplate<MorphDirection direction>
4205054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.orgstatic void erode(const SkPMColor* src, SkPMColor* dst,
4305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                  int radius, int width, int height,
447a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org                  int srcStride, int dstStride)
4505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org{
467a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org    const int srcStrideX = direction == kX ? 1 : srcStride;
477a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org    const int dstStrideX = direction == kX ? 1 : dstStride;
487a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org    const int srcStrideY = direction == kX ? srcStride : 1;
497a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org    const int dstStrideY = direction == kX ? dstStride : 1;
5056dd630c41d662bcf2a3f08100f2c6accda05ba9senorblanco@chromium.org    radius = SkMin32(radius, width - 1);
5156dd630c41d662bcf2a3f08100f2c6accda05ba9senorblanco@chromium.org    const SkPMColor* upperSrc = src + radius * srcStrideX;
5205054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    for (int x = 0; x < width; ++x) {
5305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        const SkPMColor* lp = src;
5405054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        const SkPMColor* up = upperSrc;
5505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        SkPMColor* dptr = dst;
5605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        for (int y = 0; y < height; ++y) {
5705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            int minB = 255, minG = 255, minR = 255, minA = 255;
5805054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
5905054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                int b = SkGetPackedB32(*p);
6005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                int g = SkGetPackedG32(*p);
6105054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                int r = SkGetPackedR32(*p);
6205054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                int a = SkGetPackedA32(*p);
6305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                if (b < minB) minB = b;
6405054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                if (g < minG) minG = g;
6505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                if (r < minR) minR = r;
6605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                if (a < minA) minA = a;
6705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            }
6805054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            *dptr = SkPackARGB32(minA, minR, minG, minB);
6905054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            dptr += dstStrideY;
7005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            lp += srcStrideY;
7105054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            up += srcStrideY;
7205054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        }
7305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        if (x >= radius) src += srcStrideX;
7405054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        if (x + radius < width - 1) upperSrc += srcStrideX;
7505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        dst += dstStrideX;
7605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    }
7705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org}
7805054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
797a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.orgtemplate<MorphDirection direction>
8005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.orgstatic void dilate(const SkPMColor* src, SkPMColor* dst,
8105054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                   int radius, int width, int height,
827a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org                   int srcStride, int dstStride)
8305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org{
847a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org    const int srcStrideX = direction == kX ? 1 : srcStride;
857a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org    const int dstStrideX = direction == kX ? 1 : dstStride;
867a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org    const int srcStrideY = direction == kX ? srcStride : 1;
877a47ad3bacb36ca7609490bd7cbd85d2c49a0042senorblanco@chromium.org    const int dstStrideY = direction == kX ? dstStride : 1;
8856dd630c41d662bcf2a3f08100f2c6accda05ba9senorblanco@chromium.org    radius = SkMin32(radius, width - 1);
8956dd630c41d662bcf2a3f08100f2c6accda05ba9senorblanco@chromium.org    const SkPMColor* upperSrc = src + radius * srcStrideX;
9005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    for (int x = 0; x < width; ++x) {
9105054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        const SkPMColor* lp = src;
9205054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        const SkPMColor* up = upperSrc;
9305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        SkPMColor* dptr = dst;
9405054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        for (int y = 0; y < height; ++y) {
9505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            int maxB = 0, maxG = 0, maxR = 0, maxA = 0;
9605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
9705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                int b = SkGetPackedB32(*p);
9805054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                int g = SkGetPackedG32(*p);
9905054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                int r = SkGetPackedR32(*p);
10005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                int a = SkGetPackedA32(*p);
10105054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                if (b > maxB) maxB = b;
10205054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                if (g > maxG) maxG = g;
10305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                if (r > maxR) maxR = r;
10405054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org                if (a > maxA) maxA = a;
10505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            }
10605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            *dptr = SkPackARGB32(maxA, maxR, maxG, maxB);
10705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            dptr += dstStrideY;
10805054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            lp += srcStrideY;
10905054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org            up += srcStrideY;
11005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        }
11105054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        if (x >= radius) src += srcStrideX;
11205054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        if (x + radius < width - 1) upperSrc += srcStrideX;
11305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        dst += dstStrideX;
11405054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    }
11505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org}
11605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
1170ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.orgstatic void callProcX(SkMorphologyImageFilter::Proc procX, const SkBitmap& src, SkBitmap* dst, int radiusX, const SkIRect& bounds)
11805054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org{
1190ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    procX(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0),
1200ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org          radiusX, bounds.width(), bounds.height(),
1210ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org          src.rowBytesAsPixels(), dst->rowBytesAsPixels());
12205054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org}
12305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
1240ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.orgstatic void callProcY(SkMorphologyImageFilter::Proc procY, const SkBitmap& src, SkBitmap* dst, int radiusY, const SkIRect& bounds)
12505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org{
1260ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    procY(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0),
1270ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org          radiusY, bounds.height(), bounds.width(),
1280ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org          src.rowBytesAsPixels(), dst->rowBytesAsPixels());
12905054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org}
13005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
1310ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.orgbool SkMorphologyImageFilter::filterImageGeneric(SkMorphologyImageFilter::Proc procX,
1320ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org                                                 SkMorphologyImageFilter::Proc procY,
1330ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org                                                 Proxy* proxy,
1340ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org                                                 const SkBitmap& source,
1354cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org                                                 const Context& ctx,
1360ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org                                                 SkBitmap* dst,
137ae761f7545d8ebf181d220169afac2056b057b8ccommit-bot@chromium.org                                                 SkIPoint* offset) const {
13868400767be5f72e4b9750ccc8bcf0078d42869a7senorblanco@chromium.org    SkBitmap src = source;
1396776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    SkIPoint srcOffset = SkIPoint::Make(0, 0);
1404cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) {
14168400767be5f72e4b9750ccc8bcf0078d42869a7senorblanco@chromium.org        return false;
14268400767be5f72e4b9750ccc8bcf0078d42869a7senorblanco@chromium.org    }
14368400767be5f72e4b9750ccc8bcf0078d42869a7senorblanco@chromium.org
14428fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org    if (src.colorType() != kN32_SkColorType) {
14505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        return false;
14605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    }
14705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
1488fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org    SkIRect bounds;
149118252962f89a80db661a0544f1bd61cbaab6321senorblanco@chromium.org    if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
1508fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org        return false;
1518fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org    }
1528fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org
15305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    SkAutoLockPixels alp(src);
15405054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    if (!src.getPixels()) {
15505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        return false;
15605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    }
15705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
158848250415eddc54075f7eb8795e8db79e749c6abreed    if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
159cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org        return false;
160cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org    }
16105054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
1622bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
1632bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org                                     SkIntToScalar(this->radius().height()));
1644cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    ctx.ctm().mapVectors(&radius, 1);
1652bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    int width = SkScalarFloorToInt(radius.fX);
1662bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    int height = SkScalarFloorToInt(radius.fY);
16705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
16805054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    if (width < 0 || height < 0) {
16905054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        return false;
17005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    }
17105054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
1722bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    SkIRect srcBounds = bounds;
1732bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    srcBounds.offset(-srcOffset);
1742bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org
17505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    if (width == 0 && height == 0) {
1762bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org        src.extractSubset(dst, srcBounds);
1776776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org        offset->fX = bounds.left();
1786776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org        offset->fY = bounds.top();
17905054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        return true;
18005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    }
18105054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
18205054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    SkBitmap temp;
183848250415eddc54075f7eb8795e8db79e749c6abreed    if (!temp.tryAllocPixels(dst->info())) {
18405054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org        return false;
18505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    }
18605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
18705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    if (width > 0 && height > 0) {
1880ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org        callProcX(procX, src, &temp, width, srcBounds);
1892bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org        SkIRect tmpBounds = SkIRect::MakeWH(srcBounds.width(), srcBounds.height());
1900ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org        callProcY(procY, temp, dst, height, tmpBounds);
19105054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    } else if (width > 0) {
1920ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org        callProcX(procX, src, dst, width, srcBounds);
19305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    } else if (height > 0) {
1940ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org        callProcY(procY, src, dst, height, srcBounds);
19505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    }
1962bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    offset->fX = bounds.left();
1972bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    offset->fY = bounds.top();
19805054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    return true;
19905054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org}
20005054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
2010ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.orgbool SkErodeImageFilter::onFilterImage(Proxy* proxy,
2024cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org                                       const SkBitmap& source, const Context& ctx,
203ae761f7545d8ebf181d220169afac2056b057b8ccommit-bot@chromium.org                                       SkBitmap* dst, SkIPoint* offset) const {
2040ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    Proc erodeXProc = SkMorphologyGetPlatformProc(kErodeX_SkMorphologyProcType);
2050ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    if (!erodeXProc) {
2060ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org        erodeXProc = erode<kX>;
2071878a44c7490e3312a3b617fa03d2cf297b791e0skia.committer@gmail.com    }
2080ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    Proc erodeYProc = SkMorphologyGetPlatformProc(kErodeY_SkMorphologyProcType);
2090ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    if (!erodeYProc) {
2100ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org        erodeYProc = erode<kY>;
2111878a44c7490e3312a3b617fa03d2cf297b791e0skia.committer@gmail.com    }
2124cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    return this->filterImageGeneric(erodeXProc, erodeYProc, proxy, source, ctx, dst, offset);
2130ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org}
2141878a44c7490e3312a3b617fa03d2cf297b791e0skia.committer@gmail.com
2150ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.orgbool SkDilateImageFilter::onFilterImage(Proxy* proxy,
2164cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org                                        const SkBitmap& source, const Context& ctx,
217ae761f7545d8ebf181d220169afac2056b057b8ccommit-bot@chromium.org                                        SkBitmap* dst, SkIPoint* offset) const {
2180ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    Proc dilateXProc = SkMorphologyGetPlatformProc(kDilateX_SkMorphologyProcType);
2190ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    if (!dilateXProc) {
2200ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org        dilateXProc = dilate<kX>;
2211878a44c7490e3312a3b617fa03d2cf297b791e0skia.committer@gmail.com    }
2220ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    Proc dilateYProc = SkMorphologyGetPlatformProc(kDilateY_SkMorphologyProcType);
2230ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    if (!dilateYProc) {
2240ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org        dilateYProc = dilate<kY>;
2251878a44c7490e3312a3b617fa03d2cf297b791e0skia.committer@gmail.com    }
2264cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    return this->filterImageGeneric(dilateXProc, dilateYProc, proxy, source, ctx, dst, offset);
22705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org}
22805054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
229336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.orgvoid SkMorphologyImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
230336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    if (getInput(0)) {
231336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org        getInput(0)->computeFastBounds(src, dst);
232336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    } else {
233336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org        *dst = src;
234336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    }
235336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    dst->outset(SkIntToScalar(fRadius.width()), SkIntToScalar(fRadius.height()));
236336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org}
237336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org
238c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.orgbool SkMorphologyImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
239c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org                                             SkIRect* dst) const {
240c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    SkIRect bounds = src;
241c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
242c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org                                     SkIntToScalar(this->radius().height()));
243c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    ctm.mapVectors(&radius, 1);
244c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    bounds.outset(SkScalarCeilToInt(radius.x()), SkScalarCeilToInt(radius.y()));
2451150a6d151571fb6ee816dadec844ae7ab53948asenorblanco    if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) {
2461150a6d151571fb6ee816dadec844ae7ab53948asenorblanco        return false;
2471150a6d151571fb6ee816dadec844ae7ab53948asenorblanco    }
248c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    *dst = bounds;
249c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    return true;
250c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org}
251c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org
2529fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkErodeImageFilter::CreateProc(SkReadBuffer& buffer) {
2539fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
2549fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const int width = buffer.readInt();
2559fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const int height = buffer.readInt();
25624e06d5244ae96e440410e1d76e039983b2efac9senorblanco    return Create(width, height, common.getInput(0), &common.cropRect());
2579fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
2589fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
2599fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkDilateImageFilter::CreateProc(SkReadBuffer& buffer) {
2609fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
2619fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const int width = buffer.readInt();
2629fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const int height = buffer.readInt();
26324e06d5244ae96e440410e1d76e039983b2efac9senorblanco    return Create(width, height, common.getInput(0), &common.cropRect());
2649fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
2659fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
266f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#ifndef SK_IGNORE_TO_STRING
267f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillipsvoid SkErodeImageFilter::toString(SkString* str) const {
268f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("SkErodeImageFilter: (");
269f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("radius: (%d,%d)", this->radius().fWidth, this->radius().fHeight);
270f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->append(")");
271f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips}
272f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#endif
273f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
274f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#ifndef SK_IGNORE_TO_STRING
275f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillipsvoid SkDilateImageFilter::toString(SkString* str) const {
276f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("SkDilateImageFilter: (");
277f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("radius: (%d,%d)", this->radius().fWidth, this->radius().fHeight);
278f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->append(")");
279f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips}
280f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#endif
281f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
282cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#if SK_SUPPORT_GPU
28384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
28484207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
28584207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org/**
28684207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org * Morphology effects. Depending upon the type of morphology, either the
28784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org * component-wise min (Erode_Type) or max (Dilate_Type) of all pixels in the
28884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org * kernel is selected as the new color. The new color is modulated by the input
28984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org * color.
29084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org */
29184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.orgclass GrMorphologyEffect : public Gr1DKernelEffect {
29284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
29384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.orgpublic:
29484207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
29584207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    enum MorphologyType {
29684207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org        kErode_MorphologyType,
29784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org        kDilate_MorphologyType,
29884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    };
29984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
300b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    static GrFragmentProcessor* Create(GrTexture* tex, Direction dir, int radius,
301b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       MorphologyType type) {
30255fad7af61c21d502acb9891d631e8aa29e3628cbsalomon        return SkNEW_ARGS(GrMorphologyEffect, (tex, dir, radius, type));
3030ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com    }
3040ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com
30580a61df691bd5756dfbcbc57441806f2594511d8cwallez    static GrFragmentProcessor* Create(GrTexture* tex, Direction dir, int radius,
30680a61df691bd5756dfbcbc57441806f2594511d8cwallez                                       MorphologyType type, float bounds[2]) {
30780a61df691bd5756dfbcbc57441806f2594511d8cwallez        return SkNEW_ARGS(GrMorphologyEffect, (tex, dir, radius, type, bounds));
30880a61df691bd5756dfbcbc57441806f2594511d8cwallez    }
30980a61df691bd5756dfbcbc57441806f2594511d8cwallez
31084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    virtual ~GrMorphologyEffect();
31184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
31284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    MorphologyType type() const { return fType; }
31380a61df691bd5756dfbcbc57441806f2594511d8cwallez    bool useRange() const { return fUseRange; }
31480a61df691bd5756dfbcbc57441806f2594511d8cwallez    const float* range() const { return fRange; }
31584207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
31636352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "Morphology"; }
31784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
318cfc18867d982119d9dc2888bf09f1093012daaddjvanverth    void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
31984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
32036352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    GrGLFragmentProcessor* createGLInstance() const override;
32184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
32284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.orgprotected:
32384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
32484207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    MorphologyType fType;
32580a61df691bd5756dfbcbc57441806f2594511d8cwallez    bool fUseRange;
32680a61df691bd5756dfbcbc57441806f2594511d8cwallez    float fRange[2];
32784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
32884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.orgprivate:
32936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onIsEqual(const GrFragmentProcessor&) const override;
33068b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com
33136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
3321a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel
3330ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com    GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType);
33480a61df691bd5756dfbcbc57441806f2594511d8cwallez    GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType, float bounds[2]);
3350ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com
336b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
33784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
33884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    typedef Gr1DKernelEffect INHERITED;
33984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org};
34084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
34184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
34284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
343b0a8a377f832c59cee939ad721e1f87d378b7142joshualittclass GrGLMorphologyEffect : public GrGLFragmentProcessor {
34484207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.orgpublic:
345eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    GrGLMorphologyEffect(const GrProcessor&);
34684207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
3471598899975ecc85b003a59740b588d1ddbcedb09joshualitt    virtual void emitCode(GrGLFPBuilder*,
348b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                          const GrFragmentProcessor&,
34947d7a8885b02478fa41069f14bba7ffbe5475d87bsalomon@google.com                          const char* outputColor,
35047d7a8885b02478fa41069f14bba7ffbe5475d87bsalomon@google.com                          const char* inputColor,
35177af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                          const TransformedCoordsArray&,
35236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                          const TextureSamplerArray&) override;
35384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
354cfc18867d982119d9dc2888bf09f1093012daaddjvanverth    static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b);
35584207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
35636352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
35784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
35884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.orgprivate:
35984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    int width() const { return GrMorphologyEffect::WidthFromRadius(fRadius); }
36084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
3617510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    int                                   fRadius;
36280a61df691bd5756dfbcbc57441806f2594511d8cwallez    Gr1DKernelEffect::Direction           fDirection;
36380a61df691bd5756dfbcbc57441806f2594511d8cwallez    bool                                  fUseRange;
3647510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    GrMorphologyEffect::MorphologyType    fType;
36580a61df691bd5756dfbcbc57441806f2594511d8cwallez    GrGLProgramDataManager::UniformHandle fPixelSizeUni;
36680a61df691bd5756dfbcbc57441806f2594511d8cwallez    GrGLProgramDataManager::UniformHandle fRangeUni;
36784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
368b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrGLFragmentProcessor INHERITED;
36984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org};
37084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
371eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualittGrGLMorphologyEffect::GrGLMorphologyEffect(const GrProcessor& proc) {
372b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>();
37384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    fRadius = m.radius();
37480a61df691bd5756dfbcbc57441806f2594511d8cwallez    fDirection = m.direction();
37580a61df691bd5756dfbcbc57441806f2594511d8cwallez    fUseRange = m.useRange();
37684207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    fType = m.type();
37784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org}
37884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
3791598899975ecc85b003a59740b588d1ddbcedb09joshualittvoid GrGLMorphologyEffect::emitCode(GrGLFPBuilder* builder,
380b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                    const GrFragmentProcessor&,
38147d7a8885b02478fa41069f14bba7ffbe5475d87bsalomon@google.com                                    const char* outputColor,
38247d7a8885b02478fa41069f14bba7ffbe5475d87bsalomon@google.com                                    const char* inputColor,
38377af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                                    const TransformedCoordsArray& coords,
38447d7a8885b02478fa41069f14bba7ffbe5475d87bsalomon@google.com                                    const TextureSamplerArray& samplers) {
38580a61df691bd5756dfbcbc57441806f2594511d8cwallez    fPixelSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
38680a61df691bd5756dfbcbc57441806f2594511d8cwallez                                            kFloat_GrSLType, kDefault_GrSLPrecision,
38780a61df691bd5756dfbcbc57441806f2594511d8cwallez                                            "PixelSize");
38880a61df691bd5756dfbcbc57441806f2594511d8cwallez    const char* pixelSizeInc = builder->getUniformCStr(fPixelSizeUni);
38980a61df691bd5756dfbcbc57441806f2594511d8cwallez    fRangeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
39080a61df691bd5756dfbcbc57441806f2594511d8cwallez                                            kVec2f_GrSLType, kDefault_GrSLPrecision,
39180a61df691bd5756dfbcbc57441806f2594511d8cwallez                                            "Range");
39280a61df691bd5756dfbcbc57441806f2594511d8cwallez    const char* range = builder->getUniformCStr(fRangeUni);
39384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
39429bee0fe657fabf7c396502b69c9167fba13eaaaegdaniel    GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
39530ba436f04e61d4505fb854d5fc56079636e0788joshualitt    SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
39684207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    const char* func;
39784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    switch (fType) {
39884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org        case GrMorphologyEffect::kErode_MorphologyType:
39930ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf("\t\t%s = vec4(1, 1, 1, 1);\n", outputColor);
40084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org            func = "min";
40184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org            break;
40284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org        case GrMorphologyEffect::kDilate_MorphologyType:
40330ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
40484207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org            func = "max";
40584207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org            break;
40684207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org        default:
40788cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org            SkFAIL("Unexpected type");
40884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org            func = ""; // suppress warning
40984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org            break;
41084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    }
41184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
41280a61df691bd5756dfbcbc57441806f2594511d8cwallez    const char* dir;
41380a61df691bd5756dfbcbc57441806f2594511d8cwallez    switch (fDirection) {
41480a61df691bd5756dfbcbc57441806f2594511d8cwallez        case Gr1DKernelEffect::kX_Direction:
41580a61df691bd5756dfbcbc57441806f2594511d8cwallez            dir = "x";
41680a61df691bd5756dfbcbc57441806f2594511d8cwallez            break;
41780a61df691bd5756dfbcbc57441806f2594511d8cwallez        case Gr1DKernelEffect::kY_Direction:
41880a61df691bd5756dfbcbc57441806f2594511d8cwallez            dir = "y";
41980a61df691bd5756dfbcbc57441806f2594511d8cwallez            break;
42080a61df691bd5756dfbcbc57441806f2594511d8cwallez        default:
42180a61df691bd5756dfbcbc57441806f2594511d8cwallez            SkFAIL("Unknown filter direction.");
42280a61df691bd5756dfbcbc57441806f2594511d8cwallez            dir = ""; // suppress warning
42380a61df691bd5756dfbcbc57441806f2594511d8cwallez    }
42480a61df691bd5756dfbcbc57441806f2594511d8cwallez
42580a61df691bd5756dfbcbc57441806f2594511d8cwallez    // vec2 coord = coord2D;
42680a61df691bd5756dfbcbc57441806f2594511d8cwallez    fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
42780a61df691bd5756dfbcbc57441806f2594511d8cwallez    // coord.x -= radius * pixelSize;
42880a61df691bd5756dfbcbc57441806f2594511d8cwallez    fsBuilder->codeAppendf("\t\tcoord.%s -= %d.0 * %s; \n", dir, fRadius, pixelSizeInc);
42980a61df691bd5756dfbcbc57441806f2594511d8cwallez    if (fUseRange) {
43080a61df691bd5756dfbcbc57441806f2594511d8cwallez        // highBound = min(highBound, coord.x + (width-1) * pixelSize);
43180a61df691bd5756dfbcbc57441806f2594511d8cwallez        fsBuilder->codeAppendf("\t\tfloat highBound = min(%s.y, coord.%s + %f * %s);",
43280a61df691bd5756dfbcbc57441806f2594511d8cwallez                               range, dir, float(width() - 1), pixelSizeInc);
43380a61df691bd5756dfbcbc57441806f2594511d8cwallez        // coord.x = max(lowBound, coord.x);
43480a61df691bd5756dfbcbc57441806f2594511d8cwallez        fsBuilder->codeAppendf("\t\tcoord.%s = max(%s.x, coord.%s);", dir, range, dir);
43580a61df691bd5756dfbcbc57441806f2594511d8cwallez    }
43680a61df691bd5756dfbcbc57441806f2594511d8cwallez    fsBuilder->codeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", width());
43730ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\t\t\t%s = %s(%s, ", outputColor, func, outputColor);
43830ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->appendTextureLookup(samplers[0], "coord");
43930ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppend(");\n");
44080a61df691bd5756dfbcbc57441806f2594511d8cwallez    // coord.x += pixelSize;
44180a61df691bd5756dfbcbc57441806f2594511d8cwallez    fsBuilder->codeAppendf("\t\t\tcoord.%s += %s;\n", dir, pixelSizeInc);
44280a61df691bd5756dfbcbc57441806f2594511d8cwallez    if (fUseRange) {
44380a61df691bd5756dfbcbc57441806f2594511d8cwallez        // coord.x = min(highBound, coord.x);
44480a61df691bd5756dfbcbc57441806f2594511d8cwallez        fsBuilder->codeAppendf("\t\t\tcoord.%s = min(highBound, coord.%s);", dir, dir);
44580a61df691bd5756dfbcbc57441806f2594511d8cwallez    }
44630ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppend("\t\t}\n");
447f910d3b23bcf590ee937628dbab8e39a98ee5860bsalomon@google.com    SkString modulate;
448089f8de82d6c342faa9170d8c19d8504177bf5fbegdaniel    GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
44930ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppend(modulate.c_str());
45084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org}
45184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
452b0a8a377f832c59cee939ad721e1f87d378b7142joshualittvoid GrGLMorphologyEffect::GenKey(const GrProcessor& proc,
453cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                  const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
454b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>();
45563e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    uint32_t key = static_cast<uint32_t>(m.radius());
45684207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    key |= (m.type() << 8);
45780a61df691bd5756dfbcbc57441806f2594511d8cwallez    key |= (m.direction() << 9);
45880a61df691bd5756dfbcbc57441806f2594511d8cwallez    if (m.useRange()) key |= 1 << 10;
45963e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    b->add32(key);
46084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org}
46184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
4627510b224e52b9518a8ddf7418db0e9c258f79539kkinnunenvoid GrGLMorphologyEffect::setData(const GrGLProgramDataManager& pdman,
463b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                   const GrProcessor& proc) {
46480a61df691bd5756dfbcbc57441806f2594511d8cwallez    const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>();
46580a61df691bd5756dfbcbc57441806f2594511d8cwallez    GrTexture& texture = *m.texture(0);
46680a61df691bd5756dfbcbc57441806f2594511d8cwallez    // the code we generated was for a specific kernel radius, direction and bound usage
46780a61df691bd5756dfbcbc57441806f2594511d8cwallez    SkASSERT(m.radius() == fRadius);
46880a61df691bd5756dfbcbc57441806f2594511d8cwallez    SkASSERT(m.direction() == fDirection);
46980a61df691bd5756dfbcbc57441806f2594511d8cwallez    SkASSERT(m.useRange() == fUseRange);
47080a61df691bd5756dfbcbc57441806f2594511d8cwallez
47180a61df691bd5756dfbcbc57441806f2594511d8cwallez    float pixelSize = 0.0f;
47280a61df691bd5756dfbcbc57441806f2594511d8cwallez    switch (fDirection) {
47384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org        case Gr1DKernelEffect::kX_Direction:
47480a61df691bd5756dfbcbc57441806f2594511d8cwallez            pixelSize = 1.0f / texture.width();
47584207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org            break;
47684207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org        case Gr1DKernelEffect::kY_Direction:
47780a61df691bd5756dfbcbc57441806f2594511d8cwallez            pixelSize = 1.0f / texture.height();
47884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org            break;
47984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org        default:
48088cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org            SkFAIL("Unknown filter direction.");
48184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    }
48280a61df691bd5756dfbcbc57441806f2594511d8cwallez    pdman.set1f(fPixelSizeUni, pixelSize);
48380a61df691bd5756dfbcbc57441806f2594511d8cwallez
48480a61df691bd5756dfbcbc57441806f2594511d8cwallez    if (fUseRange) {
48580a61df691bd5756dfbcbc57441806f2594511d8cwallez        const float* range = m.range();
48680a61df691bd5756dfbcbc57441806f2594511d8cwallez        if (fDirection && texture.origin() == kBottomLeft_GrSurfaceOrigin) {
48780a61df691bd5756dfbcbc57441806f2594511d8cwallez            pdman.set2f(fRangeUni, 1.0f - range[1], 1.0f - range[0]);
48880a61df691bd5756dfbcbc57441806f2594511d8cwallez        } else {
48980a61df691bd5756dfbcbc57441806f2594511d8cwallez            pdman.set2f(fRangeUni, range[0], range[1]);
49080a61df691bd5756dfbcbc57441806f2594511d8cwallez        }
49180a61df691bd5756dfbcbc57441806f2594511d8cwallez    }
49284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org}
49384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
49484207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
49584207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
49684207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.orgGrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
49784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org                                       Direction direction,
49884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org                                       int radius,
49984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org                                       MorphologyType type)
50084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    : Gr1DKernelEffect(texture, direction, radius)
50180a61df691bd5756dfbcbc57441806f2594511d8cwallez    , fType(type), fUseRange(false) {
502eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    this->initClassID<GrMorphologyEffect>();
50384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org}
50484207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
50580a61df691bd5756dfbcbc57441806f2594511d8cwallezGrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
50680a61df691bd5756dfbcbc57441806f2594511d8cwallez                                       Direction direction,
50780a61df691bd5756dfbcbc57441806f2594511d8cwallez                                       int radius,
50880a61df691bd5756dfbcbc57441806f2594511d8cwallez                                       MorphologyType type,
50980a61df691bd5756dfbcbc57441806f2594511d8cwallez                                       float range[2])
51080a61df691bd5756dfbcbc57441806f2594511d8cwallez    : Gr1DKernelEffect(texture, direction, radius)
51180a61df691bd5756dfbcbc57441806f2594511d8cwallez    , fType(type), fUseRange(true) {
51280a61df691bd5756dfbcbc57441806f2594511d8cwallez    this->initClassID<GrMorphologyEffect>();
51380a61df691bd5756dfbcbc57441806f2594511d8cwallez    fRange[0] = range[0];
51480a61df691bd5756dfbcbc57441806f2594511d8cwallez    fRange[1] = range[1];
51580a61df691bd5756dfbcbc57441806f2594511d8cwallez}
51680a61df691bd5756dfbcbc57441806f2594511d8cwallez
51784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.orgGrMorphologyEffect::~GrMorphologyEffect() {
51884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org}
51984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
520cfc18867d982119d9dc2888bf09f1093012daaddjvanverthvoid GrMorphologyEffect::getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
521eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    GrGLMorphologyEffect::GenKey(*this, caps, b);
52284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org}
52384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
524eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualittGrGLFragmentProcessor* GrMorphologyEffect::createGLInstance() const {
525eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    return SkNEW_ARGS(GrGLMorphologyEffect, (*this));
526eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
5270e08fc17e4718f7ce4e38f793695896473e96948bsalomonbool GrMorphologyEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
52849586bec7383d4ccb81f85f8e2dc4162e2d4f6a8joshualitt    const GrMorphologyEffect& s = sBase.cast<GrMorphologyEffect>();
529420d7e9a79358908850c74192b4949375563449absalomon    return (this->radius() == s.radius() &&
53084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org            this->direction() == s.direction() &&
53180a61df691bd5756dfbcbc57441806f2594511d8cwallez            this->useRange() == s.useRange() &&
53284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org            this->type() == s.type());
53384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org}
53484207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
535605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdanielvoid GrMorphologyEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
53668b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com    // This is valid because the color components of the result of the kernel all come
53768b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com    // exactly from existing values in the source texture.
5381a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel    this->updateInvariantOutputForModulation(inout);
53968b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com}
54068b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com
54184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org///////////////////////////////////////////////////////////////////////////////
54284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
543b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMorphologyEffect);
54484207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
545b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrFragmentProcessor* GrMorphologyEffect::TestCreate(SkRandom* random,
546b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                    GrContext*,
547b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                    const GrDrawTargetCaps&,
548b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                    GrTexture* textures[]) {
549b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
550b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                      GrProcessorUnitTest::kAlphaTextureIdx;
55184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    Direction dir = random->nextBool() ? kX_Direction : kY_Direction;
55284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    static const int kMaxRadius = 10;
55384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    int radius = random->nextRangeU(1, kMaxRadius);
55484207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    MorphologyType type = random->nextBool() ? GrMorphologyEffect::kErode_MorphologyType :
55584207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org                                               GrMorphologyEffect::kDilate_MorphologyType;
55684207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
5570ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com    return GrMorphologyEffect::Create(textures[texIdx], dir, radius, type);
55884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org}
55984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
56084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.orgnamespace {
56184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
56280a61df691bd5756dfbcbc57441806f2594511d8cwallez
56380a61df691bd5756dfbcbc57441806f2594511d8cwallezvoid apply_morphology_rect(GrContext* context,
56425d9c154087d2132a51d1ca74a104726f60ef380joshualitt                           GrRenderTarget* rt,
565570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                           const GrClip& clip,
56680a61df691bd5756dfbcbc57441806f2594511d8cwallez                           GrTexture* texture,
56780a61df691bd5756dfbcbc57441806f2594511d8cwallez                           const SkIRect& srcRect,
56880a61df691bd5756dfbcbc57441806f2594511d8cwallez                           const SkIRect& dstRect,
56980a61df691bd5756dfbcbc57441806f2594511d8cwallez                           int radius,
57080a61df691bd5756dfbcbc57441806f2594511d8cwallez                           GrMorphologyEffect::MorphologyType morphType,
57180a61df691bd5756dfbcbc57441806f2594511d8cwallez                           float bounds[2],
57280a61df691bd5756dfbcbc57441806f2594511d8cwallez                           Gr1DKernelEffect::Direction direction) {
57380a61df691bd5756dfbcbc57441806f2594511d8cwallez    GrPaint paint;
57480a61df691bd5756dfbcbc57441806f2594511d8cwallez    paint.addColorProcessor(GrMorphologyEffect::Create(texture,
57580a61df691bd5756dfbcbc57441806f2594511d8cwallez                                                       direction,
57680a61df691bd5756dfbcbc57441806f2594511d8cwallez                                                       radius,
57780a61df691bd5756dfbcbc57441806f2594511d8cwallez                                                       morphType,
57880a61df691bd5756dfbcbc57441806f2594511d8cwallez                                                       bounds))->unref();
579570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt    context->drawNonAARectToRect(rt, clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
58025d9c154087d2132a51d1ca74a104726f60ef380joshualitt                                 SkRect::Make(srcRect));
58180a61df691bd5756dfbcbc57441806f2594511d8cwallez}
58280a61df691bd5756dfbcbc57441806f2594511d8cwallez
58380a61df691bd5756dfbcbc57441806f2594511d8cwallezvoid apply_morphology_rect_no_bounds(GrContext* context,
58425d9c154087d2132a51d1ca74a104726f60ef380joshualitt                                     GrRenderTarget* rt,
585570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                                     const GrClip& clip,
58625d9c154087d2132a51d1ca74a104726f60ef380joshualitt                                     GrTexture* texture,
58725d9c154087d2132a51d1ca74a104726f60ef380joshualitt                                     const SkIRect& srcRect,
58825d9c154087d2132a51d1ca74a104726f60ef380joshualitt                                     const SkIRect& dstRect,
58925d9c154087d2132a51d1ca74a104726f60ef380joshualitt                                     int radius,
59025d9c154087d2132a51d1ca74a104726f60ef380joshualitt                                     GrMorphologyEffect::MorphologyType morphType,
59125d9c154087d2132a51d1ca74a104726f60ef380joshualitt                                     Gr1DKernelEffect::Direction direction) {
59284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    GrPaint paint;
593b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    paint.addColorProcessor(GrMorphologyEffect::Create(texture,
594b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                       direction,
595b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                       radius,
596b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                       morphType))->unref();
597570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt    context->drawNonAARectToRect(rt, clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
59825d9c154087d2132a51d1ca74a104726f60ef380joshualitt                                 SkRect::Make(srcRect));
59984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org}
60084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
60180a61df691bd5756dfbcbc57441806f2594511d8cwallezvoid apply_morphology_pass(GrContext* context,
60225d9c154087d2132a51d1ca74a104726f60ef380joshualitt                           GrRenderTarget* rt,
603570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                           const GrClip& clip,
60480a61df691bd5756dfbcbc57441806f2594511d8cwallez                           GrTexture* texture,
60580a61df691bd5756dfbcbc57441806f2594511d8cwallez                           const SkIRect& srcRect,
60680a61df691bd5756dfbcbc57441806f2594511d8cwallez                           const SkIRect& dstRect,
60780a61df691bd5756dfbcbc57441806f2594511d8cwallez                           int radius,
60880a61df691bd5756dfbcbc57441806f2594511d8cwallez                           GrMorphologyEffect::MorphologyType morphType,
60980a61df691bd5756dfbcbc57441806f2594511d8cwallez                           Gr1DKernelEffect::Direction direction) {
61080a61df691bd5756dfbcbc57441806f2594511d8cwallez    float bounds[2] = { 0.0f, 1.0f };
61180a61df691bd5756dfbcbc57441806f2594511d8cwallez    SkIRect lowerSrcRect = srcRect, lowerDstRect = dstRect;
61280a61df691bd5756dfbcbc57441806f2594511d8cwallez    SkIRect middleSrcRect = srcRect, middleDstRect = dstRect;
61380a61df691bd5756dfbcbc57441806f2594511d8cwallez    SkIRect upperSrcRect = srcRect, upperDstRect = dstRect;
61480a61df691bd5756dfbcbc57441806f2594511d8cwallez    if (direction == Gr1DKernelEffect::kX_Direction) {
61580a61df691bd5756dfbcbc57441806f2594511d8cwallez        bounds[0] = (SkIntToScalar(srcRect.left()) + 0.5f) / texture->width();
61680a61df691bd5756dfbcbc57441806f2594511d8cwallez        bounds[1] = (SkIntToScalar(srcRect.right()) - 0.5f) / texture->width();
61780a61df691bd5756dfbcbc57441806f2594511d8cwallez        lowerSrcRect.fRight = srcRect.left() + radius;
61880a61df691bd5756dfbcbc57441806f2594511d8cwallez        lowerDstRect.fRight = dstRect.left() + radius;
61980a61df691bd5756dfbcbc57441806f2594511d8cwallez        upperSrcRect.fLeft = srcRect.right() - radius;
62080a61df691bd5756dfbcbc57441806f2594511d8cwallez        upperDstRect.fLeft = dstRect.right() - radius;
62180a61df691bd5756dfbcbc57441806f2594511d8cwallez        middleSrcRect.inset(radius, 0);
62280a61df691bd5756dfbcbc57441806f2594511d8cwallez        middleDstRect.inset(radius, 0);
62380a61df691bd5756dfbcbc57441806f2594511d8cwallez    } else {
62480a61df691bd5756dfbcbc57441806f2594511d8cwallez        bounds[0] = (SkIntToScalar(srcRect.top()) + 0.5f) / texture->height();
62580a61df691bd5756dfbcbc57441806f2594511d8cwallez        bounds[1] = (SkIntToScalar(srcRect.bottom()) - 0.5f) / texture->height();
62680a61df691bd5756dfbcbc57441806f2594511d8cwallez        lowerSrcRect.fBottom = srcRect.top() + radius;
62780a61df691bd5756dfbcbc57441806f2594511d8cwallez        lowerDstRect.fBottom = dstRect.top() + radius;
62880a61df691bd5756dfbcbc57441806f2594511d8cwallez        upperSrcRect.fTop = srcRect.bottom() - radius;
62980a61df691bd5756dfbcbc57441806f2594511d8cwallez        upperDstRect.fTop = dstRect.bottom() - radius;
63080a61df691bd5756dfbcbc57441806f2594511d8cwallez        middleSrcRect.inset(0, radius);
63180a61df691bd5756dfbcbc57441806f2594511d8cwallez        middleDstRect.inset(0, radius);
63280a61df691bd5756dfbcbc57441806f2594511d8cwallez    }
63380a61df691bd5756dfbcbc57441806f2594511d8cwallez    if (middleSrcRect.fLeft - middleSrcRect.fRight >= 0) {
63480a61df691bd5756dfbcbc57441806f2594511d8cwallez        // radius covers srcRect; use bounds over entire draw
635570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt        apply_morphology_rect(context, rt, clip, texture, srcRect, dstRect, radius,
63680a61df691bd5756dfbcbc57441806f2594511d8cwallez                              morphType, bounds, direction);
63780a61df691bd5756dfbcbc57441806f2594511d8cwallez    } else {
63880a61df691bd5756dfbcbc57441806f2594511d8cwallez        // Draw upper and lower margins with bounds; middle without.
639570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt        apply_morphology_rect(context, rt, clip, texture, lowerSrcRect, lowerDstRect, radius,
64080a61df691bd5756dfbcbc57441806f2594511d8cwallez                              morphType, bounds, direction);
641570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt        apply_morphology_rect(context, rt, clip, texture, upperSrcRect, upperDstRect, radius,
64280a61df691bd5756dfbcbc57441806f2594511d8cwallez                              morphType, bounds, direction);
643570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt        apply_morphology_rect_no_bounds(context, rt, clip, texture, middleSrcRect, middleDstRect,
644570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                                        radius, morphType, direction);
64580a61df691bd5756dfbcbc57441806f2594511d8cwallez    }
64680a61df691bd5756dfbcbc57441806f2594511d8cwallez}
64780a61df691bd5756dfbcbc57441806f2594511d8cwallez
6488fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.orgbool apply_morphology(const SkBitmap& input,
6498fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org                      const SkIRect& rect,
6508fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org                      GrMorphologyEffect::MorphologyType morphType,
6518fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org                      SkISize radius,
6528fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org                      SkBitmap* dst) {
653e30597375c19dfb5197fd065a3d1768401eb00fabsalomon    SkAutoTUnref<GrTexture> srcTexture(SkRef(input.getTexture()));
65449f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(srcTexture);
65584207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    GrContext* context = srcTexture->getContext();
6563cbaa2d4da8bc39a99bf3afaaab43cc6dc481723bsalomon@google.com
657570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt    // setup new clip
658570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt    GrClip clip(SkRect::MakeWH(SkIntToScalar(srcTexture->width()),
659570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                               SkIntToScalar(srcTexture->height())));
6603cbaa2d4da8bc39a99bf3afaaab43cc6dc481723bsalomon@google.com
6618fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org    SkIRect dstRect = SkIRect::MakeWH(rect.width(), rect.height());
662f2703d83da3ab2ae18b45231fd4f11e16cce3184bsalomon    GrSurfaceDesc desc;
6636bc1b5fab8554a9cb643277b4867965dd4535cd6bsalomon    desc.fFlags = kRenderTarget_GrSurfaceFlag;
664c2594f41066102d7a8a73effd3c574142a018b9asenorblanco@chromium.org    desc.fWidth = rect.width();
665c2594f41066102d7a8a73effd3c574142a018b9asenorblanco@chromium.org    desc.fHeight = rect.height();
666c2594f41066102d7a8a73effd3c574142a018b9asenorblanco@chromium.org    desc.fConfig = kSkia8888_GrPixelConfig;
6678fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org    SkIRect srcRect = rect;
6683cbaa2d4da8bc39a99bf3afaaab43cc6dc481723bsalomon@google.com
66984207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    if (radius.fWidth > 0) {
670d309e7aa0efa2d5dd7e7b1af97026fcd3a047e98bsalomon        GrTexture* texture = context->textureProvider()->refScratchTexture(
671d309e7aa0efa2d5dd7e7b1af97026fcd3a047e98bsalomon            desc, GrTextureProvider::kApprox_ScratchTexMatch);
672e30597375c19dfb5197fd065a3d1768401eb00fabsalomon        if (NULL == texture) {
673673d9732bf37df724500e04afcdf27d5c711ef60senorblanco            return false;
674673d9732bf37df724500e04afcdf27d5c711ef60senorblanco        }
675570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt        apply_morphology_pass(context, texture->asRenderTarget(), clip, srcTexture,
676570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                              srcRect, dstRect, radius.fWidth, morphType,
677570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                              Gr1DKernelEffect::kX_Direction);
6788fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org        SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom,
6798fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org                                              dstRect.width(), radius.fHeight);
68089c62980c1eb50b2090f33312086c7e8c66739b4bsalomon        GrColor clearColor = GrMorphologyEffect::kErode_MorphologyType == morphType ?
68189c62980c1eb50b2090f33312086c7e8c66739b4bsalomon                                SK_ColorWHITE :
68289c62980c1eb50b2090f33312086c7e8c66739b4bsalomon                                SK_ColorTRANSPARENT;
68389c62980c1eb50b2090f33312086c7e8c66739b4bsalomon        context->clear(&clearRect, clearColor, false, texture->asRenderTarget());
684e30597375c19dfb5197fd065a3d1768401eb00fabsalomon        srcTexture.reset(texture);
6858fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org        srcRect = dstRect;
68684207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    }
68784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    if (radius.fHeight > 0) {
688d309e7aa0efa2d5dd7e7b1af97026fcd3a047e98bsalomon        GrTexture* texture = context->textureProvider()->refScratchTexture(desc,
689d309e7aa0efa2d5dd7e7b1af97026fcd3a047e98bsalomon            GrTextureProvider::kApprox_ScratchTexMatch);
690e30597375c19dfb5197fd065a3d1768401eb00fabsalomon        if (NULL == texture) {
691673d9732bf37df724500e04afcdf27d5c711ef60senorblanco            return false;
692673d9732bf37df724500e04afcdf27d5c711ef60senorblanco        }
693570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt        apply_morphology_pass(context, texture->asRenderTarget(), clip, srcTexture,
694570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                              srcRect, dstRect, radius.fHeight, morphType,
695570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                              Gr1DKernelEffect::kY_Direction);
696e30597375c19dfb5197fd065a3d1768401eb00fabsalomon        srcTexture.reset(texture);
69784207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org    }
698e30597375c19dfb5197fd065a3d1768401eb00fabsalomon    SkImageFilter::WrapTexture(srcTexture, rect.width(), rect.height(), dst);
6996aa6fec0e332c9246958245bad5fc881fefee68fsenorblanco@chromium.org    return true;
70084207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org}
70184207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
70284207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org};
70384207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org
7040ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.orgbool SkMorphologyImageFilter::filterImageGPUGeneric(bool dilate,
7050ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org                                                    Proxy* proxy,
7060ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org                                                    const SkBitmap& src,
7074cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org                                                    const Context& ctx,
7080ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org                                                    SkBitmap* result,
709ae761f7545d8ebf181d220169afac2056b057b8ccommit-bot@chromium.org                                                    SkIPoint* offset) const {
7106aa6fec0e332c9246958245bad5fc881fefee68fsenorblanco@chromium.org    SkBitmap input = src;
7112bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    SkIPoint srcOffset = SkIPoint::Make(0, 0);
7124cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    if (getInput(0) && !getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
713c2594f41066102d7a8a73effd3c574142a018b9asenorblanco@chromium.org        return false;
714c2594f41066102d7a8a73effd3c574142a018b9asenorblanco@chromium.org    }
715c2594f41066102d7a8a73effd3c574142a018b9asenorblanco@chromium.org    SkIRect bounds;
716118252962f89a80db661a0544f1bd61cbaab6321senorblanco@chromium.org    if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
7178fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org        return false;
7188fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org    }
7192bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
7202bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org                                     SkIntToScalar(this->radius().height()));
7214cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    ctx.ctm().mapVectors(&radius, 1);
7222bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    int width = SkScalarFloorToInt(radius.fX);
7232bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    int height = SkScalarFloorToInt(radius.fY);
7248fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org
7258fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org    if (width < 0 || height < 0) {
7268fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org        return false;
7278fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org    }
7288fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org
7292bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    SkIRect srcBounds = bounds;
7302bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    srcBounds.offset(-srcOffset);
7318fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org    if (width == 0 && height == 0) {
7322bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org        input.extractSubset(result, srcBounds);
7336776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org        offset->fX = bounds.left();
7346776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org        offset->fY = bounds.top();
7358fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org        return true;
7368fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org    }
7378fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org
7380ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    GrMorphologyEffect::MorphologyType type = dilate ? GrMorphologyEffect::kDilate_MorphologyType : GrMorphologyEffect::kErode_MorphologyType;
7390ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org    if (!apply_morphology(input, srcBounds, type,
7402bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org                          SkISize::Make(width, height), result)) {
7418fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org        return false;
7428fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org    }
7436776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fX = bounds.left();
7446776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fY = bounds.top();
7458fcad9879173d627ee8638c52709d924034e34cesenorblanco@chromium.org    return true;
74605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org}
74705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
7484cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.orgbool SkDilateImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
749ae761f7545d8ebf181d220169afac2056b057b8ccommit-bot@chromium.org                                         SkBitmap* result, SkIPoint* offset) const {
7504cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    return this->filterImageGPUGeneric(true, proxy, src, ctx, result, offset);
7510ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org}
7520ded88d431a1872e21986984f009db2e84f52738senorblanco@chromium.org
7534cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.orgbool SkErodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
754ae761f7545d8ebf181d220169afac2056b057b8ccommit-bot@chromium.org                                        SkBitmap* result, SkIPoint* offset) const {
7554cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    return this->filterImageGPUGeneric(false, proxy, src, ctx, result, offset);
75605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org}
75705054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
75884207c42789e67ef377befb0c9057b9b73fbd6e3senorblanco@chromium.org#endif
759