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 *,SkColorSpace *) const39 sk_sp<GrFragmentProcessor> SkColorFilter::asFragmentProcessor(GrContext*, SkColorSpace*) const {
40 return nullptr;
41 }
42 #endif
43
appendStages(SkRasterPipeline * p,SkColorSpace * dstCS,SkArenaAlloc * alloc,bool shaderIsOpaque) const44 void SkColorFilter::appendStages(SkRasterPipeline* p,
45 SkColorSpace* dstCS,
46 SkArenaAlloc* alloc,
47 bool shaderIsOpaque) const {
48 this->onAppendStages(p, dstCS, alloc, shaderIsOpaque);
49 }
50
filterColor(SkColor c) const51 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"
filterColor4f(const SkColor4f & c) const66 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:
getFlags() const95 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
toString(SkString * str) const101 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
onAppendStages(SkRasterPipeline * p,SkColorSpace * dst,SkArenaAlloc * scratch,bool shaderIsOpaque) const111 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
asFragmentProcessor(GrContext * context,SkColorSpace * dstColorSpace) const122 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:
flatten(SkWriteBuffer & buffer) const137 void flatten(SkWriteBuffer& buffer) const override {
138 buffer.writeFlattenable(fOuter.get());
139 buffer.writeFlattenable(fInner.get());
140 }
141
142 private:
SkComposeColorFilter(sk_sp<SkColorFilter> outer,sk_sp<SkColorFilter> inner,int composedFilterCount)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
privateComposedFilterCount() const153 int privateComposedFilterCount() const override {
154 return fComposedFilterCount;
155 }
156
onMakeColorSpace(SkColorSpaceXformer * xformer) const157 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
CreateProc(SkReadBuffer & buffer)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
MakeComposeFilter(sk_sp<SkColorFilter> outer,sk_sp<SkColorFilter> inner)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 };
SkSRGBGammaColorFilter(Direction dir)215 SkSRGBGammaColorFilter(Direction dir) : fDir(dir) {}
216
217 #if SK_SUPPORT_GPU
asFragmentProcessor(GrContext * x,SkColorSpace * cs) const218 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
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSRGBGammaColorFilter)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:
flatten(SkWriteBuffer & buffer) const254 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
CreateProc(SkReadBuffer & buffer)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
toString(SkString * str) const275 void SkSRGBGammaColorFilter::toString(SkString* str) const {
276 str->append("srgbgamma");
277 }
278 #endif
279
280 template <SkSRGBGammaColorFilter::Direction dir>
MakeSRGBGammaCF()281 sk_sp<SkColorFilter> MakeSRGBGammaCF() {
282 static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir);
283 return sk_ref_sp(gSingleton);
284 }
285
MakeLinearToSRGBGamma()286 sk_sp<SkColorFilter> SkColorFilter::MakeLinearToSRGBGamma() {
287 return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kLinearToSRGB>();
288 }
289
MakeSRGBToLinearGamma()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