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 "SkColorFilter.h"
9#include "SkArenaAlloc.h"
10#include "SkReadBuffer.h"
11#include "SkRefCnt.h"
12#include "SkString.h"
13#include "SkTDArray.h"
14#include "SkUnPreMultiply.h"
15#include "SkWriteBuffer.h"
16#include "SkPM4f.h"
17#include "SkNx.h"
18
19#if SK_SUPPORT_GPU
20#include "GrFragmentProcessor.h"
21#endif
22
23bool SkColorFilter::asColorMode(SkColor*, SkBlendMode*) const {
24    return false;
25}
26
27bool SkColorFilter::asColorMatrix(SkScalar matrix[20]) const {
28    return false;
29}
30
31bool SkColorFilter::asComponentTable(SkBitmap*) const {
32    return false;
33}
34
35#if SK_SUPPORT_GPU
36sk_sp<GrFragmentProcessor> SkColorFilter::asFragmentProcessor(GrContext*, SkColorSpace*) const {
37    return nullptr;
38}
39#endif
40
41bool SkColorFilter::appendStages(SkRasterPipeline* pipeline,
42                                 SkColorSpace* dst,
43                                 SkArenaAlloc* scratch,
44                                 bool shaderIsOpaque) const {
45    return this->onAppendStages(pipeline, dst, scratch, shaderIsOpaque);
46}
47
48bool SkColorFilter::onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, bool) const {
49    return false;
50}
51
52void SkColorFilter::filterSpan4f(const SkPM4f src[], int count, SkPM4f result[]) const {
53    const int N = 128;
54    SkPMColor tmp[N];
55    while (count > 0) {
56        int n = SkTMin(count, N);
57        for (int i = 0; i < n; ++i) {
58            tmp[i] = src[i].toPMColor();
59        }
60        this->filterSpan(tmp, n, tmp);
61        for (int i = 0; i < n; ++i) {
62            result[i] = SkPM4f::FromPMColor(tmp[i]);
63        }
64        src += n;
65        result += n;
66        count -= n;
67    }
68}
69
70SkColor SkColorFilter::filterColor(SkColor c) const {
71    SkPMColor dst, src = SkPreMultiplyColor(c);
72    this->filterSpan(&src, 1, &dst);
73    return SkUnPreMultiply::PMColorToColor(dst);
74}
75
76SkColor4f SkColorFilter::filterColor4f(const SkColor4f& c) const {
77    SkPM4f dst, src = c.premul();
78    this->filterSpan4f(&src, 1, &dst);
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    void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
102        fInner->filterSpan(shader, count, result);
103        fOuter->filterSpan(result, count, result);
104    }
105
106    void filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const override {
107        fInner->filterSpan4f(shader, count, result);
108        fOuter->filterSpan4f(result, count, result);
109    }
110
111#ifndef SK_IGNORE_TO_STRING
112    void toString(SkString* str) const override {
113        SkString outerS, innerS;
114        fOuter->toString(&outerS);
115        fInner->toString(&innerS);
116        // These strings can be long.  SkString::appendf has limitations.
117        str->append(SkStringPrintf("SkComposeColorFilter: outer(%s) inner(%s)", outerS.c_str(),
118                                   innerS.c_str()));
119    }
120#endif
121
122#if SK_SUPPORT_GPU
123    sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext* context,
124                                                   SkColorSpace* dstColorSpace) const override {
125        sk_sp<GrFragmentProcessor> innerFP(fInner->asFragmentProcessor(context, dstColorSpace));
126        sk_sp<GrFragmentProcessor> outerFP(fOuter->asFragmentProcessor(context, dstColorSpace));
127        if (!innerFP || !outerFP) {
128            return nullptr;
129        }
130        sk_sp<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> fOuter;
159    sk_sp<SkColorFilter> fInner;
160    const int            fComposedFilterCount;
161
162    friend class SkColorFilter;
163
164    typedef SkColorFilter INHERITED;
165};
166
167sk_sp<SkFlattenable> SkComposeColorFilter::CreateProc(SkReadBuffer& buffer) {
168    sk_sp<SkColorFilter> outer(buffer.readColorFilter());
169    sk_sp<SkColorFilter> inner(buffer.readColorFilter());
170    return MakeComposeFilter(std::move(outer), std::move(inner));
171}
172
173///////////////////////////////////////////////////////////////////////////////////////////////////
174
175sk_sp<SkColorFilter> SkColorFilter::MakeComposeFilter(sk_sp<SkColorFilter> outer,
176                                                      sk_sp<SkColorFilter> inner) {
177    if (!outer) {
178        return inner;
179    }
180    if (!inner) {
181        return outer;
182    }
183
184    // Give the subclass a shot at a more optimal composition...
185    auto composition = outer->makeComposed(inner);
186    if (composition) {
187        return composition;
188    }
189
190    int count = inner->privateComposedFilterCount() + outer->privateComposedFilterCount();
191    if (count > SK_MAX_COMPOSE_COLORFILTER_COUNT) {
192        return nullptr;
193    }
194    return sk_sp<SkColorFilter>(new SkComposeColorFilter(std::move(outer), std::move(inner),count));
195}
196
197#include "SkModeColorFilter.h"
198
199SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter)
200SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeColorFilter)
201SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter)
202SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
203