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 19 SK_DEFINE_INST_COUNT(SkImageFilter) 20 21 SkImageFilter::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 31 SkImageFilter::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 39 SkImageFilter::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 48 SkImageFilter::~SkImageFilter() { 49 for (int i = 0; i < fInputCount; i++) { 50 SkSafeUnref(fInputs[i]); 51 } 52 delete[] fInputs; 53 } 54 55 SkImageFilter::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 67 void 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 79 bool 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 92 bool 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 99 bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&, 100 SkBitmap*, SkIPoint*) { 101 return false; 102 } 103 104 bool SkImageFilter::canFilterImageGPU() const { 105 return this->asNewEffect(NULL, NULL, SkIPoint::Make(0, 0)); 106 } 107 108 bool 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 155 bool SkImageFilter::applyCropRect(SkIRect* rect) const { 156 return rect->intersect(fCropRect); 157 } 158 159 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 160 SkIRect* dst) { 161 *dst = src; 162 return true; 163 } 164 165 bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkIPoint& offset) const { 166 return false; 167 } 168 169 bool SkImageFilter::asColorFilter(SkColorFilter**) const { 170 return false; 171 } 172