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 
asColorMode(SkColor *,SkBlendMode *) const26 bool SkColorFilter::asColorMode(SkColor*, SkBlendMode*) const {
27     return false;
28 }
29 
asColorMatrix(SkScalar matrix[20]) const30 bool SkColorFilter::asColorMatrix(SkScalar matrix[20]) const {
31     return false;
32 }
33 
asComponentTable(SkBitmap *) const34 bool SkColorFilter::asComponentTable(SkBitmap*) const {
35     return false;
36 }
37 
38 #if SK_SUPPORT_GPU
asFragmentProcessor(GrContext *,const GrColorSpaceInfo &) const39 std::unique_ptr<GrFragmentProcessor> SkColorFilter::asFragmentProcessor(
40         GrContext*, const GrColorSpaceInfo&) const {
41     return nullptr;
42 }
43 #endif
44 
appendStages(SkRasterPipeline * p,SkColorSpace * dstCS,SkArenaAlloc * alloc,bool shaderIsOpaque) const45 void SkColorFilter::appendStages(SkRasterPipeline* p,
46                                  SkColorSpace* dstCS,
47                                  SkArenaAlloc* alloc,
48                                  bool shaderIsOpaque) const {
49     this->onAppendStages(p, dstCS, alloc, shaderIsOpaque);
50 }
51 
filterColor(SkColor c) const52 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"
filterColor4f(const SkColor4f & c) const67 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:
getFlags() const96     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
toString(SkString * str) const102     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 
onAppendStages(SkRasterPipeline * p,SkColorSpace * dst,SkArenaAlloc * scratch,bool shaderIsOpaque) const112     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
asFragmentProcessor(GrContext * context,const GrColorSpaceInfo & dstColorSpaceInfo) const123     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:
flatten(SkWriteBuffer & buffer) const138     void flatten(SkWriteBuffer& buffer) const override {
139         buffer.writeFlattenable(fOuter.get());
140         buffer.writeFlattenable(fInner.get());
141     }
142 
143 private:
SkComposeColorFilter(sk_sp<SkColorFilter> outer,sk_sp<SkColorFilter> inner,int composedFilterCount)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 
privateComposedFilterCount() const154     int privateComposedFilterCount() const override {
155         return fComposedFilterCount;
156     }
157 
onMakeColorSpace(SkColorSpaceXformer * xformer) const158     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 outer->makeComposed(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 
CreateProc(SkReadBuffer & buffer)176 sk_sp<SkFlattenable> SkComposeColorFilter::CreateProc(SkReadBuffer& buffer) {
177     sk_sp<SkColorFilter> outer(buffer.readColorFilter());
178     sk_sp<SkColorFilter> inner(buffer.readColorFilter());
179     return outer ? outer->makeComposed(std::move(inner)) : inner;
180 }
181 
182 
makeComposed(sk_sp<SkColorFilter> inner) const183 sk_sp<SkColorFilter> SkColorFilter::makeComposed(sk_sp<SkColorFilter> inner) const {
184     if (!inner) {
185         return sk_ref_sp(this);
186     }
187 
188     // Give the subclass a shot at a more optimal composition...
189     auto composition = this->onMakeComposed(inner);
190     if (composition) {
191         return composition;
192     }
193 
194     int count = inner->privateComposedFilterCount() + this->privateComposedFilterCount();
195     if (count > SK_MAX_COMPOSE_COLORFILTER_COUNT) {
196         return nullptr;
197     }
198     return sk_sp<SkColorFilter>(new SkComposeColorFilter(sk_ref_sp(this), std::move(inner), count));
199 }
200 
201 ///////////////////////////////////////////////////////////////////////////////////////////////////
202 
203 #if SK_SUPPORT_GPU
204 #include "../gpu/effects/GrSRGBEffect.h"
205 #endif
206 
207 class SkSRGBGammaColorFilter : public SkColorFilter {
208 public:
209     enum class Direction {
210         kLinearToSRGB,
211         kSRGBToLinear,
212     };
SkSRGBGammaColorFilter(Direction dir)213     SkSRGBGammaColorFilter(Direction dir) : fDir(dir) {}
214 
215 #if SK_SUPPORT_GPU
asFragmentProcessor(GrContext *,const GrColorSpaceInfo &) const216     std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
217             GrContext*, const GrColorSpaceInfo&) const override {
218         // wish our caller would let us know if our input was opaque...
219         GrSRGBEffect::Alpha alpha = GrSRGBEffect::Alpha::kPremul;
220         switch (fDir) {
221             case Direction::kLinearToSRGB:
222                 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kLinearToSRGB, alpha);
223             case Direction::kSRGBToLinear:
224                 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear, alpha);
225         }
226         return nullptr;
227     }
228 #endif
229 
230     SK_TO_STRING_OVERRIDE()
231 
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSRGBGammaColorFilter)232     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSRGBGammaColorFilter)
233 
234     void onAppendStages(SkRasterPipeline* p, SkColorSpace*, SkArenaAlloc* alloc,
235                         bool shaderIsOpaque) const override {
236         if (!shaderIsOpaque) {
237             p->append(SkRasterPipeline::unpremul);
238         }
239         switch (fDir) {
240             case Direction::kLinearToSRGB:
241                 p->append(SkRasterPipeline::to_srgb);
242                 break;
243             case Direction::kSRGBToLinear:
244                 p->append(SkRasterPipeline::from_srgb);
245                 break;
246         }
247         if (!shaderIsOpaque) {
248             p->append(SkRasterPipeline::premul);
249         }
250     }
251 
252 protected:
flatten(SkWriteBuffer & buffer) const253     void flatten(SkWriteBuffer& buffer) const override {
254         buffer.write32(static_cast<uint32_t>(fDir));
255     }
256 
257 private:
258     const Direction fDir;
259 
260     friend class SkColorFilter;
261     typedef SkColorFilter INHERITED;
262 };
263 
CreateProc(SkReadBuffer & buffer)264 sk_sp<SkFlattenable> SkSRGBGammaColorFilter::CreateProc(SkReadBuffer& buffer) {
265     uint32_t dir = buffer.read32();
266     if (dir <= 1) {
267         return sk_sp<SkFlattenable>(new SkSRGBGammaColorFilter(static_cast<Direction>(dir)));
268     }
269     buffer.validate(false);
270     return nullptr;
271 }
272 
273 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const274 void SkSRGBGammaColorFilter::toString(SkString* str) const {
275     str->append("srgbgamma");
276 }
277 #endif
278 
279 template <SkSRGBGammaColorFilter::Direction dir>
MakeSRGBGammaCF()280 sk_sp<SkColorFilter> MakeSRGBGammaCF() {
281     static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir);
282     return sk_ref_sp(gSingleton);
283 }
284 
MakeLinearToSRGBGamma()285 sk_sp<SkColorFilter> SkColorFilter::MakeLinearToSRGBGamma() {
286     return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kLinearToSRGB>();
287 }
288 
MakeSRGBToLinearGamma()289 sk_sp<SkColorFilter> SkColorFilter::MakeSRGBToLinearGamma() {
290     return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kSRGBToLinear>();
291 }
292 
293 ///////////////////////////////////////////////////////////////////////////////////////////////////
294 
295 #include "SkModeColorFilter.h"
296 
297 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter)
298 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeColorFilter)
299 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter)
300 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSRGBGammaColorFilter)
301 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
302