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 "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 
     23 SkXfermodeImageFilter::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 
     31 SkXfermodeImageFilter::~SkXfermodeImageFilter() {
     32     SkSafeUnref(fMode);
     33 }
     34 
     35 SkXfermodeImageFilter::SkXfermodeImageFilter(SkFlattenableReadBuffer& buffer)
     36   : INHERITED(2, buffer) {
     37     fMode = buffer.readXfermode();
     38 }
     39 
     40 void SkXfermodeImageFilter::flatten(SkFlattenableWriteBuffer& 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 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 
     98 bool 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