1/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkImageFilter.h"
9
10#include "SkBitmap.h"
11#include "SkFlattenableBuffers.h"
12#include "SkRect.h"
13#if SK_SUPPORT_GPU
14#include "GrContext.h"
15#include "GrTexture.h"
16#include "SkImageFilterUtils.h"
17#endif
18
19SK_DEFINE_INST_COUNT(SkImageFilter)
20
21SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const SkIRect* cropRect)
22  : fInputCount(inputCount),
23    fInputs(new SkImageFilter*[inputCount]),
24    fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
25    for (int i = 0; i < inputCount; ++i) {
26        fInputs[i] = inputs[i];
27        SkSafeRef(fInputs[i]);
28    }
29}
30
31SkImageFilter::SkImageFilter(SkImageFilter* input, const SkIRect* cropRect)
32  : fInputCount(1),
33    fInputs(new SkImageFilter*[1]),
34    fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
35    fInputs[0] = input;
36    SkSafeRef(fInputs[0]);
37}
38
39SkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const SkIRect* cropRect)
40  : fInputCount(2), fInputs(new SkImageFilter*[2]),
41  fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
42    fInputs[0] = input1;
43    fInputs[1] = input2;
44    SkSafeRef(fInputs[0]);
45    SkSafeRef(fInputs[1]);
46}
47
48SkImageFilter::~SkImageFilter() {
49    for (int i = 0; i < fInputCount; i++) {
50        SkSafeUnref(fInputs[i]);
51    }
52    delete[] fInputs;
53}
54
55SkImageFilter::SkImageFilter(SkFlattenableReadBuffer& buffer)
56    : fInputCount(buffer.readInt()), fInputs(new SkImageFilter*[fInputCount]) {
57    for (int i = 0; i < fInputCount; i++) {
58        if (buffer.readBool()) {
59            fInputs[i] = static_cast<SkImageFilter*>(buffer.readFlattenable());
60        } else {
61            fInputs[i] = NULL;
62        }
63    }
64    buffer.readIRect(&fCropRect);
65}
66
67void SkImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
68    buffer.writeInt(fInputCount);
69    for (int i = 0; i < fInputCount; i++) {
70        SkImageFilter* input = getInput(i);
71        buffer.writeBool(input != NULL);
72        if (input != NULL) {
73            buffer.writeFlattenable(input);
74        }
75    }
76    buffer.writeIRect(fCropRect);
77}
78
79bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
80                                const SkMatrix& ctm,
81                                SkBitmap* result, SkIPoint* loc) {
82    SkASSERT(result);
83    SkASSERT(loc);
84    /*
85     *  Give the proxy first shot at the filter. If it returns false, ask
86     *  the filter to do it.
87     */
88    return (proxy && proxy->filterImage(this, src, ctm, result, loc)) ||
89           this->onFilterImage(proxy, src, ctm, result, loc);
90}
91
92bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
93                                 SkIRect* dst) {
94    SkASSERT(&src);
95    SkASSERT(dst);
96    return this->onFilterBounds(src, ctm, dst);
97}
98
99bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
100                                  SkBitmap*, SkIPoint*) {
101    return false;
102}
103
104bool SkImageFilter::canFilterImageGPU() const {
105    return this->asNewEffect(NULL, NULL, SkIPoint::Make(0, 0));
106}
107
108bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
109                                   SkBitmap* result, SkIPoint* offset) {
110#if SK_SUPPORT_GPU
111    SkBitmap input;
112    SkASSERT(fInputCount == 1);
113    if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, ctm, &input, offset)) {
114        return false;
115    }
116    GrTexture* srcTexture = input.getTexture();
117    SkIRect bounds;
118    src.getBounds(&bounds);
119    if (!this->applyCropRect(&bounds)) {
120        return false;
121    }
122    SkRect srcRect = SkRect::Make(bounds);
123    SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
124    GrContext* context = srcTexture->getContext();
125
126    GrTextureDesc desc;
127    desc.fFlags = kRenderTarget_GrTextureFlagBit,
128    desc.fWidth = bounds.width();
129    desc.fHeight = bounds.height();
130    desc.fConfig = kRGBA_8888_GrPixelConfig;
131
132    GrAutoScratchTexture dst(context, desc);
133    GrContext::AutoMatrix am;
134    am.setIdentity(context);
135    GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget());
136    GrContext::AutoClip acs(context, dstRect);
137    GrEffectRef* effect;
138    this->asNewEffect(&effect, srcTexture, SkIPoint::Make(bounds.left(), bounds.top()));
139    SkASSERT(effect);
140    SkAutoUnref effectRef(effect);
141    GrPaint paint;
142    paint.addColorEffect(effect);
143    context->drawRectToRect(paint, dstRect, srcRect);
144
145    SkAutoTUnref<GrTexture> resultTex(dst.detach());
146    SkImageFilterUtils::WrapTexture(resultTex, bounds.width(), bounds.height(), result);
147    offset->fX += bounds.left();
148    offset->fY += bounds.top();
149    return true;
150#else
151    return false;
152#endif
153}
154
155bool SkImageFilter::applyCropRect(SkIRect* rect) const {
156    return rect->intersect(fCropRect);
157}
158
159bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
160                                   SkIRect* dst) {
161    *dst = src;
162    return true;
163}
164
165bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkIPoint& offset) const {
166    return false;
167}
168
169bool SkImageFilter::asColorFilter(SkColorFilter**) const {
170    return false;
171}
172