blob: 2a221fb869db95371fbea1d45162e490d474cf8f [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"
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +000013#include "SkValidationUtils.h"
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +000014#if SK_SUPPORT_GPU
15#include "GrContext.h"
16#include "GrTexture.h"
17#include "SkImageFilterUtils.h"
18#endif
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +000019
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000020SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect)
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000021 : fInputCount(inputCount),
22 fInputs(new SkImageFilter*[inputCount]),
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000023 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +000024 for (int i = 0; i < inputCount; ++i) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000025 fInputs[i] = inputs[i];
26 SkSafeRef(fInputs[i]);
27 }
28}
29
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000030SkImageFilter::SkImageFilter(SkImageFilter* input, const CropRect* cropRect)
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000031 : fInputCount(1),
32 fInputs(new SkImageFilter*[1]),
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000033 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
senorblanco@chromium.orgc2e8cef2012-10-22 15:07:14 +000034 fInputs[0] = input;
35 SkSafeRef(fInputs[0]);
36}
37
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000038SkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const CropRect* cropRect)
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000039 : fInputCount(2), fInputs(new SkImageFilter*[2]),
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +000040 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) {
senorblanco@chromium.orgc2e8cef2012-10-22 15:07:14 +000041 fInputs[0] = input1;
42 fInputs[1] = input2;
43 SkSafeRef(fInputs[0]);
44 SkSafeRef(fInputs[1]);
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000045}
46
47SkImageFilter::~SkImageFilter() {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +000048 for (int i = 0; i < fInputCount; i++) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000049 SkSafeUnref(fInputs[i]);
50 }
51 delete[] fInputs;
52}
53
commit-bot@chromium.orgc84728d2013-12-04 20:07:47 +000054SkImageFilter::SkImageFilter(int inputCount, SkFlattenableReadBuffer& buffer) {
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +000055 fInputCount = buffer.readInt();
commit-bot@chromium.orgc84728d2013-12-04 20:07:47 +000056 if (buffer.validate((fInputCount >= 0) && ((inputCount < 0) || (fInputCount == inputCount)))) {
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +000057 fInputs = new SkImageFilter*[fInputCount];
58 for (int i = 0; i < fInputCount; i++) {
59 if (buffer.readBool()) {
60 fInputs[i] = buffer.readImageFilter();
61 } else {
62 fInputs[i] = NULL;
63 }
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000064 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +000065 SkRect rect;
66 buffer.readRect(&rect);
67 if (buffer.validate(SkIsValidRect(rect))) {
68 uint32_t flags = buffer.readUInt();
69 fCropRect = CropRect(rect, flags);
70 }
71 } else {
72 fInputCount = 0;
73 fInputs = NULL;
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000074 }
75}
76
77void SkImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +000078 buffer.writeInt(fInputCount);
79 for (int i = 0; i < fInputCount; i++) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000080 SkImageFilter* input = getInput(i);
81 buffer.writeBool(input != NULL);
82 if (input != NULL) {
83 buffer.writeFlattenable(input);
84 }
85 }
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +000086 buffer.writeRect(fCropRect.rect());
87 buffer.writeUInt(fCropRect.flags());
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000088}
89
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +000090bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
91 const SkMatrix& ctm,
92 SkBitmap* result, SkIPoint* loc) {
93 SkASSERT(result);
94 SkASSERT(loc);
95 /*
96 * Give the proxy first shot at the filter. If it returns false, ask
97 * the filter to do it.
98 */
99 return (proxy && proxy->filterImage(this, src, ctm, result, loc)) ||
100 this->onFilterImage(proxy, src, ctm, result, loc);
101}
102
103bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
104 SkIRect* dst) {
105 SkASSERT(&src);
106 SkASSERT(dst);
107 return this->onFilterBounds(src, ctm, dst);
108}
109
110bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
111 SkBitmap*, SkIPoint*) {
112 return false;
113}
114
115bool SkImageFilter::canFilterImageGPU() const {
senorblanco@chromium.org7938bae2013-10-18 20:08:14 +0000116 return this->asNewEffect(NULL, NULL, SkMatrix::I(), SkIRect());
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000117}
118
commit-bot@chromium.org1aa54bf2013-08-05 16:53:50 +0000119bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
120 SkBitmap* result, SkIPoint* offset) {
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000121#if SK_SUPPORT_GPU
122 SkBitmap input;
123 SkASSERT(fInputCount == 1);
commit-bot@chromium.org1aa54bf2013-08-05 16:53:50 +0000124 if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, ctm, &input, offset)) {
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000125 return false;
126 }
commit-bot@chromium.orgb8d00db2013-06-26 19:18:23 +0000127 GrTexture* srcTexture = input.getTexture();
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000128 SkIRect bounds;
129 src.getBounds(&bounds);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000130 if (!this->applyCropRect(&bounds, ctm)) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000131 return false;
132 }
133 SkRect srcRect = SkRect::Make(bounds);
134 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000135 GrContext* context = srcTexture->getContext();
136
137 GrTextureDesc desc;
138 desc.fFlags = kRenderTarget_GrTextureFlagBit,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000139 desc.fWidth = bounds.width();
140 desc.fHeight = bounds.height();
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000141 desc.fConfig = kRGBA_8888_GrPixelConfig;
142
143 GrAutoScratchTexture dst(context, desc);
144 GrContext::AutoMatrix am;
145 am.setIdentity(context);
146 GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget());
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000147 GrContext::AutoClip acs(context, dstRect);
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000148 GrEffectRef* effect;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000149 SkMatrix matrix(ctm);
150 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
senorblanco@chromium.org7938bae2013-10-18 20:08:14 +0000151 this->asNewEffect(&effect, srcTexture, matrix, bounds);
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000152 SkASSERT(effect);
153 SkAutoUnref effectRef(effect);
154 GrPaint paint;
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000155 paint.addColorEffect(effect);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000156 context->drawRectToRect(paint, dstRect, srcRect);
157
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000158 SkAutoTUnref<GrTexture> resultTex(dst.detach());
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000159 SkImageFilterUtils::WrapTexture(resultTex, bounds.width(), bounds.height(), result);
160 offset->fX += bounds.left();
161 offset->fY += bounds.top();
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000162 return true;
163#else
senorblanco@chromium.orgc2594f42013-01-30 19:08:47 +0000164 return false;
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000165#endif
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000166}
167
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000168bool SkImageFilter::applyCropRect(SkIRect* rect, const SkMatrix& matrix) const {
169 SkRect cropRect;
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000170 matrix.mapRect(&cropRect, fCropRect.rect());
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000171 SkIRect cropRectI;
172 cropRect.roundOut(&cropRectI);
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000173 uint32_t flags = fCropRect.flags();
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000174 // If the original crop rect edges were unset, max out the new crop edges
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000175 if (!(flags & CropRect::kHasLeft_CropEdge)) cropRectI.fLeft = SK_MinS32;
176 if (!(flags & CropRect::kHasTop_CropEdge)) cropRectI.fTop = SK_MinS32;
177 if (!(flags & CropRect::kHasRight_CropEdge)) cropRectI.fRight = SK_MaxS32;
178 if (!(flags & CropRect::kHasBottom_CropEdge)) cropRectI.fBottom = SK_MaxS32;
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000179 return rect->intersect(cropRectI);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000180}
181
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000182bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
183 SkIRect* dst) {
184 *dst = src;
185 return true;
186}
187
senorblanco@chromium.org7938bae2013-10-18 20:08:14 +0000188bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkMatrix&, const SkIRect&) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000189 return false;
190}
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000191
sugoi@google.coma1c511b2013-02-21 15:02:28 +0000192bool SkImageFilter::asColorFilter(SkColorFilter**) const {
193 return false;
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000194}