Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkImageFilter.cpp
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 "SkReadBuffer.h"
12 #include "SkWriteBuffer.h"
13 #include "SkRect.h"
14 #include "SkValidationUtils.h"
15 #if SK_SUPPORT_GPU
16 #include "GrContext.h"
17 #include "GrTexture.h"
18 #include "SkImageFilterUtils.h"
19 #endif
20
21 SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect)
22   : fInputCount(inputCount),
23     fInputs(new SkImageFilter*[inputCount]),
24     fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
25     for (int i = 0; i < inputCount; ++i) {
26         fInputs[i] = inputs[i];
27         SkSafeRef(fInputs[i]);
28     }
29 }
30
31 SkImageFilter::SkImageFilter(SkImageFilter* input, const CropRect* cropRect)
32   : fInputCount(1),
33     fInputs(new SkImageFilter*[1]),
34     fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
35     fInputs[0] = input;
36     SkSafeRef(fInputs[0]);
37 }
38
39 SkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const CropRect* cropRect)
40   : fInputCount(2), fInputs(new SkImageFilter*[2]),
41     fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
42     fInputs[0] = input1;
43     fInputs[1] = input2;
44     SkSafeRef(fInputs[0]);
45     SkSafeRef(fInputs[1]);
46 }
47
48 SkImageFilter::~SkImageFilter() {
49     for (int i = 0; i < fInputCount; i++) {
50         SkSafeUnref(fInputs[i]);
51     }
52     delete[] fInputs;
53 }
54
55 SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer) {
56     fInputCount = buffer.readInt();
57     if (buffer.validate((fInputCount >= 0) && ((inputCount < 0) || (fInputCount == inputCount)))) {
58         fInputs = new SkImageFilter*[fInputCount];
59         for (int i = 0; i < fInputCount; i++) {
60             if (buffer.readBool()) {
61                 fInputs[i] = buffer.readImageFilter();
62             } else {
63                 fInputs[i] = NULL;
64             }
65             if (!buffer.isValid()) {
66                 fInputCount = i; // Do not use fInputs past that point in the destructor
67                 break;
68             }
69         }
70         SkRect rect;
71         buffer.readRect(&rect);
72         if (buffer.isValid() && buffer.validate(SkIsValidRect(rect))) {
73             uint32_t flags = buffer.readUInt();
74             fCropRect = CropRect(rect, flags);
75         }
76     } else {
77         fInputCount = 0;
78         fInputs = NULL;
79     }
80 }
81
82 void SkImageFilter::flatten(SkWriteBuffer& buffer) const {
83     buffer.writeInt(fInputCount);
84     for (int i = 0; i < fInputCount; i++) {
85         SkImageFilter* input = getInput(i);
86         buffer.writeBool(input != NULL);
87         if (input != NULL) {
88             buffer.writeFlattenable(input);
89         }
90     }
91     buffer.writeRect(fCropRect.rect());
92     buffer.writeUInt(fCropRect.flags());
93 }
94
95 bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
96                                 const SkMatrix& ctm,
97                                 SkBitmap* result, SkIPoint* offset) const {
98     SkASSERT(result);
99     SkASSERT(offset);
100     /*
101      *  Give the proxy first shot at the filter. If it returns false, ask
102      *  the filter to do it.
103      */
104     return (proxy && proxy->filterImage(this, src, ctm, result, offset)) ||
105            this->onFilterImage(proxy, src, ctm, result, offset);
106 }
107
108 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
109                                  SkIRect* dst) const {
110     SkASSERT(&src);
111     SkASSERT(dst);
112     return this->onFilterBounds(src, ctm, dst);
113 }
114
115 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
116     if (0 == fInputCount) {
117         *dst = src;
118         return;
119     }
120     if (this->getInput(0)) {
121         this->getInput(0)->computeFastBounds(src, dst);
122     } else {
123         *dst = src;
124     }
125     for (int i = 1; i < fInputCount; i++) {
126         SkImageFilter* input = this->getInput(i);
127         if (input) {
128             SkRect bounds;
129             input->computeFastBounds(src, &bounds);
130             dst->join(bounds);
131         } else {
132             dst->join(src);
133         }
134     }
135 }
136
137 bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
138                                   SkBitmap*, SkIPoint*) const {
139     return false;
140 }
141
142 bool SkImageFilter::canFilterImageGPU() const {
143     return this->asNewEffect(NULL, NULL, SkMatrix::I(), SkIRect());
144 }
145
146 bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
147                                    SkBitmap* result, SkIPoint* offset) const {
148 #if SK_SUPPORT_GPU
149     SkBitmap input;
150     SkASSERT(fInputCount == 1);
151     SkIPoint srcOffset = SkIPoint::Make(0, 0);
152     if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, ctm, &input, &srcOffset)) {
153         return false;
154     }
155     GrTexture* srcTexture = input.getTexture();
156     SkIRect bounds;
157     src.getBounds(&bounds);
158     bounds.offset(srcOffset);
159     if (!this->applyCropRect(&bounds, ctm)) {
160         return false;
161     }
162     SkRect srcRect = SkRect::Make(bounds);
163     SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
164     GrContext* context = srcTexture->getContext();
165
166     GrTextureDesc desc;
167     desc.fFlags = kRenderTarget_GrTextureFlagBit,
168     desc.fWidth = bounds.width();
169     desc.fHeight = bounds.height();
170     desc.fConfig = kRGBA_8888_GrPixelConfig;
171
172     GrAutoScratchTexture dst(context, desc);
173     GrContext::AutoMatrix am;
174     am.setIdentity(context);
175     GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget());
176     GrContext::AutoClip acs(context, dstRect);
177     GrEffectRef* effect;
178     offset->fX = bounds.left();
179     offset->fY = bounds.top();
180     bounds.offset(-srcOffset);
181     SkMatrix matrix(ctm);
182     matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
183     this->asNewEffect(&effect, srcTexture, matrix, bounds);
184     SkASSERT(effect);
185     SkAutoUnref effectRef(effect);
186     GrPaint paint;
187     paint.addColorEffect(effect);
188     context->drawRectToRect(paint, dstRect, srcRect);
189
190     SkAutoTUnref<GrTexture> resultTex(dst.detach());
191     SkImageFilterUtils::WrapTexture(resultTex, bounds.width(), bounds.height(), result);
192     return true;
193 #else
194     return false;
195 #endif
196 }
197
198 bool SkImageFilter::applyCropRect(SkIRect* rect, const SkMatrix& matrix) const {
199     SkRect cropRect;
200     matrix.mapRect(&cropRect, fCropRect.rect());
201     SkIRect cropRectI;
202     cropRect.roundOut(&cropRectI);
203     uint32_t flags = fCropRect.flags();
204     // If the original crop rect edges were unset, max out the new crop edges
205     if (!(flags & CropRect::kHasLeft_CropEdge)) cropRectI.fLeft = SK_MinS32;
206     if (!(flags & CropRect::kHasTop_CropEdge)) cropRectI.fTop = SK_MinS32;
207     if (!(flags & CropRect::kHasRight_CropEdge)) cropRectI.fRight = SK_MaxS32;
208     if (!(flags & CropRect::kHasBottom_CropEdge)) cropRectI.fBottom = SK_MaxS32;
209     return rect->intersect(cropRectI);
210 }
211
212 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
213                                    SkIRect* dst) const {
214     if (fInputCount < 1) {
215         return false;
216     }
217
218     SkIRect bounds;
219     for (int i = 0; i < fInputCount; ++i) {
220         SkImageFilter* filter = this->getInput(i);
221         SkIRect rect = src;
222         if (filter && !filter->filterBounds(src, ctm, &rect)) {
223             return false;
224         }
225         if (0 == i) {
226             bounds = rect;
227         } else {
228             bounds.join(rect);
229         }
230     }
231
232     // don't modify dst until now, so we don't accidentally change it in the
233     // loop, but then return false on the next filter.
234     *dst = bounds;
235     return true;
236 }
237
238 bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkMatrix&, const SkIRect&) const {
239     return false;
240 }
241
242 bool SkImageFilter::asColorFilter(SkColorFilter**) const {
243     return false;
244 }