Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      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 "SkColorFilter.h"
     10 #include "SkColorSpaceXformer.h"
     11 #include "SkNx.h"
     12 #include "SkPM4f.h"
     13 #include "SkRasterPipeline.h"
     14 #include "SkReadBuffer.h"
     15 #include "SkRefCnt.h"
     16 #include "SkString.h"
     17 #include "SkTDArray.h"
     18 #include "SkUnPreMultiply.h"
     19 #include "SkWriteBuffer.h"
     20 #include "../jumper/SkJumper.h"
     21 
     22 #if SK_SUPPORT_GPU
     23 #include "GrFragmentProcessor.h"
     24 #endif
     25 
     26 bool SkColorFilter::asColorMode(SkColor*, SkBlendMode*) const {
     27     return false;
     28 }
     29 
     30 bool SkColorFilter::asColorMatrix(SkScalar matrix[20]) const {
     31     return false;
     32 }
     33 
     34 bool SkColorFilter::asComponentTable(SkBitmap*) const {
     35     return false;
     36 }
     37 
     38 #if SK_SUPPORT_GPU
     39 sk_sp<GrFragmentProcessor> SkColorFilter::asFragmentProcessor(GrContext*, SkColorSpace*) const {
     40     return nullptr;
     41 }
     42 #endif
     43 
     44 void SkColorFilter::appendStages(SkRasterPipeline* p,
     45                                  SkColorSpace* dstCS,
     46                                  SkArenaAlloc* alloc,
     47                                  bool shaderIsOpaque) const {
     48     this->onAppendStages(p, dstCS, alloc, shaderIsOpaque);
     49 }
     50 
     51 SkColor SkColorFilter::filterColor(SkColor c) const {
     52     const float inv255 = 1.0f / 255;
     53     SkColor4f c4 = this->filterColor4f({
     54         SkColorGetR(c) * inv255,
     55         SkColorGetG(c) * inv255,
     56         SkColorGetB(c) * inv255,
     57         SkColorGetA(c) * inv255,
     58     });
     59     return SkColorSetARGB(sk_float_round2int(c4.fA*255),
     60                           sk_float_round2int(c4.fR*255),
     61                           sk_float_round2int(c4.fG*255),
     62                           sk_float_round2int(c4.fB*255));
     63 }
     64 
     65 #include "SkRasterPipeline.h"
     66 SkColor4f SkColorFilter::filterColor4f(const SkColor4f& c) const {
     67     SkPM4f dst, src = c.premul();
     68 
     69     SkSTArenaAlloc<128> alloc;
     70     SkRasterPipeline    pipeline(&alloc);
     71 
     72     pipeline.append_uniform_color(&alloc, src);
     73     this->onAppendStages(&pipeline, nullptr, &alloc, c.fA == 1);
     74     SkPM4f* dstPtr = &dst;
     75     pipeline.append(SkRasterPipeline::store_f32, &dstPtr);
     76     pipeline.run(0,0, 1);
     77 
     78     return dst.unpremul();
     79 }
     80 
     81 ///////////////////////////////////////////////////////////////////////////////////////////////////
     82 
     83 /*
     84  *  Since colorfilters may be used on the GPU backend, and in that case we may string together
     85  *  many GrFragmentProcessors, we might exceed some internal instruction/resource limit.
     86  *
     87  *  Since we don't yet know *what* those limits might be when we construct the final shader,
     88  *  we just set an arbitrary limit during construction. If later we find smarter ways to know what
     89  *  the limnits are, we can change this constant (or remove it).
     90  */
     91 #define SK_MAX_COMPOSE_COLORFILTER_COUNT    4
     92 
     93 class SkComposeColorFilter : public SkColorFilter {
     94 public:
     95     uint32_t getFlags() const override {
     96         // Can only claim alphaunchanged and SkPM4f support if both our proxys do.
     97         return fOuter->getFlags() & fInner->getFlags();
     98     }
     99 
    100 #ifndef SK_IGNORE_TO_STRING
    101     void toString(SkString* str) const override {
    102         SkString outerS, innerS;
    103         fOuter->toString(&outerS);
    104         fInner->toString(&innerS);
    105         // These strings can be long.  SkString::appendf has limitations.
    106         str->append(SkStringPrintf("SkComposeColorFilter: outer(%s) inner(%s)", outerS.c_str(),
    107                                    innerS.c_str()));
    108     }
    109 #endif
    110 
    111     void onAppendStages(SkRasterPipeline* p, SkColorSpace* dst, SkArenaAlloc* scratch,
    112                         bool shaderIsOpaque) const override {
    113         bool innerIsOpaque = shaderIsOpaque;
    114         if (!(fInner->getFlags() & kAlphaUnchanged_Flag)) {
    115             innerIsOpaque = false;
    116         }
    117         fInner->appendStages(p, dst, scratch, shaderIsOpaque);
    118         fOuter->appendStages(p, dst, scratch, innerIsOpaque);
    119     }
    120 
    121 #if SK_SUPPORT_GPU
    122     sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext* context,
    123                                                    SkColorSpace* dstColorSpace) const override {
    124         sk_sp<GrFragmentProcessor> innerFP(fInner->asFragmentProcessor(context, dstColorSpace));
    125         sk_sp<GrFragmentProcessor> outerFP(fOuter->asFragmentProcessor(context, dstColorSpace));
    126         if (!innerFP || !outerFP) {
    127             return nullptr;
    128         }
    129         sk_sp<GrFragmentProcessor> series[] = { std::move(innerFP), std::move(outerFP) };
    130         return GrFragmentProcessor::RunInSeries(series, 2);
    131     }
    132 #endif
    133 
    134     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeColorFilter)
    135 
    136 protected:
    137     void flatten(SkWriteBuffer& buffer) const override {
    138         buffer.writeFlattenable(fOuter.get());
    139         buffer.writeFlattenable(fInner.get());
    140     }
    141 
    142 private:
    143     SkComposeColorFilter(sk_sp<SkColorFilter> outer, sk_sp<SkColorFilter> inner,
    144                          int composedFilterCount)
    145         : fOuter(std::move(outer))
    146         , fInner(std::move(inner))
    147         , fComposedFilterCount(composedFilterCount)
    148     {
    149         SkASSERT(composedFilterCount >= 2);
    150         SkASSERT(composedFilterCount <= SK_MAX_COMPOSE_COLORFILTER_COUNT);
    151     }
    152 
    153     int privateComposedFilterCount() const override {
    154         return fComposedFilterCount;
    155     }
    156 
    157     sk_sp<SkColorFilter> onMakeColorSpace(SkColorSpaceXformer* xformer) const override {
    158         auto outer = xformer->apply(fOuter.get());
    159         auto inner = xformer->apply(fInner.get());
    160         if (outer != fOuter || inner != fInner) {
    161             return SkColorFilter::MakeComposeFilter(outer, inner);
    162         }
    163         return this->INHERITED::onMakeColorSpace(xformer);
    164     }
    165 
    166     sk_sp<SkColorFilter> fOuter;
    167     sk_sp<SkColorFilter> fInner;
    168     const int            fComposedFilterCount;
    169 
    170     friend class SkColorFilter;
    171 
    172     typedef SkColorFilter INHERITED;
    173 };
    174 
    175 sk_sp<SkFlattenable> SkComposeColorFilter::CreateProc(SkReadBuffer& buffer) {
    176     sk_sp<SkColorFilter> outer(buffer.readColorFilter());
    177     sk_sp<SkColorFilter> inner(buffer.readColorFilter());
    178     return MakeComposeFilter(std::move(outer), std::move(inner));
    179 }
    180 
    181 sk_sp<SkColorFilter> SkColorFilter::MakeComposeFilter(sk_sp<SkColorFilter> outer,
    182                                                       sk_sp<SkColorFilter> inner) {
    183     if (!outer) {
    184         return inner;
    185     }
    186     if (!inner) {
    187         return outer;
    188     }
    189 
    190     // Give the subclass a shot at a more optimal composition...
    191     auto composition = outer->makeComposed(inner);
    192     if (composition) {
    193         return composition;
    194     }
    195 
    196     int count = inner->privateComposedFilterCount() + outer->privateComposedFilterCount();
    197     if (count > SK_MAX_COMPOSE_COLORFILTER_COUNT) {
    198         return nullptr;
    199     }
    200     return sk_sp<SkColorFilter>(new SkComposeColorFilter(std::move(outer), std::move(inner),count));
    201 }
    202 
    203 ///////////////////////////////////////////////////////////////////////////////////////////////////
    204 
    205 #if SK_SUPPORT_GPU
    206 #include "../gpu/effects/GrSRGBEffect.h"
    207 #endif
    208 
    209 class SkSRGBGammaColorFilter : public SkColorFilter {
    210 public:
    211     enum class Direction {
    212         kLinearToSRGB,
    213         kSRGBToLinear,
    214     };
    215     SkSRGBGammaColorFilter(Direction dir) : fDir(dir) {}
    216 
    217 #if SK_SUPPORT_GPU
    218     sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext* x, SkColorSpace* cs) const override {
    219         // wish our caller would let us know if our input was opaque...
    220         GrSRGBEffect::Alpha alpha = GrSRGBEffect::Alpha::kPremul;
    221         switch (fDir) {
    222             case Direction::kLinearToSRGB:
    223                 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kLinearToSRGB, alpha);
    224             case Direction::kSRGBToLinear:
    225                 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear, alpha);
    226         }
    227         return nullptr;
    228     }
    229 #endif
    230 
    231     SK_TO_STRING_OVERRIDE()
    232 
    233     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSRGBGammaColorFilter)
    234 
    235     void onAppendStages(SkRasterPipeline* p, SkColorSpace*, SkArenaAlloc* alloc,
    236                         bool shaderIsOpaque) const override {
    237         if (!shaderIsOpaque) {
    238             p->append(SkRasterPipeline::unpremul);
    239         }
    240         switch (fDir) {
    241             case Direction::kLinearToSRGB:
    242                 p->append(SkRasterPipeline::to_srgb);
    243                 break;
    244             case Direction::kSRGBToLinear:
    245                 p->append_from_srgb(shaderIsOpaque ? kOpaque_SkAlphaType : kUnpremul_SkAlphaType);
    246                 break;
    247         }
    248         if (!shaderIsOpaque) {
    249             p->append(SkRasterPipeline::premul);
    250         }
    251     }
    252 
    253 protected:
    254     void flatten(SkWriteBuffer& buffer) const override {
    255         buffer.write32(static_cast<uint32_t>(fDir));
    256     }
    257 
    258 private:
    259     const Direction fDir;
    260 
    261     friend class SkColorFilter;
    262     typedef SkColorFilter INHERITED;
    263 };
    264 
    265 sk_sp<SkFlattenable> SkSRGBGammaColorFilter::CreateProc(SkReadBuffer& buffer) {
    266     uint32_t dir = buffer.read32();
    267     if (dir <= 1) {
    268         return sk_sp<SkFlattenable>(new SkSRGBGammaColorFilter(static_cast<Direction>(dir)));
    269     }
    270     buffer.validate(false);
    271     return nullptr;
    272 }
    273 
    274 #ifndef SK_IGNORE_TO_STRING
    275 void SkSRGBGammaColorFilter::toString(SkString* str) const {
    276     str->append("srgbgamma");
    277 }
    278 #endif
    279 
    280 template <SkSRGBGammaColorFilter::Direction dir>
    281 sk_sp<SkColorFilter> MakeSRGBGammaCF() {
    282     static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir);
    283     return sk_ref_sp(gSingleton);
    284 }
    285 
    286 sk_sp<SkColorFilter> SkColorFilter::MakeLinearToSRGBGamma() {
    287     return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kLinearToSRGB>();
    288 }
    289 
    290 sk_sp<SkColorFilter> SkColorFilter::MakeSRGBToLinearGamma() {
    291     return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kSRGBToLinear>();
    292 }
    293 
    294 ///////////////////////////////////////////////////////////////////////////////////////////////////
    295 
    296 #include "SkModeColorFilter.h"
    297 
    298 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter)
    299 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeColorFilter)
    300 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter)
    301 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSRGBGammaColorFilter)
    302 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
    303