Line data Source code
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 :
17 0 : sk_sp<SkShader> SkShader::MakeComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src,
18 : SkBlendMode mode) {
19 0 : if (!src || !dst) {
20 0 : return nullptr;
21 : }
22 0 : if (SkBlendMode::kSrc == mode) {
23 0 : return src;
24 : }
25 0 : if (SkBlendMode::kDst == mode) {
26 0 : return dst;
27 : }
28 0 : return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode));
29 : }
30 :
31 : ///////////////////////////////////////////////////////////////////////////////
32 :
33 : class SkAutoAlphaRestore {
34 : public:
35 : SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
36 : fAlpha = paint->getAlpha();
37 : fPaint = paint;
38 : paint->setAlpha(newAlpha);
39 : }
40 :
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 :
50 0 : sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) {
51 0 : sk_sp<SkShader> shaderA(buffer.readShader());
52 0 : sk_sp<SkShader> shaderB(buffer.readShader());
53 : SkBlendMode mode;
54 0 : if (buffer.isVersionLT(SkReadBuffer::kXfermodeToBlendMode2_Version)) {
55 0 : sk_sp<SkXfermode> xfer = buffer.readXfermode();
56 0 : mode = xfer ? xfer->blend() : SkBlendMode::kSrcOver;
57 : } else {
58 0 : mode = (SkBlendMode)buffer.read32();
59 : }
60 0 : if (!shaderA || !shaderB) {
61 0 : return nullptr;
62 : }
63 0 : return sk_make_sp<SkComposeShader>(std::move(shaderA), std::move(shaderB), mode);
64 : }
65 :
66 0 : void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
67 0 : buffer.writeFlattenable(fShaderA.get());
68 0 : buffer.writeFlattenable(fShaderB.get());
69 0 : buffer.write32((int)fMode);
70 0 : }
71 :
72 0 : 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 0 : 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 0 : SkPaint opaquePaint(*rec.fPaint);
84 0 : opaquePaint.setAlpha(0xFF);
85 :
86 0 : ContextRec newRec(rec);
87 0 : newRec.fMatrix = &tmpM;
88 0 : newRec.fPaint = &opaquePaint;
89 :
90 0 : SkShader::Context* contextA = fShaderA->makeContext(newRec, alloc);
91 0 : SkShader::Context* contextB = fShaderB->makeContext(newRec, alloc);
92 0 : if (!contextA || !contextB) {
93 0 : return nullptr;
94 : }
95 :
96 0 : return alloc->make<ComposeShaderContext>(*this, rec, contextA, contextB);
97 : }
98 :
99 0 : SkComposeShader::ComposeShaderContext::ComposeShaderContext(
100 : const SkComposeShader& shader, const ContextRec& rec,
101 0 : SkShader::Context* contextA, SkShader::Context* contextB)
102 : : INHERITED(shader, rec)
103 : , fShaderContextA(contextA)
104 0 : , fShaderContextB(contextB) {}
105 :
106 0 : bool SkComposeShader::asACompose(ComposeRec* rec) const {
107 0 : if (rec) {
108 0 : rec->fShaderA = fShaderA.get();
109 0 : rec->fShaderB = fShaderB.get();
110 0 : rec->fBlendMode = fMode;
111 : }
112 0 : 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 :
120 0 : void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
121 0 : SkShader::Context* shaderContextA = fShaderContextA;
122 0 : SkShader::Context* shaderContextB = fShaderContextB;
123 0 : SkBlendMode mode = static_cast<const SkComposeShader&>(fShader).fMode;
124 0 : unsigned scale = SkAlpha255To256(this->getPaintAlpha());
125 :
126 : SkPMColor tmp[TMP_COLOR_COUNT];
127 :
128 0 : SkXfermode* xfer = SkXfermode::Peek(mode);
129 0 : if (nullptr == xfer) { // implied SRC_OVER
130 : // TODO: when we have a good test-case, should use SkBlitRow::Proc32
131 : // for these loops
132 0 : do {
133 0 : int n = count;
134 0 : if (n > TMP_COLOR_COUNT) {
135 0 : n = TMP_COLOR_COUNT;
136 : }
137 :
138 0 : shaderContextA->shadeSpan(x, y, result, n);
139 0 : shaderContextB->shadeSpan(x, y, tmp, n);
140 :
141 0 : if (256 == scale) {
142 0 : for (int i = 0; i < n; i++) {
143 0 : result[i] = SkPMSrcOver(tmp[i], result[i]);
144 : }
145 : } else {
146 0 : for (int i = 0; i < n; i++) {
147 0 : result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
148 : scale);
149 : }
150 : }
151 :
152 0 : result += n;
153 0 : x += n;
154 0 : count -= n;
155 0 : } while (count > 0);
156 : } else { // use mode for the composition
157 0 : do {
158 0 : int n = count;
159 0 : if (n > TMP_COLOR_COUNT) {
160 0 : n = TMP_COLOR_COUNT;
161 : }
162 :
163 0 : shaderContextA->shadeSpan(x, y, result, n);
164 0 : shaderContextB->shadeSpan(x, y, tmp, n);
165 0 : xfer->xfer32(result, tmp, n, nullptr);
166 :
167 0 : if (256 != scale) {
168 0 : for (int i = 0; i < n; i++) {
169 0 : result[i] = SkAlphaMulQ(result[i], scale);
170 : }
171 : }
172 :
173 0 : result += n;
174 0 : x += n;
175 0 : count -= n;
176 0 : } while (count > 0);
177 : }
178 0 : }
179 :
180 : #if SK_SUPPORT_GPU
181 :
182 : #include "effects/GrConstColorProcessor.h"
183 : #include "effects/GrXfermodeFragmentProcessor.h"
184 :
185 : /////////////////////////////////////////////////////////////////////
186 :
187 0 : sk_sp<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(const AsFPArgs& args) const {
188 0 : switch (fMode) {
189 : case SkBlendMode::kClear:
190 : return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
191 0 : GrConstColorProcessor::kIgnore_InputMode);
192 : break;
193 : case SkBlendMode::kSrc:
194 0 : return fShaderB->asFragmentProcessor(args);
195 : break;
196 : case SkBlendMode::kDst:
197 0 : return fShaderA->asFragmentProcessor(args);
198 : break;
199 : default:
200 0 : sk_sp<GrFragmentProcessor> fpA(fShaderA->asFragmentProcessor(args));
201 0 : if (!fpA) {
202 0 : return nullptr;
203 : }
204 0 : sk_sp<GrFragmentProcessor> fpB(fShaderB->asFragmentProcessor(args));
205 0 : if (!fpB) {
206 0 : return nullptr;
207 : }
208 0 : return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
209 0 : std::move(fpA), fMode);
210 : }
211 : }
212 : #endif
213 :
214 : #ifndef SK_IGNORE_TO_STRING
215 0 : void SkComposeShader::toString(SkString* str) const {
216 0 : str->append("SkComposeShader: (");
217 :
218 0 : str->append("ShaderA: ");
219 0 : fShaderA->toString(str);
220 0 : str->append(" ShaderB: ");
221 0 : fShaderB->toString(str);
222 0 : if (SkBlendMode::kSrcOver != fMode) {
223 0 : str->appendf(" Xfermode: %s", SkXfermode::ModeName(fMode));
224 : }
225 :
226 0 : this->INHERITED::toString(str);
227 :
228 0 : str->append(")");
229 0 : }
230 : #endif
|