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 16 SkColorShader::SkColorShader(SkColor c) : fColor(c) {} 17 18 bool SkColorShader::isOpaque() const { 19 return SkColorGetA(fColor) == 255; 20 } 21 22 sk_sp<SkFlattenable> SkColorShader::CreateProc(SkReadBuffer& buffer) { 23 return sk_make_sp<SkColorShader>(buffer.readColor()); 24 } 25 26 void SkColorShader::flatten(SkWriteBuffer& buffer) const { 27 buffer.writeColor(fColor); 28 } 29 30 uint32_t SkColorShader::ColorShaderContext::getFlags() const { 31 return fFlags; 32 } 33 34 SkShaderBase::Context* SkColorShader::onMakeContext(const ContextRec& rec, 35 SkArenaAlloc* alloc) const { 36 return alloc->make<ColorShaderContext>(*this, rec); 37 } 38 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 67 void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) { 68 sk_memset32(span, fPMColor, count); 69 } 70 71 void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { 72 memset(alpha, SkGetPackedA32(fPMColor), count); 73 } 74 75 void SkColorShader::ColorShaderContext::shadeSpan4f(int x, int y, SkPM4f span[], int count) { 76 for (int i = 0; i < count; ++i) { 77 span[i] = fPM4f; 78 } 79 } 80 81 SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const { 82 if (info) { 83 if (info->fColors && info->fColorCount >= 1) { 84 info->fColors[0] = fColor; 85 } 86 info->fColorCount = 1; 87 info->fTileMode = SkShader::kRepeat_TileMode; 88 } 89 return kColor_GradientType; 90 } 91 92 #if SK_SUPPORT_GPU 93 94 #include "SkGr.h" 95 #include "effects/GrConstColorProcessor.h" 96 sk_sp<GrFragmentProcessor> SkColorShader::asFragmentProcessor(const AsFPArgs& args) const { 97 GrColor4f color = SkColorToPremulGrColor4f(fColor, args.fDstColorSpace); 98 return GrConstColorProcessor::Make(color, GrConstColorProcessor::kModulateA_InputMode); 99 } 100 101 #endif 102 103 #ifndef SK_IGNORE_TO_STRING 104 void SkColorShader::toString(SkString* str) const { 105 str->append("SkColorShader: ("); 106 107 str->append("Color: "); 108 str->appendHex(fColor); 109 110 this->INHERITED::toString(str); 111 112 str->append(")"); 113 } 114 #endif 115 116 /////////////////////////////////////////////////////////////////////////////////////////////////// 117 /////////////////////////////////////////////////////////////////////////////////////////////////// 118 119 static unsigned unit_to_byte(float unit) { 120 SkASSERT(unit >= 0 && unit <= 1); 121 return (unsigned)(unit * 255 + 0.5); 122 } 123 124 static SkColor unit_to_skcolor(const SkColor4f& unit, SkColorSpace* cs) { 125 return SkColorSetARGB(unit_to_byte(unit.fA), unit_to_byte(unit.fR), 126 unit_to_byte(unit.fG), unit_to_byte(unit.fB)); 127 } 128 129 SkColor4Shader::SkColor4Shader(const SkColor4f& color, sk_sp<SkColorSpace> space) 130 : fColorSpace(std::move(space)) 131 , fColor4(color) 132 , fCachedByteColor(unit_to_skcolor(color.pin(), space.get())) 133 {} 134 135 sk_sp<SkFlattenable> SkColor4Shader::CreateProc(SkReadBuffer& buffer) { 136 SkColor4f color; 137 buffer.readColor4f(&color); 138 if (buffer.readBool()) { 139 // TODO how do we unflatten colorspaces 140 } 141 return SkShader::MakeColorShader(color, nullptr); 142 } 143 144 void SkColor4Shader::flatten(SkWriteBuffer& buffer) const { 145 buffer.writeColor4f(fColor4); 146 buffer.writeBool(false); // TODO how do we flatten colorspaces? 147 } 148 149 uint32_t SkColor4Shader::Color4Context::getFlags() const { 150 return fFlags; 151 } 152 153 SkShaderBase::Context* SkColor4Shader::onMakeContext(const ContextRec& rec, 154 SkArenaAlloc* alloc) const { 155 return alloc->make<Color4Context>(*this, rec); 156 } 157 158 SkColor4Shader::Color4Context::Color4Context(const SkColor4Shader& shader, 159 const ContextRec& rec) 160 : INHERITED(shader, rec) 161 { 162 SkColor color = shader.fCachedByteColor; 163 unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha())); 164 165 unsigned r = SkColorGetR(color); 166 unsigned g = SkColorGetG(color); 167 unsigned b = SkColorGetB(color); 168 169 if (a != 255) { 170 r = SkMulDiv255Round(r, a); 171 g = SkMulDiv255Round(g, a); 172 b = SkMulDiv255Round(b, a); 173 } 174 fPMColor = SkPackARGB32(a, r, g, b); 175 176 SkColor4f c4 = shader.fColor4; 177 c4.fA *= rec.fPaint->getAlpha() * (1 / 255.0f); 178 fPM4f = c4.premul(); 179 180 fFlags = kConstInY32_Flag; 181 if (255 == a) { 182 fFlags |= kOpaqueAlpha_Flag; 183 } 184 } 185 186 void SkColor4Shader::Color4Context::shadeSpan(int x, int y, SkPMColor span[], int count) { 187 sk_memset32(span, fPMColor, count); 188 } 189 190 void SkColor4Shader::Color4Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { 191 memset(alpha, SkGetPackedA32(fPMColor), count); 192 } 193 194 void SkColor4Shader::Color4Context::shadeSpan4f(int x, int y, SkPM4f span[], int count) { 195 for (int i = 0; i < count; ++i) { 196 span[i] = fPM4f; 197 } 198 } 199 200 // TODO: do we need an updated version of this method for color4+colorspace? 201 SkShader::GradientType SkColor4Shader::asAGradient(GradientInfo* info) const { 202 if (info) { 203 if (info->fColors && info->fColorCount >= 1) { 204 info->fColors[0] = fCachedByteColor; 205 } 206 info->fColorCount = 1; 207 info->fTileMode = SkShader::kRepeat_TileMode; 208 } 209 return kColor_GradientType; 210 } 211 212 #if SK_SUPPORT_GPU 213 214 #include "SkGr.h" 215 #include "effects/GrConstColorProcessor.h" 216 #include "GrColorSpaceXform.h" 217 sk_sp<GrFragmentProcessor> SkColor4Shader::asFragmentProcessor(const AsFPArgs& args) const { 218 sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(), 219 args.fDstColorSpace); 220 GrColor4f color = GrColor4f::FromSkColor4f(fColor4); 221 if (colorSpaceXform) { 222 color = colorSpaceXform->apply(color); 223 } 224 return GrConstColorProcessor::Make(color.premul(), GrConstColorProcessor::kModulateA_InputMode); 225 } 226 227 #endif 228 229 #ifndef SK_IGNORE_TO_STRING 230 void SkColor4Shader::toString(SkString* str) const { 231 str->append("SkColor4Shader: ("); 232 233 str->append("RGBA:"); 234 for (int i = 0; i < 4; ++i) { 235 str->appendf(" %g", fColor4.vec()[i]); 236 } 237 str->append(" )"); 238 } 239 #endif 240 241 sk_sp<SkShader> SkColor4Shader::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 242 return SkShader::MakeColorShader(xformer->apply(fCachedByteColor)); 243 } 244 245 sk_sp<SkShader> SkShader::MakeColorShader(const SkColor4f& color, sk_sp<SkColorSpace> space) { 246 if (!SkScalarsAreFinite(color.vec(), 4)) { 247 return nullptr; 248 } 249 return sk_make_sp<SkColor4Shader>(color, std::move(space)); 250 } 251 252 /////////////////////////////////////////////////////////////////////////////////////////////////// 253 254 bool SkColorShader::onAppendStages(SkRasterPipeline* p, 255 SkColorSpace* dst, 256 SkArenaAlloc* scratch, 257 const SkMatrix&, 258 const SkPaint&, 259 const SkMatrix*) const { 260 p->append_uniform_color(scratch, SkPM4f_from_SkColor(fColor, dst)); 261 return true; 262 } 263 264 bool SkColor4Shader::onAppendStages(SkRasterPipeline* p, 265 SkColorSpace* dst, 266 SkArenaAlloc* scratch, 267 const SkMatrix&, 268 const SkPaint&, 269 const SkMatrix*) const { 270 p->append_uniform_color(scratch, to_colorspace(fColor4, fColorSpace.get(), dst).premul()); 271 return true; 272 } 273