1 /* 2 * Copyright 2013 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 "SkXfermodeImageFilter.h" 9 #include "SkCanvas.h" 10 #include "SkDevice.h" 11 #include "SkColorPriv.h" 12 #include "SkReadBuffer.h" 13 #include "SkWriteBuffer.h" 14 #include "SkXfermode.h" 15 #if SK_SUPPORT_GPU 16 #include "GrContext.h" 17 #include "effects/GrTextureDomain.h" 18 #include "SkGr.h" 19 #endif 20 21 /////////////////////////////////////////////////////////////////////////////// 22 23 SkXfermodeImageFilter::SkXfermodeImageFilter(SkXfermode* mode, 24 SkImageFilter* inputs[2], 25 const CropRect* cropRect) 26 : INHERITED(2, inputs, cropRect), fMode(mode) { 27 SkSafeRef(fMode); 28 } 29 30 SkXfermodeImageFilter::~SkXfermodeImageFilter() { 31 SkSafeUnref(fMode); 32 } 33 34 SkFlattenable* SkXfermodeImageFilter::CreateProc(SkReadBuffer& buffer) { 35 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2); 36 SkAutoTUnref<SkXfermode> mode(buffer.readXfermode()); 37 return Create(mode, common.getInput(0), common.getInput(1), &common.cropRect()); 38 } 39 40 void SkXfermodeImageFilter::flatten(SkWriteBuffer& buffer) const { 41 this->INHERITED::flatten(buffer); 42 buffer.writeFlattenable(fMode); 43 } 44 45 bool SkXfermodeImageFilter::onFilterImage(Proxy* proxy, 46 const SkBitmap& src, 47 const Context& ctx, 48 SkBitmap* dst, 49 SkIPoint* offset) const { 50 SkBitmap background = src, foreground = src; 51 SkImageFilter* backgroundInput = getInput(0); 52 SkImageFilter* foregroundInput = getInput(1); 53 SkIPoint backgroundOffset = SkIPoint::Make(0, 0); 54 if (backgroundInput && 55 !backgroundInput->filterImage(proxy, src, ctx, &background, &backgroundOffset)) { 56 background.reset(); 57 } 58 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); 59 if (foregroundInput && 60 !foregroundInput->filterImage(proxy, src, ctx, &foreground, &foregroundOffset)) { 61 foreground.reset(); 62 } 63 64 SkIRect bounds, foregroundBounds; 65 if (!applyCropRect(ctx, foreground, foregroundOffset, &foregroundBounds)) { 66 foregroundBounds.setEmpty(); 67 foreground.reset(); 68 } 69 if (!applyCropRect(ctx, background, backgroundOffset, &bounds)) { 70 bounds.setEmpty(); 71 background.reset(); 72 } 73 bounds.join(foregroundBounds); 74 if (bounds.isEmpty()) { 75 return false; 76 } 77 78 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); 79 if (NULL == device.get()) { 80 return false; 81 } 82 SkCanvas canvas(device); 83 canvas.translate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); 84 SkPaint paint; 85 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 86 canvas.drawBitmap(background, SkIntToScalar(backgroundOffset.fX), 87 SkIntToScalar(backgroundOffset.fY), &paint); 88 paint.setXfermode(fMode); 89 canvas.drawBitmap(foreground, SkIntToScalar(foregroundOffset.fX), 90 SkIntToScalar(foregroundOffset.fY), &paint); 91 canvas.clipRect(SkRect::Make(foregroundBounds), SkRegion::kDifference_Op); 92 paint.setColor(SK_ColorTRANSPARENT); 93 canvas.drawPaint(paint); 94 *dst = device->accessBitmap(false); 95 offset->fX = bounds.left(); 96 offset->fY = bounds.top(); 97 return true; 98 } 99 100 #ifndef SK_IGNORE_TO_STRING 101 void SkXfermodeImageFilter::toString(SkString* str) const { 102 str->appendf("SkXfermodeImageFilter: ("); 103 str->appendf("xfermode: ("); 104 if (fMode) { 105 fMode->toString(str); 106 } 107 str->append("))"); 108 } 109 #endif 110 111 #if SK_SUPPORT_GPU 112 113 bool SkXfermodeImageFilter::canFilterImageGPU() const { 114 return fMode && fMode->asFragmentProcessor(NULL, NULL) && !cropRectIsSet(); 115 } 116 117 bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, 118 const SkBitmap& src, 119 const Context& ctx, 120 SkBitmap* result, 121 SkIPoint* offset) const { 122 SkBitmap background = src; 123 SkIPoint backgroundOffset = SkIPoint::Make(0, 0); 124 if (getInput(0) && !getInput(0)->getInputResultGPU(proxy, src, ctx, &background, 125 &backgroundOffset)) { 126 return onFilterImage(proxy, src, ctx, result, offset); 127 } 128 GrTexture* backgroundTex = background.getTexture(); 129 130 if (NULL == backgroundTex) { 131 SkASSERT(false); 132 return false; 133 } 134 135 SkBitmap foreground = src; 136 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); 137 if (getInput(1) && !getInput(1)->getInputResultGPU(proxy, src, ctx, &foreground, 138 &foregroundOffset)) { 139 return onFilterImage(proxy, src, ctx, result, offset); 140 } 141 GrTexture* foregroundTex = foreground.getTexture(); 142 GrContext* context = foregroundTex->getContext(); 143 144 GrFragmentProcessor* xferProcessor = NULL; 145 146 GrSurfaceDesc desc; 147 desc.fFlags = kRenderTarget_GrSurfaceFlag; 148 desc.fWidth = src.width(); 149 desc.fHeight = src.height(); 150 desc.fConfig = kSkia8888_GrPixelConfig; 151 SkAutoTUnref<GrTexture> dst(context->textureProvider()->refScratchTexture( 152 desc, GrTextureProvider::kApprox_ScratchTexMatch)); 153 if (!dst) { 154 return false; 155 } 156 157 if (!fMode || !fMode->asFragmentProcessor(&xferProcessor, backgroundTex)) { 158 // canFilterImageGPU() should've taken care of this 159 SkASSERT(false); 160 return false; 161 } 162 163 SkMatrix foregroundMatrix = GrCoordTransform::MakeDivByTextureWHMatrix(foregroundTex); 164 foregroundMatrix.preTranslate(SkIntToScalar(backgroundOffset.fX-foregroundOffset.fX), 165 SkIntToScalar(backgroundOffset.fY-foregroundOffset.fY)); 166 167 168 SkRect srcRect; 169 src.getBounds(&srcRect); 170 171 GrPaint paint; 172 SkAutoTUnref<GrFragmentProcessor> foregroundDomain(GrTextureDomainEffect::Create( 173 foregroundTex, foregroundMatrix, 174 GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), 175 GrTextureDomain::kDecal_Mode, 176 GrTextureParams::kNone_FilterMode) 177 ); 178 179 paint.addColorProcessor(foregroundDomain.get()); 180 paint.addColorProcessor(xferProcessor)->unref(); 181 context->drawRect(dst->asRenderTarget(), GrClip::WideOpen(), paint, SkMatrix::I(), srcRect); 182 183 offset->fX = backgroundOffset.fX; 184 offset->fY = backgroundOffset.fY; 185 WrapTexture(dst, src.width(), src.height(), result); 186 return true; 187 } 188 189 #endif 190 191