Home | History | Annotate | Download | only in effects
      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