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