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