1 /*
2  * Copyright 2016 Google Inc.
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 "SkColorShader.h"
10 #include "SkColorSpace.h"
11 #include "SkPM4fPriv.h"
12 #include "SkRasterPipeline.h"
13 #include "SkReadBuffer.h"
14 #include "SkUtils.h"
15 
SkColorShader(SkColor c)16 SkColorShader::SkColorShader(SkColor c) : fColor(c) {}
17 
isOpaque() const18 bool SkColorShader::isOpaque() const {
19     return SkColorGetA(fColor) == 255;
20 }
21 
CreateProc(SkReadBuffer & buffer)22 sk_sp<SkFlattenable> SkColorShader::CreateProc(SkReadBuffer& buffer) {
23     return sk_make_sp<SkColorShader>(buffer.readColor());
24 }
25 
flatten(SkWriteBuffer & buffer) const26 void SkColorShader::flatten(SkWriteBuffer& buffer) const {
27     buffer.writeColor(fColor);
28 }
29 
getFlags() const30 uint32_t SkColorShader::ColorShaderContext::getFlags() const {
31     return fFlags;
32 }
33 
onMakeContext(const ContextRec & rec,SkArenaAlloc * alloc) const34 SkShader::Context* SkColorShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const {
35     return alloc->make<ColorShaderContext>(*this, rec);
36 }
37 
ColorShaderContext(const SkColorShader & shader,const ContextRec & rec)38 SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader,
39                                                       const ContextRec& rec)
40     : INHERITED(shader, rec)
41 {
42     SkColor color = shader.fColor;
43     unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha()));
44 
45     unsigned r = SkColorGetR(color);
46     unsigned g = SkColorGetG(color);
47     unsigned b = SkColorGetB(color);
48 
49     if (a != 255) {
50         r = SkMulDiv255Round(r, a);
51         g = SkMulDiv255Round(g, a);
52         b = SkMulDiv255Round(b, a);
53     }
54     fPMColor = SkPackARGB32(a, r, g, b);
55 
56     SkColor4f c4 = SkColor4f::FromColor(shader.fColor);
57     c4.fA *= rec.fPaint->getAlpha() / 255.0f;
58     fPM4f = c4.premul();
59 
60     fFlags = kConstInY32_Flag;
61     if (255 == a) {
62         fFlags |= kOpaqueAlpha_Flag;
63     }
64 }
65 
shadeSpan(int x,int y,SkPMColor span[],int count)66 void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) {
67     sk_memset32(span, fPMColor, count);
68 }
69 
shadeSpanAlpha(int x,int y,uint8_t alpha[],int count)70 void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
71     memset(alpha, SkGetPackedA32(fPMColor), count);
72 }
73 
shadeSpan4f(int x,int y,SkPM4f span[],int count)74 void SkColorShader::ColorShaderContext::shadeSpan4f(int x, int y, SkPM4f span[], int count) {
75     for (int i = 0; i < count; ++i) {
76         span[i] = fPM4f;
77     }
78 }
79 
asAGradient(GradientInfo * info) const80 SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
81     if (info) {
82         if (info->fColors && info->fColorCount >= 1) {
83             info->fColors[0] = fColor;
84         }
85         info->fColorCount = 1;
86         info->fTileMode = SkShader::kRepeat_TileMode;
87     }
88     return kColor_GradientType;
89 }
90 
91 #if SK_SUPPORT_GPU
92 
93 #include "SkGr.h"
94 #include "effects/GrConstColorProcessor.h"
asFragmentProcessor(const AsFPArgs & args) const95 sk_sp<GrFragmentProcessor> SkColorShader::asFragmentProcessor(const AsFPArgs& args) const {
96     GrColor4f color = SkColorToPremulGrColor4f(fColor, args.fDstColorSpace);
97     return GrConstColorProcessor::Make(color, GrConstColorProcessor::kModulateA_InputMode);
98 }
99 
100 #endif
101 
102 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const103 void SkColorShader::toString(SkString* str) const {
104     str->append("SkColorShader: (");
105 
106     str->append("Color: ");
107     str->appendHex(fColor);
108 
109     this->INHERITED::toString(str);
110 
111     str->append(")");
112 }
113 #endif
114 
115 ///////////////////////////////////////////////////////////////////////////////////////////////////
116 ///////////////////////////////////////////////////////////////////////////////////////////////////
117 
unit_to_byte(float unit)118 static unsigned unit_to_byte(float unit) {
119     SkASSERT(unit >= 0 && unit <= 1);
120     return (unsigned)(unit * 255 + 0.5);
121 }
122 
unit_to_skcolor(const SkColor4f & unit,SkColorSpace * cs)123 static SkColor unit_to_skcolor(const SkColor4f& unit, SkColorSpace* cs) {
124     return SkColorSetARGB(unit_to_byte(unit.fA), unit_to_byte(unit.fR),
125                           unit_to_byte(unit.fG), unit_to_byte(unit.fB));
126 }
127 
SkColor4Shader(const SkColor4f & color,sk_sp<SkColorSpace> space)128 SkColor4Shader::SkColor4Shader(const SkColor4f& color, sk_sp<SkColorSpace> space)
129     : fColorSpace(std::move(space))
130     , fColor4(color)
131     , fCachedByteColor(unit_to_skcolor(color.pin(), space.get()))
132 {}
133 
CreateProc(SkReadBuffer & buffer)134 sk_sp<SkFlattenable> SkColor4Shader::CreateProc(SkReadBuffer& buffer) {
135     SkColor4f color;
136     buffer.readColor4f(&color);
137     if (buffer.readBool()) {
138         // TODO how do we unflatten colorspaces
139     }
140     return SkShader::MakeColorShader(color, nullptr);
141 }
142 
flatten(SkWriteBuffer & buffer) const143 void SkColor4Shader::flatten(SkWriteBuffer& buffer) const {
144     buffer.writeColor4f(fColor4);
145     buffer.writeBool(false);    // TODO how do we flatten colorspaces?
146 }
147 
getFlags() const148 uint32_t SkColor4Shader::Color4Context::getFlags() const {
149     return fFlags;
150 }
151 
onMakeContext(const ContextRec & rec,SkArenaAlloc * alloc) const152 SkShader::Context* SkColor4Shader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const {
153     return alloc->make<Color4Context>(*this, rec);
154 }
155 
Color4Context(const SkColor4Shader & shader,const ContextRec & rec)156 SkColor4Shader::Color4Context::Color4Context(const SkColor4Shader& shader,
157                                                       const ContextRec& rec)
158 : INHERITED(shader, rec)
159 {
160     SkColor color = shader.fCachedByteColor;
161     unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha()));
162 
163     unsigned r = SkColorGetR(color);
164     unsigned g = SkColorGetG(color);
165     unsigned b = SkColorGetB(color);
166 
167     if (a != 255) {
168         r = SkMulDiv255Round(r, a);
169         g = SkMulDiv255Round(g, a);
170         b = SkMulDiv255Round(b, a);
171     }
172     fPMColor = SkPackARGB32(a, r, g, b);
173 
174     SkColor4f c4 = shader.fColor4;
175     c4.fA *= rec.fPaint->getAlpha() * (1 / 255.0f);
176     fPM4f = c4.premul();
177 
178     fFlags = kConstInY32_Flag;
179     if (255 == a) {
180         fFlags |= kOpaqueAlpha_Flag;
181     }
182 }
183 
shadeSpan(int x,int y,SkPMColor span[],int count)184 void SkColor4Shader::Color4Context::shadeSpan(int x, int y, SkPMColor span[], int count) {
185     sk_memset32(span, fPMColor, count);
186 }
187 
shadeSpanAlpha(int x,int y,uint8_t alpha[],int count)188 void SkColor4Shader::Color4Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
189     memset(alpha, SkGetPackedA32(fPMColor), count);
190 }
191 
shadeSpan4f(int x,int y,SkPM4f span[],int count)192 void SkColor4Shader::Color4Context::shadeSpan4f(int x, int y, SkPM4f span[], int count) {
193     for (int i = 0; i < count; ++i) {
194         span[i] = fPM4f;
195     }
196 }
197 
198 // TODO: do we need an updated version of this method for color4+colorspace?
asAGradient(GradientInfo * info) const199 SkShader::GradientType SkColor4Shader::asAGradient(GradientInfo* info) const {
200     if (info) {
201         if (info->fColors && info->fColorCount >= 1) {
202             info->fColors[0] = fCachedByteColor;
203         }
204         info->fColorCount = 1;
205         info->fTileMode = SkShader::kRepeat_TileMode;
206     }
207     return kColor_GradientType;
208 }
209 
210 #if SK_SUPPORT_GPU
211 
212 #include "SkGr.h"
213 #include "effects/GrConstColorProcessor.h"
214 #include "GrColorSpaceXform.h"
asFragmentProcessor(const AsFPArgs & args) const215 sk_sp<GrFragmentProcessor> SkColor4Shader::asFragmentProcessor(const AsFPArgs& args) const {
216     sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
217                                                                        args.fDstColorSpace);
218     GrColor4f color = GrColor4f::FromSkColor4f(fColor4);
219     if (colorSpaceXform) {
220         color = colorSpaceXform->apply(color);
221     }
222     return GrConstColorProcessor::Make(color.premul(), GrConstColorProcessor::kModulateA_InputMode);
223 }
224 
225 #endif
226 
227 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const228 void SkColor4Shader::toString(SkString* str) const {
229     str->append("SkColor4Shader: (");
230 
231     str->append("RGBA:");
232     for (int i = 0; i < 4; ++i) {
233         str->appendf(" %g", fColor4.vec()[i]);
234     }
235     str->append(" )");
236 }
237 #endif
238 
MakeColorShader(const SkColor4f & color,sk_sp<SkColorSpace> space)239 sk_sp<SkShader> SkShader::MakeColorShader(const SkColor4f& color, sk_sp<SkColorSpace> space) {
240     if (!SkScalarsAreFinite(color.vec(), 4)) {
241         return nullptr;
242     }
243     return sk_make_sp<SkColor4Shader>(color, std::move(space));
244 }
245 
246 ///////////////////////////////////////////////////////////////////////////////////////////////////
247 ///////////////////////////////////////////////////////////////////////////////////////////////////
248 
D32_BlitBW(SkShader::Context::BlitState * state,int x,int y,const SkPixmap & dst,int count)249 static void D32_BlitBW(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
250                        int count) {
251     SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0];
252     const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
253     proc(state->fMode, dst.writable_addr32(x, y), src, count, nullptr);
254 }
255 
D32_BlitAA(SkShader::Context::BlitState * state,int x,int y,const SkPixmap & dst,int count,const SkAlpha aa[])256 static void D32_BlitAA(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
257                        int count, const SkAlpha aa[]) {
258     SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0];
259     const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
260     proc(state->fMode, dst.writable_addr32(x, y), src, count, aa);
261 }
262 
F16_BlitBW(SkShader::Context::BlitState * state,int x,int y,const SkPixmap & dst,int count)263 static void F16_BlitBW(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
264                        int count) {
265     SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0];
266     const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
267     proc(state->fMode, dst.writable_addr64(x, y), src, count, nullptr);
268 }
269 
F16_BlitAA(SkShader::Context::BlitState * state,int x,int y,const SkPixmap & dst,int count,const SkAlpha aa[])270 static void F16_BlitAA(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst,
271                        int count, const SkAlpha aa[]) {
272     SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0];
273     const SkPM4f* src = (const SkPM4f*)state->fStorage[1];
274     proc(state->fMode, dst.writable_addr64(x, y), src, count, aa);
275 }
276 
choose_blitprocs(const SkPM4f * pm4,const SkImageInfo & info,SkShader::Context::BlitState * state)277 static bool choose_blitprocs(const SkPM4f* pm4, const SkImageInfo& info,
278                              SkShader::Context::BlitState* state) {
279     uint32_t flags = SkXfermode::kSrcIsSingle_D32Flag;
280     if (pm4->a() == 1) {
281         flags |= SkXfermode::kSrcIsOpaque_D32Flag;
282     }
283     switch (info.colorType()) {
284         case kN32_SkColorType:
285             if (info.gammaCloseToSRGB()) {
286                 flags |= SkXfermode::kDstIsSRGB_D32Flag;
287             }
288             state->fStorage[0] = (void*)SkXfermode::GetD32Proc(state->fMode, flags);
289             state->fStorage[1] = (void*)pm4;
290             state->fBlitBW = D32_BlitBW;
291             state->fBlitAA = D32_BlitAA;
292             return true;
293         case kRGBA_F16_SkColorType:
294             state->fStorage[0] = (void*)SkXfermode::GetF16Proc(state->fMode, flags);
295             state->fStorage[1] = (void*)pm4;
296             state->fBlitBW = F16_BlitBW;
297             state->fBlitAA = F16_BlitAA;
298             return true;
299         default:
300             return false;
301     }
302 }
303 
onChooseBlitProcs(const SkImageInfo & info,BlitState * state)304 bool SkColorShader::ColorShaderContext::onChooseBlitProcs(const SkImageInfo& info,
305                                                           BlitState* state) {
306     return choose_blitprocs(&fPM4f, info, state);
307 }
308 
onChooseBlitProcs(const SkImageInfo & info,BlitState * state)309 bool SkColor4Shader::Color4Context::onChooseBlitProcs(const SkImageInfo& info, BlitState* state) {
310     return choose_blitprocs(&fPM4f, info, state);
311 }
312 
onAppendStages(SkRasterPipeline * p,SkColorSpace * dst,SkArenaAlloc * scratch,const SkMatrix &,const SkPaint &,const SkMatrix *) const313 bool SkColorShader::onAppendStages(SkRasterPipeline* p,
314                                    SkColorSpace* dst,
315                                    SkArenaAlloc* scratch,
316                                    const SkMatrix&,
317                                    const SkPaint&,
318                                    const SkMatrix*) const {
319     auto color = scratch->make<SkPM4f>(SkPM4f_from_SkColor(fColor, dst));
320     p->append(SkRasterPipeline::constant_color, color);
321     return append_gamut_transform(p, scratch,
322                                   SkColorSpace::MakeSRGB().get(), dst);
323 }
324 
onAppendStages(SkRasterPipeline * p,SkColorSpace * dst,SkArenaAlloc * scratch,const SkMatrix &,const SkPaint &,const SkMatrix *) const325 bool SkColor4Shader::onAppendStages(SkRasterPipeline* p,
326                                     SkColorSpace* dst,
327                                     SkArenaAlloc* scratch,
328                                     const SkMatrix&,
329                                     const SkPaint&,
330                                     const SkMatrix*) const {
331     auto color = scratch->make<SkPM4f>(fColor4.premul());
332     p->append(SkRasterPipeline::constant_color, color);
333     return append_gamut_transform(p, scratch, fColorSpace.get(), dst);
334 }
335