blob: 3b7de25c93ed1ca5b51b1154493789745878510e [file] [log] [blame]
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +00001/*
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"
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +00009
10#include "SkBitmap.h"
11#include "SkFlattenableBuffers.h"
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +000012#include "SkRect.h"
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +000013#if SK_SUPPORT_GPU
14#include "GrContext.h"
15#include "GrTexture.h"
16#include "SkImageFilterUtils.h"
17#endif
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +000018
19SK_DEFINE_INST_COUNT(SkImageFilter)
20
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000021SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect)
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000022 : fInputCount(inputCount),
23 fInputs(new SkImageFilter*[inputCount]),
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000024#ifdef SK_CROP_RECT_IS_INT
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000025 fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000026#else
27 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
28#endif
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +000029 for (int i = 0; i < inputCount; ++i) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000030 fInputs[i] = inputs[i];
31 SkSafeRef(fInputs[i]);
32 }
33}
34
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000035SkImageFilter::SkImageFilter(SkImageFilter* input, const CropRect* cropRect)
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000036 : fInputCount(1),
37 fInputs(new SkImageFilter*[1]),
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000038#ifdef SK_CROP_RECT_IS_INT
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000039 fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000040#else
41 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
42#endif
senorblanco@chromium.orgc2e8cef2012-10-22 15:07:14 +000043 fInputs[0] = input;
44 SkSafeRef(fInputs[0]);
45}
46
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000047SkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const CropRect* cropRect)
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000048 : fInputCount(2), fInputs(new SkImageFilter*[2]),
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000049#ifdef SK_CROP_RECT_IS_INT
50 fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
51#else
52 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
53#endif
senorblanco@chromium.orgc2e8cef2012-10-22 15:07:14 +000054 fInputs[0] = input1;
55 fInputs[1] = input2;
56 SkSafeRef(fInputs[0]);
57 SkSafeRef(fInputs[1]);
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000058}
59
60SkImageFilter::~SkImageFilter() {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +000061 for (int i = 0; i < fInputCount; i++) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000062 SkSafeUnref(fInputs[i]);
63 }
64 delete[] fInputs;
65}
66
skia.committer@gmail.comfc843592012-10-11 02:01:14 +000067SkImageFilter::SkImageFilter(SkFlattenableReadBuffer& buffer)
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +000068 : fInputCount(buffer.readInt()), fInputs(new SkImageFilter*[fInputCount]) {
69 for (int i = 0; i < fInputCount; i++) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000070 if (buffer.readBool()) {
71 fInputs[i] = static_cast<SkImageFilter*>(buffer.readFlattenable());
72 } else {
73 fInputs[i] = NULL;
74 }
75 }
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000076#ifdef SK_CROP_RECT_IS_INT
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000077 buffer.readIRect(&fCropRect);
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000078#else
79 buffer.readRect(&fCropRect.fRect);
80 fCropRect.fFlags = buffer.readUInt();
81#endif
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000082}
83
84void SkImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +000085 buffer.writeInt(fInputCount);
86 for (int i = 0; i < fInputCount; i++) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000087 SkImageFilter* input = getInput(i);
88 buffer.writeBool(input != NULL);
89 if (input != NULL) {
90 buffer.writeFlattenable(input);
91 }
92 }
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000093#ifdef SK_CROP_RECT_IS_INT
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000094 buffer.writeIRect(fCropRect);
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000095#else
96 buffer.writeRect(fCropRect.fRect);
97 buffer.writeUInt(fCropRect.fFlags);
98#endif
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000099}
100
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000101bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
102 const SkMatrix& ctm,
103 SkBitmap* result, SkIPoint* loc) {
104 SkASSERT(result);
105 SkASSERT(loc);
106 /*
107 * Give the proxy first shot at the filter. If it returns false, ask
108 * the filter to do it.
109 */
110 return (proxy && proxy->filterImage(this, src, ctm, result, loc)) ||
111 this->onFilterImage(proxy, src, ctm, result, loc);
112}
113
114bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
115 SkIRect* dst) {
116 SkASSERT(&src);
117 SkASSERT(dst);
118 return this->onFilterBounds(src, ctm, dst);
119}
120
121bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
122 SkBitmap*, SkIPoint*) {
123 return false;
124}
125
126bool SkImageFilter::canFilterImageGPU() const {
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000127 return this->asNewEffect(NULL, NULL, SkMatrix::I());
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000128}
129
commit-bot@chromium.org1aa54bf2013-08-05 16:53:50 +0000130bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
131 SkBitmap* result, SkIPoint* offset) {
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000132#if SK_SUPPORT_GPU
133 SkBitmap input;
134 SkASSERT(fInputCount == 1);
commit-bot@chromium.org1aa54bf2013-08-05 16:53:50 +0000135 if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, ctm, &input, offset)) {
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000136 return false;
137 }
commit-bot@chromium.orgb8d00db2013-06-26 19:18:23 +0000138 GrTexture* srcTexture = input.getTexture();
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000139 SkIRect bounds;
140 src.getBounds(&bounds);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000141 if (!this->applyCropRect(&bounds, ctm)) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000142 return false;
143 }
144 SkRect srcRect = SkRect::Make(bounds);
145 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000146 GrContext* context = srcTexture->getContext();
147
148 GrTextureDesc desc;
149 desc.fFlags = kRenderTarget_GrTextureFlagBit,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000150 desc.fWidth = bounds.width();
151 desc.fHeight = bounds.height();
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000152 desc.fConfig = kRGBA_8888_GrPixelConfig;
153
154 GrAutoScratchTexture dst(context, desc);
155 GrContext::AutoMatrix am;
156 am.setIdentity(context);
157 GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget());
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000158 GrContext::AutoClip acs(context, dstRect);
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000159 GrEffectRef* effect;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000160 SkMatrix matrix(ctm);
161 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
162 this->asNewEffect(&effect, srcTexture, matrix);
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000163 SkASSERT(effect);
164 SkAutoUnref effectRef(effect);
165 GrPaint paint;
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000166 paint.addColorEffect(effect);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000167 context->drawRectToRect(paint, dstRect, srcRect);
168
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000169 SkAutoTUnref<GrTexture> resultTex(dst.detach());
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000170 SkImageFilterUtils::WrapTexture(resultTex, bounds.width(), bounds.height(), result);
171 offset->fX += bounds.left();
172 offset->fY += bounds.top();
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000173 return true;
174#else
senorblanco@chromium.orgc2594f42013-01-30 19:08:47 +0000175 return false;
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000176#endif
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000177}
178
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000179bool SkImageFilter::applyCropRect(SkIRect* rect, const SkMatrix& matrix) const {
180 SkRect cropRect;
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000181#ifdef SK_CROP_RECT_IS_INT
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000182 matrix.mapRect(&cropRect, SkRect::Make(fCropRect));
183 SkIRect cropRectI;
184 cropRect.roundOut(&cropRectI);
185 // If the original crop rect edges were unset, max out the new crop edges
186 if (fCropRect.fLeft == SK_MinS32) cropRectI.fLeft = SK_MinS32;
187 if (fCropRect.fTop == SK_MinS32) cropRectI.fTop = SK_MinS32;
188 if (fCropRect.fRight == SK_MaxS32) cropRectI.fRight = SK_MaxS32;
189 if (fCropRect.fBottom == SK_MaxS32) cropRectI.fBottom = SK_MaxS32;
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000190#else
191 matrix.mapRect(&cropRect, fCropRect.fRect);
192 SkIRect cropRectI;
193 cropRect.roundOut(&cropRectI);
194 // If the original crop rect edges were unset, max out the new crop edges
195 if (!(fCropRect.fFlags & CropRect::kHasLeft_CropEdge)) cropRectI.fLeft = SK_MinS32;
196 if (!(fCropRect.fFlags & CropRect::kHasTop_CropEdge)) cropRectI.fTop = SK_MinS32;
197 if (!(fCropRect.fFlags & CropRect::kHasRight_CropEdge)) cropRectI.fRight = SK_MaxS32;
198 if (!(fCropRect.fFlags & CropRect::kHasBottom_CropEdge)) cropRectI.fBottom = SK_MaxS32;
199#endif
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000200 return rect->intersect(cropRectI);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000201}
202
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000203bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
204 SkIRect* dst) {
205 *dst = src;
206 return true;
207}
208
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000209bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkMatrix&) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000210 return false;
211}
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000212
sugoi@google.coma1c511b2013-02-21 15:02:28 +0000213bool SkImageFilter::asColorFilter(SkColorFilter**) const {
214 return false;
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000215}