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