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::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