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