2 * Copyright 2012 The Android Open Source Project
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkImageFilter.h"
11 #include "SkReadBuffer.h"
12 #include "SkWriteBuffer.h"
14 #include "SkValidationUtils.h"
16 #include "GrContext.h"
17 #include "GrTexture.h"
18 #include "SkImageFilterUtils.h"
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]);
31 SkImageFilter::SkImageFilter(SkImageFilter* input, const CropRect* cropRect)
33 fInputs(new SkImageFilter*[1]),
34 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
36 SkSafeRef(fInputs[0]);
39 SkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const CropRect* cropRect)
40 : fInputCount(2), fInputs(new SkImageFilter*[2]),
41 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
44 SkSafeRef(fInputs[0]);
45 SkSafeRef(fInputs[1]);
48 SkImageFilter::~SkImageFilter() {
49 for (int i = 0; i < fInputCount; i++) {
50 SkSafeUnref(fInputs[i]);
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();
65 if (!buffer.isValid()) {
66 fInputCount = i; // Do not use fInputs past that point in the destructor
71 buffer.readRect(&rect);
72 if (buffer.isValid() && buffer.validate(SkIsValidRect(rect))) {
73 uint32_t flags = buffer.readUInt();
74 fCropRect = CropRect(rect, flags);
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);
88 buffer.writeFlattenable(input);
91 buffer.writeRect(fCropRect.rect());
92 buffer.writeUInt(fCropRect.flags());
95 bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
97 SkBitmap* result, SkIPoint* offset) const {
101 * Give the proxy first shot at the filter. If it returns false, ask
102 * the filter to do it.
104 return (proxy && proxy->filterImage(this, src, ctm, result, offset)) ||
105 this->onFilterImage(proxy, src, ctm, result, offset);
108 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
109 SkIRect* dst) const {
112 return this->onFilterBounds(src, ctm, dst);
115 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
116 if (0 == fInputCount) {
120 if (this->getInput(0)) {
121 this->getInput(0)->computeFastBounds(src, dst);
125 for (int i = 1; i < fInputCount; i++) {
126 SkImageFilter* input = this->getInput(i);
129 input->computeFastBounds(src, &bounds);
137 bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
138 SkBitmap*, SkIPoint*) const {
142 bool SkImageFilter::canFilterImageGPU() const {
143 return this->asNewEffect(NULL, NULL, SkMatrix::I(), SkIRect());
146 bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
147 SkBitmap* result, SkIPoint* offset) const {
150 SkASSERT(fInputCount == 1);
151 SkIPoint srcOffset = SkIPoint::Make(0, 0);
152 if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, ctm, &input, &srcOffset)) {
155 GrTexture* srcTexture = input.getTexture();
157 src.getBounds(&bounds);
158 bounds.offset(srcOffset);
159 if (!this->applyCropRect(&bounds, ctm)) {
162 SkRect srcRect = SkRect::Make(bounds);
163 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
164 GrContext* context = srcTexture->getContext();
167 desc.fFlags = kRenderTarget_GrTextureFlagBit,
168 desc.fWidth = bounds.width();
169 desc.fHeight = bounds.height();
170 desc.fConfig = kRGBA_8888_GrPixelConfig;
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);
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);
185 SkAutoUnref effectRef(effect);
187 paint.addColorEffect(effect);
188 context->drawRectToRect(paint, dstRect, srcRect);
190 SkAutoTUnref<GrTexture> resultTex(dst.detach());
191 SkImageFilterUtils::WrapTexture(resultTex, bounds.width(), bounds.height(), result);
198 bool SkImageFilter::applyCropRect(SkIRect* rect, const SkMatrix& matrix) const {
200 matrix.mapRect(&cropRect, fCropRect.rect());
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);
212 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
213 SkIRect* dst) const {
214 if (fInputCount < 1) {
219 for (int i = 0; i < fInputCount; ++i) {
220 SkImageFilter* filter = this->getInput(i);
222 if (filter && !filter->filterBounds(src, ctm, &rect)) {
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.
238 bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkMatrix&, const SkIRect&) const {
242 bool SkImageFilter::asColorFilter(SkColorFilter**) const {