• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 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 "SkArenaAlloc.h"
9 #include "SkComposeShader.h"
10 #include "SkColorFilter.h"
11 #include "SkColorPriv.h"
12 #include "SkColorShader.h"
13 #include "SkReadBuffer.h"
14 #include "SkWriteBuffer.h"
15 #include "SkString.h"
16 
MakeComposeShader(sk_sp<SkShader> dst,sk_sp<SkShader> src,SkBlendMode mode)17 sk_sp<SkShader> SkShader::MakeComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src,
18                                             SkBlendMode mode) {
19     if (!src || !dst) {
20         return nullptr;
21     }
22     if (SkBlendMode::kSrc == mode) {
23         return src;
24     }
25     if (SkBlendMode::kDst == mode) {
26         return dst;
27     }
28     return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode));
29 }
30 
31 ///////////////////////////////////////////////////////////////////////////////
32 
33 class SkAutoAlphaRestore {
34 public:
SkAutoAlphaRestore(SkPaint * paint,uint8_t newAlpha)35     SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
36         fAlpha = paint->getAlpha();
37         fPaint = paint;
38         paint->setAlpha(newAlpha);
39     }
40 
~SkAutoAlphaRestore()41     ~SkAutoAlphaRestore() {
42         fPaint->setAlpha(fAlpha);
43     }
44 private:
45     SkPaint*    fPaint;
46     uint8_t     fAlpha;
47 };
48 #define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore)
49 
CreateProc(SkReadBuffer & buffer)50 sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) {
51     sk_sp<SkShader> shaderA(buffer.readShader());
52     sk_sp<SkShader> shaderB(buffer.readShader());
53     SkBlendMode mode;
54     if (buffer.isVersionLT(SkReadBuffer::kXfermodeToBlendMode2_Version)) {
55         sk_sp<SkXfermode> xfer = buffer.readXfermode();
56         mode = xfer ? xfer->blend() : SkBlendMode::kSrcOver;
57     } else {
58         mode = (SkBlendMode)buffer.read32();
59     }
60     if (!shaderA || !shaderB) {
61         return nullptr;
62     }
63     return sk_make_sp<SkComposeShader>(std::move(shaderA), std::move(shaderB), mode);
64 }
65 
flatten(SkWriteBuffer & buffer) const66 void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
67     buffer.writeFlattenable(fShaderA.get());
68     buffer.writeFlattenable(fShaderB.get());
69     buffer.write32((int)fMode);
70 }
71 
onMakeContext(const ContextRec & rec,SkArenaAlloc * alloc) const72 SkShader::Context* SkComposeShader::onMakeContext(
73     const ContextRec& rec, SkArenaAlloc* alloc) const
74 {
75     // we preconcat our localMatrix (if any) with the device matrix
76     // before calling our sub-shaders
77     SkMatrix tmpM;
78     tmpM.setConcat(*rec.fMatrix, this->getLocalMatrix());
79 
80     // Our sub-shaders need to see opaque, so by combining them we don't double-alphatize the
81     // result. ComposeShader itself will respect the alpha, and post-apply it after calling the
82     // sub-shaders.
83     SkPaint opaquePaint(*rec.fPaint);
84     opaquePaint.setAlpha(0xFF);
85 
86     ContextRec newRec(rec);
87     newRec.fMatrix = &tmpM;
88     newRec.fPaint = &opaquePaint;
89 
90     SkShader::Context* contextA = fShaderA->makeContext(newRec, alloc);
91     SkShader::Context* contextB = fShaderB->makeContext(newRec, alloc);
92     if (!contextA || !contextB) {
93         return nullptr;
94     }
95 
96     return alloc->make<ComposeShaderContext>(*this, rec, contextA, contextB);
97 }
98 
ComposeShaderContext(const SkComposeShader & shader,const ContextRec & rec,SkShader::Context * contextA,SkShader::Context * contextB)99 SkComposeShader::ComposeShaderContext::ComposeShaderContext(
100         const SkComposeShader& shader, const ContextRec& rec,
101         SkShader::Context* contextA, SkShader::Context* contextB)
102     : INHERITED(shader, rec)
103     , fShaderContextA(contextA)
104     , fShaderContextB(contextB) {}
105 
asACompose(ComposeRec * rec) const106 bool SkComposeShader::asACompose(ComposeRec* rec) const {
107     if (rec) {
108         rec->fShaderA   = fShaderA.get();
109         rec->fShaderB   = fShaderB.get();
110         rec->fBlendMode = fMode;
111     }
112     return true;
113 }
114 
115 
116 // larger is better (fewer times we have to loop), but we shouldn't
117 // take up too much stack-space (each element is 4 bytes)
118 #define TMP_COLOR_COUNT     64
119 
shadeSpan(int x,int y,SkPMColor result[],int count)120 void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
121     SkShader::Context* shaderContextA = fShaderContextA;
122     SkShader::Context* shaderContextB = fShaderContextB;
123     SkBlendMode        mode = static_cast<const SkComposeShader&>(fShader).fMode;
124     unsigned           scale = SkAlpha255To256(this->getPaintAlpha());
125 
126     SkPMColor   tmp[TMP_COLOR_COUNT];
127 
128     SkXfermode* xfer = SkXfermode::Peek(mode);
129     if (nullptr == xfer) {   // implied SRC_OVER
130         // TODO: when we have a good test-case, should use SkBlitRow::Proc32
131         // for these loops
132         do {
133             int n = count;
134             if (n > TMP_COLOR_COUNT) {
135                 n = TMP_COLOR_COUNT;
136             }
137 
138             shaderContextA->shadeSpan(x, y, result, n);
139             shaderContextB->shadeSpan(x, y, tmp, n);
140 
141             if (256 == scale) {
142                 for (int i = 0; i < n; i++) {
143                     result[i] = SkPMSrcOver(tmp[i], result[i]);
144                 }
145             } else {
146                 for (int i = 0; i < n; i++) {
147                     result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
148                                             scale);
149                 }
150             }
151 
152             result += n;
153             x += n;
154             count -= n;
155         } while (count > 0);
156     } else {    // use mode for the composition
157         do {
158             int n = count;
159             if (n > TMP_COLOR_COUNT) {
160                 n = TMP_COLOR_COUNT;
161             }
162 
163             shaderContextA->shadeSpan(x, y, result, n);
164             shaderContextB->shadeSpan(x, y, tmp, n);
165             xfer->xfer32(result, tmp, n, nullptr);
166 
167             if (256 != scale) {
168                 for (int i = 0; i < n; i++) {
169                     result[i] = SkAlphaMulQ(result[i], scale);
170                 }
171             }
172 
173             result += n;
174             x += n;
175             count -= n;
176         } while (count > 0);
177     }
178 }
179 
180 #if SK_SUPPORT_GPU
181 
182 #include "effects/GrConstColorProcessor.h"
183 #include "effects/GrXfermodeFragmentProcessor.h"
184 
185 /////////////////////////////////////////////////////////////////////
186 
asFragmentProcessor(const AsFPArgs & args) const187 sk_sp<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(const AsFPArgs& args) const {
188     switch (fMode) {
189         case SkBlendMode::kClear:
190             return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
191                                                GrConstColorProcessor::kIgnore_InputMode);
192             break;
193         case SkBlendMode::kSrc:
194             return fShaderB->asFragmentProcessor(args);
195             break;
196         case SkBlendMode::kDst:
197             return fShaderA->asFragmentProcessor(args);
198             break;
199         default:
200             sk_sp<GrFragmentProcessor> fpA(fShaderA->asFragmentProcessor(args));
201             if (!fpA) {
202                 return nullptr;
203             }
204             sk_sp<GrFragmentProcessor> fpB(fShaderB->asFragmentProcessor(args));
205             if (!fpB) {
206                 return nullptr;
207             }
208             return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
209                                                                       std::move(fpA), fMode);
210     }
211 }
212 #endif
213 
214 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const215 void SkComposeShader::toString(SkString* str) const {
216     str->append("SkComposeShader: (");
217 
218     str->append("ShaderA: ");
219     fShaderA->toString(str);
220     str->append(" ShaderB: ");
221     fShaderB->toString(str);
222     if (SkBlendMode::kSrcOver != fMode) {
223         str->appendf(" Xfermode: %s", SkXfermode::ModeName(fMode));
224     }
225 
226     this->INHERITED::toString(str);
227 
228     str->append(")");
229 }
230 #endif
231