Home | History | Annotate | Download | only in shaders
      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