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 "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 
     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(SkReadBuffer& buffer)
     36   : INHERITED(2, buffer) {
     37     fMode = buffer.readXfermode();
     38 }
     39 
     40 void SkXfermodeImageFilter::flatten(SkWriteBuffer& 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 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 
    102 bool SkXfermodeImageFilter::canFilterImageGPU() const {
    103     return fMode && fMode->asNewEffect(NULL, NULL) && !cropRectIsSet();
    104 }
    105 
    106 bool 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