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