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/GrSimpleTextureEffect.h" 18#include "SkGr.h" 19#endif 20 21/////////////////////////////////////////////////////////////////////////////// 22 23SkXfermodeImageFilter::SkXfermodeImageFilter(SkXfermode* mode, 24 SkImageFilter* background, 25 SkImageFilter* foreground, 26 const CropRect* cropRect) 27 : INHERITED(background, foreground, cropRect), fMode(mode) { 28 SkSafeRef(fMode); 29} 30 31SkXfermodeImageFilter::~SkXfermodeImageFilter() { 32 SkSafeUnref(fMode); 33} 34 35SkXfermodeImageFilter::SkXfermodeImageFilter(SkReadBuffer& buffer) 36 : INHERITED(2, buffer) { 37 fMode = buffer.readXfermode(); 38} 39 40void SkXfermodeImageFilter::flatten(SkWriteBuffer& buffer) const { 41 this->INHERITED::flatten(buffer); 42 buffer.writeFlattenable(fMode); 43} 44 45bool 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#if SK_SUPPORT_GPU 101 102bool SkXfermodeImageFilter::canFilterImageGPU() const { 103 return fMode && fMode->asNewEffect(NULL, NULL) && !cropRectIsSet(); 104} 105 106bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, 107 const SkBitmap& src, 108 const Context& ctx, 109 SkBitmap* result, 110 SkIPoint* offset) const { 111 SkBitmap background = src; 112 SkIPoint backgroundOffset = SkIPoint::Make(0, 0); 113 if (getInput(0) && !getInput(0)->getInputResultGPU(proxy, src, ctx, &background, 114 &backgroundOffset)) { 115 return onFilterImage(proxy, src, ctx, result, offset); 116 } 117 GrTexture* backgroundTex = background.getTexture(); 118 SkBitmap foreground = src; 119 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); 120 if (getInput(1) && !getInput(1)->getInputResultGPU(proxy, src, ctx, &foreground, 121 &foregroundOffset)) { 122 return onFilterImage(proxy, src, ctx, result, offset); 123 } 124 GrTexture* foregroundTex = foreground.getTexture(); 125 GrContext* context = foregroundTex->getContext(); 126 127 GrEffectRef* xferEffect = NULL; 128 129 GrTextureDesc desc; 130 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; 131 desc.fWidth = src.width(); 132 desc.fHeight = src.height(); 133 desc.fConfig = kSkia8888_GrPixelConfig; 134 135 GrAutoScratchTexture ast(context, desc); 136 SkAutoTUnref<GrTexture> dst(ast.detach()); 137 138 GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); 139 140 if (!fMode || !fMode->asNewEffect(&xferEffect, backgroundTex)) { 141 // canFilterImageGPU() should've taken care of this 142 SkASSERT(false); 143 return false; 144 } 145 146 SkMatrix foregroundMatrix = GrEffect::MakeDivByTextureWHMatrix(foregroundTex); 147 foregroundMatrix.preTranslate(SkIntToScalar(backgroundOffset.fX-foregroundOffset.fX), 148 SkIntToScalar(backgroundOffset.fY-foregroundOffset.fY)); 149 150 151 SkRect srcRect; 152 src.getBounds(&srcRect); 153 154 GrPaint paint; 155 paint.addColorTextureEffect(foregroundTex, foregroundMatrix); 156 paint.addColorEffect(xferEffect)->unref(); 157 context->drawRect(paint, srcRect); 158 159 offset->fX = backgroundOffset.fX; 160 offset->fY = backgroundOffset.fY; 161 WrapTexture(dst, src.width(), src.height(), result); 162 return true; 163} 164 165#endif 166