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
26bool SkColorFilter::asColorMode(SkColor*, SkBlendMode*) const {
27    return false;
28}
29
30bool SkColorFilter::asColorMatrix(SkScalar matrix[20]) const {
31    return false;
32}
33
34bool SkColorFilter::asComponentTable(SkBitmap*) const {
35    return false;
36}
37
38#if SK_SUPPORT_GPU
39std::unique_ptr<GrFragmentProcessor> SkColorFilter::asFragmentProcessor(
40        GrContext*, const GrColorSpaceInfo&) const {
41    return nullptr;
42}
43#endif
44
45void SkColorFilter::appendStages(SkRasterPipeline* p,
46                                 SkColorSpace* dstCS,
47                                 SkArenaAlloc* alloc,
48                                 bool shaderIsOpaque) const {
49    this->onAppendStages(p, dstCS, alloc, shaderIsOpaque);
50}
51
52SkColor 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"
67SkColor4f 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
94class SkComposeColorFilter : public SkColorFilter {
95public:
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
137protected:
138    void flatten(SkWriteBuffer& buffer) const override {
139        buffer.writeFlattenable(fOuter.get());
140        buffer.writeFlattenable(fInner.get());
141    }
142
143private:
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
176sk_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
182sk_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
210class SkSRGBGammaColorFilter : public SkColorFilter {
211public:
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
255protected:
256    void flatten(SkWriteBuffer& buffer) const override {
257        buffer.write32(static_cast<uint32_t>(fDir));
258    }
259
260private:
261    const Direction fDir;
262
263    friend class SkColorFilter;
264    typedef SkColorFilter INHERITED;
265};
266
267sk_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
277void SkSRGBGammaColorFilter::toString(SkString* str) const {
278    str->append("srgbgamma");
279}
280#endif
281
282template <SkSRGBGammaColorFilter::Direction dir>
283sk_sp<SkColorFilter> MakeSRGBGammaCF() {
284    static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir);
285    return sk_ref_sp(gSingleton);
286}
287
288sk_sp<SkColorFilter> SkColorFilter::MakeLinearToSRGBGamma() {
289    return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kLinearToSRGB>();
290}
291
292sk_sp<SkColorFilter> SkColorFilter::MakeSRGBToLinearGamma() {
293    return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kSRGBToLinear>();
294}
295
296///////////////////////////////////////////////////////////////////////////////////////////////////
297
298#include "SkModeColorFilter.h"
299
300SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter)
301SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeColorFilter)
302SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter)
303SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSRGBGammaColorFilter)
304SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
305