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 "SkFlattenableBuffers.h" 13#include "SkXfermode.h" 14#if SK_SUPPORT_GPU 15#include "GrContext.h" 16#include "effects/GrSimpleTextureEffect.h" 17#include "SkGr.h" 18#include "SkImageFilterUtils.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(SkFlattenableReadBuffer& buffer) 36 : INHERITED(2, buffer) { 37 fMode = buffer.readXfermode(); 38} 39 40void SkXfermodeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { 41 this->INHERITED::flatten(buffer); 42 buffer.writeFlattenable(fMode); 43} 44 45bool SkXfermodeImageFilter::onFilterImage(Proxy* proxy, 46 const SkBitmap& src, 47 const SkMatrix& ctm, 48 SkBitmap* dst, 49 SkIPoint* offset) { 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, ctm, &background, &backgroundOffset)) { 56 return false; 57 } 58 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); 59 if (foregroundInput && 60 !foregroundInput->filterImage(proxy, src, ctm, &foreground, &foregroundOffset)) { 61 return false; 62 } 63 64 SkIRect bounds, foregroundBounds; 65 background.getBounds(&bounds); 66 bounds.offset(backgroundOffset); 67 foreground.getBounds(&foregroundBounds); 68 foregroundBounds.offset(foregroundOffset); 69 bounds.join(foregroundBounds); 70 if (!applyCropRect(&bounds, ctm)) { 71 return false; 72 } 73 74 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); 75 if (NULL == device.get()) { 76 return false; 77 } 78 SkCanvas canvas(device); 79 canvas.translate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); 80 SkPaint paint; 81 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 82 canvas.drawBitmap(background, SkIntToScalar(backgroundOffset.fX), 83 SkIntToScalar(backgroundOffset.fY), &paint); 84 paint.setXfermode(fMode); 85 canvas.drawBitmap(foreground, SkIntToScalar(foregroundOffset.fX), 86 SkIntToScalar(foregroundOffset.fY), &paint); 87 canvas.clipRect(SkRect::Make(foregroundBounds), SkRegion::kDifference_Op); 88 paint.setColor(SK_ColorTRANSPARENT); 89 canvas.drawPaint(paint); 90 *dst = device->accessBitmap(false); 91 offset->fX += bounds.left(); 92 offset->fY += bounds.top(); 93 return true; 94} 95 96#if SK_SUPPORT_GPU 97 98bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, 99 const SkBitmap& src, 100 const SkMatrix& ctm, 101 SkBitmap* result, 102 SkIPoint* offset) { 103 SkBitmap background; 104 SkIPoint backgroundOffset = SkIPoint::Make(0, 0); 105 if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &background, 106 &backgroundOffset)) { 107 return false; 108 } 109 GrTexture* backgroundTex = background.getTexture(); 110 SkBitmap foreground; 111 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); 112 if (!SkImageFilterUtils::GetInputResultGPU(getInput(1), proxy, src, ctm, &foreground, 113 &foregroundOffset)) { 114 return false; 115 } 116 GrTexture* foregroundTex = foreground.getTexture(); 117 GrContext* context = foregroundTex->getContext(); 118 119 GrEffectRef* xferEffect = NULL; 120 121 GrTextureDesc desc; 122 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; 123 desc.fWidth = src.width(); 124 desc.fHeight = src.height(); 125 desc.fConfig = kSkia8888_GrPixelConfig; 126 127 GrAutoScratchTexture ast(context, desc); 128 SkAutoTUnref<GrTexture> dst(ast.detach()); 129 130 GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); 131 132 SkXfermode::Coeff sm, dm; 133 if (!SkXfermode::AsNewEffectOrCoeff(fMode, &xferEffect, &sm, &dm, backgroundTex)) { 134 return false; 135 } 136 137 SkMatrix foregroundMatrix = GrEffect::MakeDivByTextureWHMatrix(foregroundTex); 138 foregroundMatrix.preTranslate(SkIntToScalar(backgroundOffset.fX-foregroundOffset.fX), 139 SkIntToScalar(backgroundOffset.fY-foregroundOffset.fY)); 140 141 142 SkRect srcRect; 143 src.getBounds(&srcRect); 144 if (NULL != xferEffect) { 145 GrPaint paint; 146 paint.addColorTextureEffect(foregroundTex, foregroundMatrix); 147 paint.addColorEffect(xferEffect)->unref(); 148 context->drawRect(paint, srcRect); 149 } else { 150 GrPaint backgroundPaint; 151 SkMatrix backgroundMatrix = GrEffect::MakeDivByTextureWHMatrix(backgroundTex); 152 backgroundPaint.addColorTextureEffect(backgroundTex, backgroundMatrix); 153 context->drawRect(backgroundPaint, srcRect); 154 155 GrPaint foregroundPaint; 156 foregroundPaint.setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm)); 157 foregroundPaint.addColorTextureEffect(foregroundTex, foregroundMatrix); 158 context->drawRect(foregroundPaint, srcRect); 159 } 160 offset->fX += backgroundOffset.fX; 161 offset->fY += backgroundOffset.fY; 162 return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result); 163} 164 165#endif 166