• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 SkShaderBase::Context* SkColorShader::onMakeContext(const ContextRec& rec,
35                                                     SkArenaAlloc* alloc) const {
36     return alloc->make<ColorShaderContext>(*this, rec);
37 }
38 
ColorShaderContext(const SkColorShader & shader,const ContextRec & rec)39 SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader,
40                                                       const ContextRec& rec)
41     : INHERITED(shader, rec)
42 {
43     SkColor color = shader.fColor;
44     unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha()));
45 
46     unsigned r = SkColorGetR(color);
47     unsigned g = SkColorGetG(color);
48     unsigned b = SkColorGetB(color);
49 
50     if (a != 255) {
51         r = SkMulDiv255Round(r, a);
52         g = SkMulDiv255Round(g, a);
53         b = SkMulDiv255Round(b, a);
54     }
55     fPMColor = SkPackARGB32(a, r, g, b);
56 
57     SkColor4f c4 = SkColor4f::FromColor(shader.fColor);
58     c4.fA *= rec.fPaint->getAlpha() / 255.0f;
59     fPM4f = c4.premul();
60 
61     fFlags = kConstInY32_Flag;
62     if (255 == a) {
63         fFlags |= kOpaqueAlpha_Flag;
64     }
65 }
66 
shadeSpan(int x,int y,SkPMColor span[],int count)67 void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) {
68     sk_memset32(span, fPMColor, count);
69 }
70 
shadeSpan4f(int x,int y,SkPM4f span[],int count)71 void SkColorShader::ColorShaderContext::shadeSpan4f(int x, int y, SkPM4f span[], int count) {
72     for (int i = 0; i < count; ++i) {
73         span[i] = fPM4f;
74     }
75 }
76 
asAGradient(GradientInfo * info) const77 SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
78     if (info) {
79         if (info->fColors && info->fColorCount >= 1) {
80             info->fColors[0] = fColor;
81         }
82         info->fColorCount = 1;
83         info->fTileMode = SkShader::kRepeat_TileMode;
84     }
85     return kColor_GradientType;
86 }
87 
88 #if SK_SUPPORT_GPU
89 
90 #include "SkGr.h"
91 #include "effects/GrConstColorProcessor.h"
asFragmentProcessor(const GrFPArgs & args) const92 std::unique_ptr<GrFragmentProcessor> SkColorShader::asFragmentProcessor(
93         const GrFPArgs& args) const {
94     GrColor4f color = SkColorToPremulGrColor4f(fColor, *args.fDstColorSpaceInfo);
95     return GrConstColorProcessor::Make(color, GrConstColorProcessor::InputMode::kModulateA);
96 }
97 
98 #endif
99 
100 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const101 void SkColorShader::toString(SkString* str) const {
102     str->append("SkColorShader: (");
103 
104     str->append("Color: ");
105     str->appendHex(fColor);
106 
107     this->INHERITED::toString(str);
108 
109     str->append(")");
110 }
111 #endif
112 
113 ///////////////////////////////////////////////////////////////////////////////////////////////////
114 ///////////////////////////////////////////////////////////////////////////////////////////////////
115 
unit_to_byte(float unit)116 static unsigned unit_to_byte(float unit) {
117     SkASSERT(unit >= 0 && unit <= 1);
118     return (unsigned)(unit * 255 + 0.5);
119 }
120 
unit_to_skcolor(const SkColor4f & unit,SkColorSpace * cs)121 static SkColor unit_to_skcolor(const SkColor4f& unit, SkColorSpace* cs) {
122     return SkColorSetARGB(unit_to_byte(unit.fA), unit_to_byte(unit.fR),
123                           unit_to_byte(unit.fG), unit_to_byte(unit.fB));
124 }
125 
SkColor4Shader(const SkColor4f & color,sk_sp<SkColorSpace> space)126 SkColor4Shader::SkColor4Shader(const SkColor4f& color, sk_sp<SkColorSpace> space)
127     : fColorSpace(std::move(space))
128     , fColor4(color)
129     , fCachedByteColor(unit_to_skcolor(color.pin(), space.get()))
130 {}
131 
CreateProc(SkReadBuffer & buffer)132 sk_sp<SkFlattenable> SkColor4Shader::CreateProc(SkReadBuffer& buffer) {
133     SkColor4f color;
134     buffer.readColor4f(&color);
135     if (buffer.readBool()) {
136         // TODO how do we unflatten colorspaces
137     }
138     return SkShader::MakeColorShader(color, nullptr);
139 }
140 
flatten(SkWriteBuffer & buffer) const141 void SkColor4Shader::flatten(SkWriteBuffer& buffer) const {
142     buffer.writeColor4f(fColor4);
143     buffer.writeBool(false);    // TODO how do we flatten colorspaces?
144 }
145 
getFlags() const146 uint32_t SkColor4Shader::Color4Context::getFlags() const {
147     return fFlags;
148 }
149 
onMakeContext(const ContextRec & rec,SkArenaAlloc * alloc) const150 SkShaderBase::Context* SkColor4Shader::onMakeContext(const ContextRec& rec,
151                                                      SkArenaAlloc* alloc) const {
152     return alloc->make<Color4Context>(*this, rec);
153 }
154 
Color4Context(const SkColor4Shader & shader,const ContextRec & rec)155 SkColor4Shader::Color4Context::Color4Context(const SkColor4Shader& shader,
156                                                       const ContextRec& rec)
157 : INHERITED(shader, rec)
158 {
159     SkColor color = shader.fCachedByteColor;
160     unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha()));
161 
162     unsigned r = SkColorGetR(color);
163     unsigned g = SkColorGetG(color);
164     unsigned b = SkColorGetB(color);
165 
166     if (a != 255) {
167         r = SkMulDiv255Round(r, a);
168         g = SkMulDiv255Round(g, a);
169         b = SkMulDiv255Round(b, a);
170     }
171     fPMColor = SkPackARGB32(a, r, g, b);
172 
173     SkColor4f c4 = shader.fColor4;
174     c4.fA *= rec.fPaint->getAlpha() * (1 / 255.0f);
175     fPM4f = c4.premul();
176 
177     fFlags = kConstInY32_Flag;
178     if (255 == a) {
179         fFlags |= kOpaqueAlpha_Flag;
180     }
181 }
182 
shadeSpan(int x,int y,SkPMColor span[],int count)183 void SkColor4Shader::Color4Context::shadeSpan(int x, int y, SkPMColor span[], int count) {
184     sk_memset32(span, fPMColor, count);
185 }
186 
shadeSpan4f(int x,int y,SkPM4f span[],int count)187 void SkColor4Shader::Color4Context::shadeSpan4f(int x, int y, SkPM4f span[], int count) {
188     for (int i = 0; i < count; ++i) {
189         span[i] = fPM4f;
190     }
191 }
192 
193 // TODO: do we need an updated version of this method for color4+colorspace?
asAGradient(GradientInfo * info) const194 SkShader::GradientType SkColor4Shader::asAGradient(GradientInfo* info) const {
195     if (info) {
196         if (info->fColors && info->fColorCount >= 1) {
197             info->fColors[0] = fCachedByteColor;
198         }
199         info->fColorCount = 1;
200         info->fTileMode = SkShader::kRepeat_TileMode;
201     }
202     return kColor_GradientType;
203 }
204 
205 #if SK_SUPPORT_GPU
206 
207 #include "GrColorSpaceInfo.h"
208 #include "GrColorSpaceXform.h"
209 #include "SkGr.h"
210 #include "effects/GrConstColorProcessor.h"
211 
asFragmentProcessor(const GrFPArgs & args) const212 std::unique_ptr<GrFragmentProcessor> SkColor4Shader::asFragmentProcessor(
213         const GrFPArgs& args) const {
214     // Construct an xform assuming float inputs. The color space can have a transfer function on
215     // it, which will be applied below.
216     auto colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(), kRGBA_float_GrPixelConfig,
217                                                    args.fDstColorSpaceInfo->colorSpace());
218     GrColor4f color = GrColor4f::FromSkColor4f(fColor4);
219     if (colorSpaceXform) {
220         color = colorSpaceXform->clampedXform(color);
221     }
222     return GrConstColorProcessor::Make(color.premul(),
223                                        GrConstColorProcessor::InputMode::kModulateA);
224 }
225 
226 #endif
227 
228 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const229 void SkColor4Shader::toString(SkString* str) const {
230     str->append("SkColor4Shader: (");
231 
232     str->append("RGBA:");
233     for (int i = 0; i < 4; ++i) {
234         str->appendf(" %g", fColor4.vec()[i]);
235     }
236     str->append(" )");
237 }
238 #endif
239 
onMakeColorSpace(SkColorSpaceXformer * xformer) const240 sk_sp<SkShader> SkColor4Shader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
241     return SkShader::MakeColorShader(xformer->apply(fCachedByteColor));
242 }
243 
MakeColorShader(const SkColor4f & color,sk_sp<SkColorSpace> space)244 sk_sp<SkShader> SkShader::MakeColorShader(const SkColor4f& color, sk_sp<SkColorSpace> space) {
245     if (!SkScalarsAreFinite(color.vec(), 4)) {
246         return nullptr;
247     }
248     return sk_make_sp<SkColor4Shader>(color, std::move(space));
249 }
250 
251 ///////////////////////////////////////////////////////////////////////////////////////////////////
252 
onAppendStages(const StageRec & rec) const253 bool SkColorShader::onAppendStages(const StageRec& rec) const {
254     rec.fPipeline->append_constant_color(rec.fAlloc, SkPM4f_from_SkColor(fColor, rec.fDstCS));
255     return true;
256 }
257 
onAppendStages(const StageRec & rec) const258 bool SkColor4Shader::onAppendStages(const StageRec& rec) const {
259     rec.fPipeline->append_constant_color(
260                      rec.fAlloc, to_colorspace(fColor4, fColorSpace.get(), rec.fDstCS).premul());
261     return true;
262 }
263