140a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org/*
240a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org * Copyright 2012 The Android Open Source Project
340a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org *
440a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org * Use of this source code is governed by a BSD-style license that can be
540a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org * found in the LICENSE file.
640a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org */
740a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org
840a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org#include "SkImageFilter.h"
930ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org
1030ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org#include "SkBitmap.h"
1130ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org#include "SkFlattenableBuffers.h"
1240a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org#include "SkRect.h"
132f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org#if SK_SUPPORT_GPU
142f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org#include "GrContext.h"
152f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org#include "GrTexture.h"
162f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org#include "SkImageFilterUtils.h"
172f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org#endif
1840a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org
1940a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.orgSK_DEFINE_INST_COUNT(SkImageFilter)
2040a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org
21c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.orgSkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const SkIRect* cropRect)
22c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org  : fInputCount(inputCount),
23c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org    fInputs(new SkImageFilter*[inputCount]),
24c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org    fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
2552b453755a3f9f0bb43d4631f0a189246a99cedcsenorblanco@chromium.org    for (int i = 0; i < inputCount; ++i) {
2630ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org        fInputs[i] = inputs[i];
2730ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org        SkSafeRef(fInputs[i]);
2830ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org    }
2930ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org}
3030ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org
31c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.orgSkImageFilter::SkImageFilter(SkImageFilter* input, const SkIRect* cropRect)
32c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org  : fInputCount(1),
33c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org    fInputs(new SkImageFilter*[1]),
34c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org    fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
35633e80d26879db936d77962eae3d50ca9ad99fbcsenorblanco@chromium.org    fInputs[0] = input;
36633e80d26879db936d77962eae3d50ca9ad99fbcsenorblanco@chromium.org    SkSafeRef(fInputs[0]);
37633e80d26879db936d77962eae3d50ca9ad99fbcsenorblanco@chromium.org}
38633e80d26879db936d77962eae3d50ca9ad99fbcsenorblanco@chromium.org
39c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.orgSkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const SkIRect* cropRect)
40c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org  : fInputCount(2), fInputs(new SkImageFilter*[2]),
41c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org  fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
42633e80d26879db936d77962eae3d50ca9ad99fbcsenorblanco@chromium.org    fInputs[0] = input1;
43633e80d26879db936d77962eae3d50ca9ad99fbcsenorblanco@chromium.org    fInputs[1] = input2;
44633e80d26879db936d77962eae3d50ca9ad99fbcsenorblanco@chromium.org    SkSafeRef(fInputs[0]);
45633e80d26879db936d77962eae3d50ca9ad99fbcsenorblanco@chromium.org    SkSafeRef(fInputs[1]);
4630ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org}
4730ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org
4830ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.orgSkImageFilter::~SkImageFilter() {
4952b453755a3f9f0bb43d4631f0a189246a99cedcsenorblanco@chromium.org    for (int i = 0; i < fInputCount; i++) {
5030ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org        SkSafeUnref(fInputs[i]);
5130ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org    }
5230ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org    delete[] fInputs;
5330ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org}
5430ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org
556dfcd8019c80e926683b6173db149da8b3524b99skia.committer@gmail.comSkImageFilter::SkImageFilter(SkFlattenableReadBuffer& buffer)
5652b453755a3f9f0bb43d4631f0a189246a99cedcsenorblanco@chromium.org    : fInputCount(buffer.readInt()), fInputs(new SkImageFilter*[fInputCount]) {
5752b453755a3f9f0bb43d4631f0a189246a99cedcsenorblanco@chromium.org    for (int i = 0; i < fInputCount; i++) {
5830ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org        if (buffer.readBool()) {
5930ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org            fInputs[i] = static_cast<SkImageFilter*>(buffer.readFlattenable());
6030ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org        } else {
6130ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org            fInputs[i] = NULL;
6230ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org        }
6330ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org    }
64c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org    buffer.readIRect(&fCropRect);
6530ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org}
6630ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org
6730ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.orgvoid SkImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
6852b453755a3f9f0bb43d4631f0a189246a99cedcsenorblanco@chromium.org    buffer.writeInt(fInputCount);
6952b453755a3f9f0bb43d4631f0a189246a99cedcsenorblanco@chromium.org    for (int i = 0; i < fInputCount; i++) {
7030ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org        SkImageFilter* input = getInput(i);
7130ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org        buffer.writeBool(input != NULL);
7230ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org        if (input != NULL) {
7330ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org            buffer.writeFlattenable(input);
7430ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org        }
7530ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org    }
76c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org    buffer.writeIRect(fCropRect);
7730ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org}
7830ac0dbd00cc752c5a4bb3127bea8de624de37c3senorblanco@chromium.org
7940a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.orgbool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
8040a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org                                const SkMatrix& ctm,
8140a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org                                SkBitmap* result, SkIPoint* loc) {
8240a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org    SkASSERT(result);
8340a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org    SkASSERT(loc);
8440a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org    /*
8540a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org     *  Give the proxy first shot at the filter. If it returns false, ask
8640a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org     *  the filter to do it.
8740a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org     */
8840a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org    return (proxy && proxy->filterImage(this, src, ctm, result, loc)) ||
8940a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org           this->onFilterImage(proxy, src, ctm, result, loc);
9040a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org}
9140a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org
9240a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.orgbool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
9340a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org                                 SkIRect* dst) {
9440a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org    SkASSERT(&src);
9540a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org    SkASSERT(dst);
9640a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org    return this->onFilterBounds(src, ctm, dst);
9740a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org}
9840a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org
9940a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.orgbool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
10040a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org                                  SkBitmap*, SkIPoint*) {
10140a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org    return false;
10240a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org}
10340a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org
10440a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.orgbool SkImageFilter::canFilterImageGPU() const {
105846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    return this->asNewEffect(NULL, NULL, SkIPoint::Make(0, 0));
10640a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org}
10740a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org
1086bdc8c54bc474b0a2abe4c0d9bdd47b8e3d29ef6commit-bot@chromium.orgbool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
1096bdc8c54bc474b0a2abe4c0d9bdd47b8e3d29ef6commit-bot@chromium.org                                   SkBitmap* result, SkIPoint* offset) {
1102f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org#if SK_SUPPORT_GPU
1112f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    SkBitmap input;
1122f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    SkASSERT(fInputCount == 1);
1136bdc8c54bc474b0a2abe4c0d9bdd47b8e3d29ef6commit-bot@chromium.org    if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, ctm, &input, offset)) {
1142f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org        return false;
1152f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    }
11687816f8e3e4e8633221d6e2c20c2ecdab3b6b6fccommit-bot@chromium.org    GrTexture* srcTexture = input.getTexture();
117846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    SkIRect bounds;
118846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    src.getBounds(&bounds);
119846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    if (!this->applyCropRect(&bounds)) {
120846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org        return false;
121846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    }
122846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    SkRect srcRect = SkRect::Make(bounds);
123846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
1242f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    GrContext* context = srcTexture->getContext();
1252f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org
1262f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    GrTextureDesc desc;
1272f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    desc.fFlags = kRenderTarget_GrTextureFlagBit,
128846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    desc.fWidth = bounds.width();
129846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    desc.fHeight = bounds.height();
1302f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    desc.fConfig = kRGBA_8888_GrPixelConfig;
1312f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org
1322f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    GrAutoScratchTexture dst(context, desc);
1332f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    GrContext::AutoMatrix am;
1342f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    am.setIdentity(context);
1352f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget());
136846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    GrContext::AutoClip acs(context, dstRect);
1372f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    GrEffectRef* effect;
138846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    this->asNewEffect(&effect, srcTexture, SkIPoint::Make(bounds.left(), bounds.top()));
1392f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    SkASSERT(effect);
1402f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    SkAutoUnref effectRef(effect);
1412f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    GrPaint paint;
1424de2cfb9a63682aa6624f781a7454956ef6619a7commit-bot@chromium.org    paint.addColorEffect(effect);
143846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    context->drawRectToRect(paint, dstRect, srcRect);
144846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org
1452f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    SkAutoTUnref<GrTexture> resultTex(dst.detach());
146846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    SkImageFilterUtils::WrapTexture(resultTex, bounds.width(), bounds.height(), result);
147846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    offset->fX += bounds.left();
148846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.org    offset->fY += bounds.top();
1492f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org    return true;
1502f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org#else
151868224802ab329ab4eb527ba07ea660bdcac60f7senorblanco@chromium.org    return false;
1522f91984aefff09d732188437c374b82a863e6754senorblanco@chromium.org#endif
15340a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org}
15440a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org
155c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.orgbool SkImageFilter::applyCropRect(SkIRect* rect) const {
156c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org    return rect->intersect(fCropRect);
157c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org}
158c97456b20f8c3496ca88c48f82bb4428399b15cfsenorblanco@chromium.org
15940a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.orgbool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
16040a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org                                   SkIRect* dst) {
16140a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org    *dst = src;
16240a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org    return true;
16340a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org}
16440a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org
165846089636a8b41a1bcfc370159fd1aa9ec7625c6senorblanco@chromium.orgbool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkIPoint& offset) const {
16640a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org    return false;
16740a3e261f94e6bdfa35ccea7f43c6e462c7ce432senorblanco@chromium.org}
16852b453755a3f9f0bb43d4631f0a189246a99cedcsenorblanco@chromium.org
16989820941d3235c89e15142daae082da5b892e5d4sugoi@google.combool SkImageFilter::asColorFilter(SkColorFilter**) const {
17089820941d3235c89e15142daae082da5b892e5d4sugoi@google.com    return false;
17152b453755a3f9f0bb43d4631f0a189246a99cedcsenorblanco@chromium.org}
172