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