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 "SkColorPriv.h" 11 #include "SkFlattenableBuffers.h" 12 #include "SkXfermode.h" 13 #if SK_SUPPORT_GPU 14 #include "GrContext.h" 15 #include "effects/GrSimpleTextureEffect.h" 16 #include "SkGr.h" 17 #include "SkImageFilterUtils.h" 18 #endif 19 20 /////////////////////////////////////////////////////////////////////////////// 21 22 SkXfermodeImageFilter::SkXfermodeImageFilter(SkXfermode* mode, 23 SkImageFilter* background, 24 SkImageFilter* foreground) 25 : INHERITED(background, foreground), fMode(mode) { 26 SkSafeRef(fMode); 27 } 28 29 SkXfermodeImageFilter::~SkXfermodeImageFilter() { 30 SkSafeUnref(fMode); 31 } 32 33 SkXfermodeImageFilter::SkXfermodeImageFilter(SkFlattenableReadBuffer& buffer) 34 : INHERITED(buffer) { 35 fMode = buffer.readFlattenableT<SkXfermode>(); 36 } 37 38 void SkXfermodeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { 39 this->INHERITED::flatten(buffer); 40 buffer.writeFlattenable(fMode); 41 } 42 43 bool SkXfermodeImageFilter::onFilterImage(Proxy* proxy, 44 const SkBitmap& src, 45 const SkMatrix& ctm, 46 SkBitmap* dst, 47 SkIPoint* offset) { 48 SkBitmap background = src, foreground = src; 49 SkImageFilter* backgroundInput = getInput(0); 50 SkImageFilter* foregroundInput = getInput(1); 51 SkIPoint backgroundOffset = SkIPoint::Make(0, 0); 52 if (backgroundInput && 53 !backgroundInput->filterImage(proxy, src, ctm, &background, &backgroundOffset)) { 54 return false; 55 } 56 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); 57 if (foregroundInput && 58 !foregroundInput->filterImage(proxy, src, ctm, &foreground, &foregroundOffset)) { 59 return false; 60 } 61 dst->setConfig(background.config(), background.width(), background.height()); 62 dst->allocPixels(); 63 SkCanvas canvas(*dst); 64 SkPaint paint; 65 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 66 canvas.drawBitmap(background, 0, 0, &paint); 67 paint.setXfermode(fMode); 68 canvas.drawBitmap(foreground, 69 SkIntToScalar(foregroundOffset.fX - backgroundOffset.fX), 70 SkIntToScalar(foregroundOffset.fY - backgroundOffset.fY), 71 &paint); 72 offset->fX += backgroundOffset.fX; 73 offset->fY += backgroundOffset.fY; 74 return true; 75 } 76 77 #if SK_SUPPORT_GPU 78 79 bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, 80 const SkBitmap& src, 81 const SkMatrix& ctm, 82 SkBitmap* result, 83 SkIPoint* offset) { 84 SkBitmap background; 85 SkIPoint backgroundOffset = SkIPoint::Make(0, 0); 86 if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &background, 87 &backgroundOffset)) { 88 return false; 89 } 90 GrTexture* backgroundTex = background.getTexture(); 91 SkBitmap foreground; 92 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); 93 if (!SkImageFilterUtils::GetInputResultGPU(getInput(1), proxy, src, ctm, &foreground, 94 &foregroundOffset)) { 95 return false; 96 } 97 GrTexture* foregroundTex = foreground.getTexture(); 98 GrContext* context = foregroundTex->getContext(); 99 100 GrEffectRef* xferEffect = NULL; 101 102 GrTextureDesc desc; 103 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; 104 desc.fWidth = src.width(); 105 desc.fHeight = src.height(); 106 desc.fConfig = kSkia8888_GrPixelConfig; 107 108 GrAutoScratchTexture ast(context, desc); 109 SkAutoTUnref<GrTexture> dst(ast.detach()); 110 111 GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); 112 113 SkXfermode::Coeff sm, dm; 114 if (!SkXfermode::AsNewEffectOrCoeff(fMode, context, &xferEffect, &sm, &dm, backgroundTex)) { 115 return false; 116 } 117 118 SkMatrix foregroundMatrix = GrEffect::MakeDivByTextureWHMatrix(foregroundTex); 119 foregroundMatrix.preTranslate(SkIntToScalar(backgroundOffset.fX-foregroundOffset.fX), 120 SkIntToScalar(backgroundOffset.fY-foregroundOffset.fY)); 121 122 123 SkRect srcRect; 124 src.getBounds(&srcRect); 125 if (NULL != xferEffect) { 126 GrPaint paint; 127 paint.addColorTextureEffect(foregroundTex, foregroundMatrix); 128 paint.addColorEffect(xferEffect)->unref(); 129 context->drawRect(paint, srcRect); 130 } else { 131 GrPaint backgroundPaint; 132 SkMatrix backgroundMatrix = GrEffect::MakeDivByTextureWHMatrix(backgroundTex); 133 backgroundPaint.addColorTextureEffect(backgroundTex, backgroundMatrix); 134 context->drawRect(backgroundPaint, srcRect); 135 136 GrPaint foregroundPaint; 137 foregroundPaint.setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm)); 138 foregroundPaint.addColorTextureEffect(foregroundTex, foregroundMatrix); 139 context->drawRect(foregroundPaint, srcRect); 140 } 141 offset->fX += backgroundOffset.fX; 142 offset->fY += backgroundOffset.fY; 143 return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result); 144 } 145 146 #endif 147