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::shadeSpan4f(int x, int y, SkPM4f span[], int count) { 72 for (int i = 0; i < count; ++i) { 73 span[i] = fPM4f; 74 } 75 } 76 77 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" 92 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 101 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 116 static unsigned unit_to_byte(float unit) { 117 SkASSERT(unit >= 0 && unit <= 1); 118 return (unsigned)(unit * 255 + 0.5); 119 } 120 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 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 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 141 void SkColor4Shader::flatten(SkWriteBuffer& buffer) const { 142 buffer.writeColor4f(fColor4); 143 buffer.writeBool(false); // TODO how do we flatten colorspaces? 144 } 145 146 uint32_t SkColor4Shader::Color4Context::getFlags() const { 147 return fFlags; 148 } 149 150 SkShaderBase::Context* SkColor4Shader::onMakeContext(const ContextRec& rec, 151 SkArenaAlloc* alloc) const { 152 return alloc->make<Color4Context>(*this, rec); 153 } 154 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 183 void SkColor4Shader::Color4Context::shadeSpan(int x, int y, SkPMColor span[], int count) { 184 sk_memset32(span, fPMColor, count); 185 } 186 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? 194 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 212 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 229 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 240 sk_sp<SkShader> SkColor4Shader::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 241 return SkShader::MakeColorShader(xformer->apply(fCachedByteColor)); 242 } 243 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 253 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 258 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