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 "SkBlendModePriv.h"
10 #include "SkComposeShader.h"
11 #include "SkColorFilter.h"
12 #include "SkColorData.h"
13 #include "SkColorShader.h"
14 #include "SkRasterPipeline.h"
15 #include "SkReadBuffer.h"
16 #include "SkWriteBuffer.h"
17 #include "SkString.h"
18 
MakeCompose(sk_sp<SkShader> dst,sk_sp<SkShader> src,SkBlendMode mode,float lerpT)19 sk_sp<SkShader> SkShader::MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode,
20                                       float lerpT) {
21     if (!src || !dst || SkScalarIsNaN(lerpT)) {
22         return nullptr;
23     }
24     lerpT = SkScalarPin(lerpT, 0, 1);
25 
26     if (lerpT == 0) {
27         return dst;
28     } else if (lerpT == 1) {
29         if (mode == SkBlendMode::kSrc) {
30             return src;
31         }
32         if (mode == SkBlendMode::kDst) {
33             return dst;
34         }
35     }
36     return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode, lerpT));
37 }
38 
39 ///////////////////////////////////////////////////////////////////////////////
40 
CreateProc(SkReadBuffer & buffer)41 sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) {
42     sk_sp<SkShader> dst(buffer.readShader());
43     sk_sp<SkShader> src(buffer.readShader());
44     unsigned        mode = buffer.read32();
45     float           lerp = buffer.readScalar();
46 
47     // check for valid mode before we cast to the enum type
48     if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
49         return nullptr;
50     }
51     return MakeCompose(std::move(dst), std::move(src), static_cast<SkBlendMode>(mode), lerp);
52 }
53 
flatten(SkWriteBuffer & buffer) const54 void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
55     buffer.writeFlattenable(fDst.get());
56     buffer.writeFlattenable(fSrc.get());
57     buffer.write32((int)fMode);
58     buffer.writeScalar(fLerpT);
59 }
60 
onMakeColorSpace(SkColorSpaceXformer * xformer) const61 sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
62     return MakeCompose(xformer->apply(fDst.get()), xformer->apply(fSrc.get()),
63                        fMode, fLerpT);
64 }
65 
66 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
asACompose(ComposeRec * rec) const67 bool SkComposeShader::asACompose(ComposeRec* rec) const {
68     if (!this->isJustMode()) {
69         return false;
70     }
71 
72     if (rec) {
73         rec->fShaderA   = fDst.get();
74         rec->fShaderB   = fSrc.get();
75         rec->fBlendMode = fMode;
76     }
77     return true;
78 }
79 #endif
80 
onAppendStages(const StageRec & rec) const81 bool SkComposeShader::onAppendStages(const StageRec& rec) const {
82     struct Storage {
83         float   fRGBA[4 * SkRasterPipeline_kMaxStride];
84         float   fAlpha;
85     };
86     auto storage = rec.fAlloc->make<Storage>();
87 
88     if (!as_SB(fSrc)->appendStages(rec)) {
89         return false;
90     }
91     // This outputs r,g,b,a, which we'll need later when we apply the mode, but we save it off now
92     // since fShaderB will overwrite them.
93     rec.fPipeline->append(SkRasterPipeline::store_rgba, storage->fRGBA);
94 
95     if (!as_SB(fDst)->appendStages(rec)) {
96         return false;
97     }
98     // We now have our logical 'dst' in r,g,b,a, but we need it in dr,dg,db,da for the mode/lerp
99     // so we have to shuttle them. If we had a stage the would load_into_dst, then we could
100     // reverse the two shader invocations, and avoid this move...
101     rec.fPipeline->append(SkRasterPipeline::move_src_dst);
102     rec.fPipeline->append(SkRasterPipeline::load_rgba, storage->fRGBA);
103 
104     if (!this->isJustLerp()) {
105         SkBlendMode_AppendStages(fMode, rec.fPipeline);
106     }
107     if (!this->isJustMode()) {
108         rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fLerpT);
109     }
110     return true;
111 }
112 
113 #if SK_SUPPORT_GPU
114 
115 #include "effects/GrConstColorProcessor.h"
116 #include "effects/GrXfermodeFragmentProcessor.h"
117 
118 /////////////////////////////////////////////////////////////////////
119 
asFragmentProcessor(const GrFPArgs & args) const120 std::unique_ptr<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(
121         const GrFPArgs& args) const {
122     if (this->isJustMode()) {
123         SkASSERT(fMode != SkBlendMode::kSrc && fMode != SkBlendMode::kDst); // caught in factory
124         if (fMode == SkBlendMode::kClear) {
125             return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
126                                                GrConstColorProcessor::InputMode::kIgnore);
127         }
128     }
129 
130     std::unique_ptr<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args));
131     if (!fpA) {
132         return nullptr;
133     }
134     std::unique_ptr<GrFragmentProcessor> fpB(as_SB(fSrc)->asFragmentProcessor(args));
135     if (!fpB) {
136         return nullptr;
137     }
138     // TODO: account for fLerpT when it is < 1
139     return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
140                                                               std::move(fpA), fMode);
141 }
142 #endif
143