• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SkXfermodeImageFilter(SkXfermode * mode,SkImageFilter * background,SkImageFilter * foreground,const CropRect * cropRect)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 
~SkXfermodeImageFilter()31 SkXfermodeImageFilter::~SkXfermodeImageFilter() {
32     SkSafeUnref(fMode);
33 }
34 
SkXfermodeImageFilter(SkReadBuffer & buffer)35 SkXfermodeImageFilter::SkXfermodeImageFilter(SkReadBuffer& buffer)
36   : INHERITED(2, buffer) {
37     fMode = buffer.readXfermode();
38 }
39 
flatten(SkWriteBuffer & buffer) const40 void SkXfermodeImageFilter::flatten(SkWriteBuffer& buffer) const {
41     this->INHERITED::flatten(buffer);
42     buffer.writeFlattenable(fMode);
43 }
44 
onFilterImage(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * dst,SkIPoint * offset) const45 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 
canFilterImageGPU() const102 bool SkXfermodeImageFilter::canFilterImageGPU() const {
103     return fMode && fMode->asNewEffect(NULL, NULL) && !cropRectIsSet();
104 }
105 
filterImageGPU(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const106 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