Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / effects / SkXfermodeImageFilter.cpp
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 #include "SkImageFilterUtils.h"
20 #endif
21
22 ///////////////////////////////////////////////////////////////////////////////
23
24 SkXfermodeImageFilter::SkXfermodeImageFilter(SkXfermode* mode,
25                                              SkImageFilter* background,
26                                              SkImageFilter* foreground,
27                                              const CropRect* cropRect)
28   : INHERITED(background, foreground, cropRect), fMode(mode) {
29     SkSafeRef(fMode);
30 }
31
32 SkXfermodeImageFilter::~SkXfermodeImageFilter() {
33     SkSafeUnref(fMode);
34 }
35
36 SkXfermodeImageFilter::SkXfermodeImageFilter(SkReadBuffer& buffer)
37   : INHERITED(2, buffer) {
38     fMode = buffer.readXfermode();
39 }
40
41 void SkXfermodeImageFilter::flatten(SkWriteBuffer& buffer) const {
42     this->INHERITED::flatten(buffer);
43     buffer.writeFlattenable(fMode);
44 }
45
46 bool SkXfermodeImageFilter::onFilterImage(Proxy* proxy,
47                                             const SkBitmap& src,
48                                             const SkMatrix& ctm,
49                                             SkBitmap* dst,
50                                             SkIPoint* offset) const {
51     SkBitmap background = src, foreground = src;
52     SkImageFilter* backgroundInput = getInput(0);
53     SkImageFilter* foregroundInput = getInput(1);
54     SkIPoint backgroundOffset = SkIPoint::Make(0, 0);
55     if (backgroundInput &&
56         !backgroundInput->filterImage(proxy, src, ctm, &background, &backgroundOffset)) {
57         return false;
58     }
59     SkIPoint foregroundOffset = SkIPoint::Make(0, 0);
60     if (foregroundInput &&
61         !foregroundInput->filterImage(proxy, src, ctm, &foreground, &foregroundOffset)) {
62         return false;
63     }
64
65     SkIRect bounds, foregroundBounds;
66     background.getBounds(&bounds);
67     bounds.offset(backgroundOffset);
68     foreground.getBounds(&foregroundBounds);
69     foregroundBounds.offset(foregroundOffset);
70     bounds.join(foregroundBounds);
71     if (!applyCropRect(&bounds, ctm)) {
72         return false;
73     }
74
75     SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
76     if (NULL == device.get()) {
77         return false;
78     }
79     SkCanvas canvas(device);
80     canvas.translate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
81     SkPaint paint;
82     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
83     canvas.drawBitmap(background, SkIntToScalar(backgroundOffset.fX),
84                       SkIntToScalar(backgroundOffset.fY), &paint);
85     paint.setXfermode(fMode);
86     canvas.drawBitmap(foreground, SkIntToScalar(foregroundOffset.fX),
87                       SkIntToScalar(foregroundOffset.fY), &paint);
88     canvas.clipRect(SkRect::Make(foregroundBounds), SkRegion::kDifference_Op);
89     paint.setColor(SK_ColorTRANSPARENT);
90     canvas.drawPaint(paint);
91     *dst = device->accessBitmap(false);
92     offset->fX = bounds.left();
93     offset->fY = bounds.top();
94     return true;
95 }
96
97 #if SK_SUPPORT_GPU
98
99 bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy,
100                                            const SkBitmap& src,
101                                            const SkMatrix& ctm,
102                                            SkBitmap* result,
103                                            SkIPoint* offset) const {
104     SkBitmap background;
105     SkIPoint backgroundOffset = SkIPoint::Make(0, 0);
106     if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &background,
107                                                &backgroundOffset)) {
108         return false;
109     }
110     GrTexture* backgroundTex = background.getTexture();
111     SkBitmap foreground;
112     SkIPoint foregroundOffset = SkIPoint::Make(0, 0);
113     if (!SkImageFilterUtils::GetInputResultGPU(getInput(1), proxy, src, ctm, &foreground,
114                                                &foregroundOffset)) {
115         return false;
116     }
117     GrTexture* foregroundTex = foreground.getTexture();
118     GrContext* context = foregroundTex->getContext();
119
120     GrEffectRef* xferEffect = NULL;
121
122     GrTextureDesc desc;
123     desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
124     desc.fWidth = src.width();
125     desc.fHeight = src.height();
126     desc.fConfig = kSkia8888_GrPixelConfig;
127
128     GrAutoScratchTexture ast(context, desc);
129     SkAutoTUnref<GrTexture> dst(ast.detach());
130
131     GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
132
133     SkXfermode::Coeff sm, dm;
134     if (!SkXfermode::AsNewEffectOrCoeff(fMode, &xferEffect, &sm, &dm, backgroundTex)) {
135         return false;
136     }
137
138     SkMatrix foregroundMatrix = GrEffect::MakeDivByTextureWHMatrix(foregroundTex);
139     foregroundMatrix.preTranslate(SkIntToScalar(backgroundOffset.fX-foregroundOffset.fX),
140                                   SkIntToScalar(backgroundOffset.fY-foregroundOffset.fY));
141
142
143     SkRect srcRect;
144     src.getBounds(&srcRect);
145     if (NULL != xferEffect) {
146         GrPaint paint;
147         paint.addColorTextureEffect(foregroundTex, foregroundMatrix);
148         paint.addColorEffect(xferEffect)->unref();
149         context->drawRect(paint, srcRect);
150     } else {
151         GrPaint backgroundPaint;
152         SkMatrix backgroundMatrix = GrEffect::MakeDivByTextureWHMatrix(backgroundTex);
153         backgroundPaint.addColorTextureEffect(backgroundTex, backgroundMatrix);
154         context->drawRect(backgroundPaint, srcRect);
155
156         GrPaint foregroundPaint;
157         foregroundPaint.setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm));
158         foregroundPaint.addColorTextureEffect(foregroundTex, foregroundMatrix);
159         context->drawRect(foregroundPaint, srcRect);
160     }
161     offset->fX = backgroundOffset.fX;
162     offset->fY = backgroundOffset.fY;
163     return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result);
164 }
165
166 #endif