/src/skia/src/core/SkColorFilter.cpp
Line | Count | Source (jump to first uncovered line) |
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 "include/core/SkRefCnt.h" |
9 | | #include "include/core/SkString.h" |
10 | | #include "include/core/SkUnPreMultiply.h" |
11 | | #include "include/effects/SkRuntimeEffect.h" |
12 | | #include "include/private/SkNx.h" |
13 | | #include "include/private/SkTDArray.h" |
14 | | #include "src/core/SkArenaAlloc.h" |
15 | | #include "src/core/SkColorFilterBase.h" |
16 | | #include "src/core/SkColorSpacePriv.h" |
17 | | #include "src/core/SkColorSpaceXformSteps.h" |
18 | | #include "src/core/SkMatrixProvider.h" |
19 | | #include "src/core/SkRasterPipeline.h" |
20 | | #include "src/core/SkReadBuffer.h" |
21 | | #include "src/core/SkRuntimeEffectPriv.h" |
22 | | #include "src/core/SkVM.h" |
23 | | #include "src/core/SkWriteBuffer.h" |
24 | | |
25 | | #if SK_SUPPORT_GPU |
26 | | #include "src/gpu/GrColorInfo.h" |
27 | | #include "src/gpu/GrColorSpaceXform.h" |
28 | | #include "src/gpu/GrFragmentProcessor.h" |
29 | | #endif |
30 | | |
31 | 1.58k | bool SkColorFilter::asAColorMode(SkColor* color, SkBlendMode* mode) const { |
32 | 1.58k | return as_CFB(this)->onAsAColorMode(color, mode); |
33 | 1.58k | } |
34 | | |
35 | 0 | bool SkColorFilter::asAColorMatrix(float matrix[20]) const { |
36 | 0 | return as_CFB(this)->onAsAColorMatrix(matrix); |
37 | 0 | } |
38 | | |
39 | 955k | bool SkColorFilter::isAlphaUnchanged() const { |
40 | 955k | return as_CFB(this)->onIsAlphaUnchanged(); |
41 | 955k | } |
42 | | |
43 | | sk_sp<SkColorFilter> SkColorFilter::Deserialize(const void* data, size_t size, |
44 | 0 | const SkDeserialProcs* procs) { |
45 | 0 | return sk_sp<SkColorFilter>(static_cast<SkColorFilter*>( |
46 | 0 | SkFlattenable::Deserialize( |
47 | 0 | kSkColorFilter_Type, data, size, procs).release())); |
48 | 0 | } |
49 | | |
50 | | ////////////////////////////////////////////////////////////////////////////////////////////////// |
51 | | |
52 | 1.54k | bool SkColorFilterBase::onAsAColorMode(SkColor*, SkBlendMode*) const { |
53 | 1.54k | return false; |
54 | 1.54k | } |
55 | | |
56 | 0 | bool SkColorFilterBase::onAsAColorMatrix(float matrix[20]) const { |
57 | 0 | return false; |
58 | 0 | } |
59 | | |
60 | | #if SK_SUPPORT_GPU |
61 | | GrFPResult SkColorFilterBase::asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP, |
62 | | GrRecordingContext* context, |
63 | 0 | const GrColorInfo& dstColorInfo) const { |
64 | | // This color filter doesn't implement `asFragmentProcessor`. |
65 | 0 | return GrFPFailure(std::move(inputFP)); |
66 | 0 | } |
67 | | #endif |
68 | | |
69 | 212k | bool SkColorFilterBase::appendStages(const SkStageRec& rec, bool shaderIsOpaque) const { |
70 | 212k | return this->onAppendStages(rec, shaderIsOpaque); |
71 | 212k | } |
72 | | |
73 | | skvm::Color SkColorFilterBase::program(skvm::Builder* p, skvm::Color c, |
74 | | const SkColorInfo& dst, |
75 | 189k | skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { |
76 | 189k | skvm::F32 original = c.a; |
77 | 189k | if ((c = this->onProgram(p,c, dst, uniforms,alloc))) { |
78 | 189k | if (this->isAlphaUnchanged()) { |
79 | 98.5k | c.a = original; |
80 | 98.5k | } |
81 | 189k | return c; |
82 | 189k | } |
83 | | //SkDebugf("cannot onProgram %s\n", this->getTypeName()); |
84 | 0 | return {}; |
85 | 0 | } |
86 | | |
87 | 65.1k | SkColor SkColorFilter::filterColor(SkColor c) const { |
88 | | // This is mostly meaningless. We should phase-out this call entirely. |
89 | 65.1k | SkColorSpace* cs = nullptr; |
90 | 65.1k | return this->filterColor4f(SkColor4f::FromColor(c), cs, cs).toSkColor(); |
91 | 65.1k | } |
92 | | |
93 | | SkColor4f SkColorFilter::filterColor4f(const SkColor4f& origSrcColor, SkColorSpace* srcCS, |
94 | 76.2k | SkColorSpace* dstCS) const { |
95 | 76.2k | SkPMColor4f color = { origSrcColor.fR, origSrcColor.fG, origSrcColor.fB, origSrcColor.fA }; |
96 | 76.2k | SkColorSpaceXformSteps(srcCS, kUnpremul_SkAlphaType, |
97 | 76.2k | dstCS, kPremul_SkAlphaType).apply(color.vec()); |
98 | | |
99 | 76.2k | return as_CFB(this)->onFilterColor4f(color, dstCS).unpremul(); |
100 | 76.2k | } |
101 | | |
102 | | SkPMColor4f SkColorFilterBase::onFilterColor4f(const SkPMColor4f& color, |
103 | 69.2k | SkColorSpace* dstCS) const { |
104 | 69.2k | constexpr size_t kEnoughForCommonFilters = 512; // big enough for compose+colormatrix |
105 | 69.2k | SkSTArenaAlloc<kEnoughForCommonFilters> alloc; |
106 | 69.2k | SkRasterPipeline pipeline(&alloc); |
107 | 69.2k | pipeline.append_constant_color(&alloc, color.vec()); |
108 | 69.2k | SkPaint blankPaint; |
109 | 69.2k | SkSimpleMatrixProvider matrixProvider(SkMatrix::I()); |
110 | 69.2k | SkStageRec rec = { |
111 | 69.2k | &pipeline, &alloc, kRGBA_F32_SkColorType, dstCS, blankPaint, nullptr, matrixProvider |
112 | 69.2k | }; |
113 | | |
114 | 69.2k | if (as_CFB(this)->onAppendStages(rec, color.fA == 1)) { |
115 | 46.4k | SkPMColor4f dst; |
116 | 46.4k | SkRasterPipeline_MemoryCtx dstPtr = { &dst, 0 }; |
117 | 46.4k | pipeline.append(SkRasterPipeline::store_f32, &dstPtr); |
118 | 46.4k | pipeline.run(0,0, 1,1); |
119 | 46.4k | return dst; |
120 | 46.4k | } |
121 | | |
122 | | // This filter doesn't support SkRasterPipeline... try skvm. |
123 | 22.7k | skvm::Builder b; |
124 | 22.7k | skvm::Uniforms uni(b.uniform(), 4); |
125 | 22.7k | SkColor4f uniColor = {color.fR, color.fG, color.fB, color.fA}; |
126 | 22.7k | SkColorInfo dstInfo = {kRGBA_F32_SkColorType, kPremul_SkAlphaType, sk_ref_sp(dstCS)}; |
127 | 22.7k | if (skvm::Color filtered = |
128 | 22.7k | as_CFB(this)->program(&b, b.uniformColor(uniColor, &uni), dstInfo, &uni, &alloc)) { |
129 | | |
130 | 22.7k | b.store({skvm::PixelFormat::FLOAT, 32,32,32,32, 0,32,64,96}, |
131 | 22.7k | b.varying<SkColor4f>(), filtered); |
132 | | |
133 | 22.7k | const bool allow_jit = false; // We're only filtering one color, no point JITing. |
134 | 22.7k | b.done("filterColor4f", allow_jit).eval(1, uni.buf.data(), &color); |
135 | 22.7k | return color; |
136 | 22.7k | } |
137 | | |
138 | 0 | SkASSERT(false); |
139 | 0 | return SkPMColor4f{0,0,0,0}; |
140 | 0 | } |
141 | | |
142 | | /////////////////////////////////////////////////////////////////////////////////////////////////// |
143 | | |
144 | | class SkComposeColorFilter : public SkColorFilterBase { |
145 | | public: |
146 | 241k | bool onIsAlphaUnchanged() const override { |
147 | | // Can only claim alphaunchanged support if both our proxys do. |
148 | 241k | return fOuter->isAlphaUnchanged() & fInner->isAlphaUnchanged(); |
149 | 241k | } |
150 | | |
151 | 75.4k | bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override { |
152 | 75.4k | bool innerIsOpaque = shaderIsOpaque; |
153 | 75.4k | if (!fInner->isAlphaUnchanged()) { |
154 | 55.1k | innerIsOpaque = false; |
155 | 55.1k | } |
156 | 75.4k | return fInner->appendStages(rec, shaderIsOpaque) && |
157 | 25.4k | fOuter->appendStages(rec, innerIsOpaque); |
158 | 75.4k | } |
159 | | |
160 | | skvm::Color onProgram(skvm::Builder* p, skvm::Color c, |
161 | | const SkColorInfo& dst, |
162 | 61.5k | skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override { |
163 | 61.5k | c = fInner->program(p, c, dst, uniforms, alloc); |
164 | 61.5k | return c ? fOuter->program(p, c, dst, uniforms, alloc) : skvm::Color{}; |
165 | 61.5k | } |
166 | | |
167 | | #if SK_SUPPORT_GPU |
168 | | GrFPResult asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP, |
169 | | GrRecordingContext* context, |
170 | 10 | const GrColorInfo& dstColorInfo) const override { |
171 | 10 | GrFragmentProcessor* originalInputFP = inputFP.get(); |
172 | | |
173 | 10 | auto [innerSuccess, innerFP] = |
174 | 10 | fInner->asFragmentProcessor(std::move(inputFP), context, dstColorInfo); |
175 | 10 | if (!innerSuccess) { |
176 | 0 | return GrFPFailure(std::move(innerFP)); |
177 | 0 | } |
178 | | |
179 | 10 | auto [outerSuccess, outerFP] = |
180 | 10 | fOuter->asFragmentProcessor(std::move(innerFP), context, dstColorInfo); |
181 | 10 | if (!outerSuccess) { |
182 | | // In the rare event that the outer FP cannot be built, we have no good way of |
183 | | // separating the inputFP from the innerFP, so we need to return a cloned inputFP. |
184 | | // This could hypothetically be expensive, but failure here should be extremely rare. |
185 | 0 | return GrFPFailure(originalInputFP->clone()); |
186 | 0 | } |
187 | | |
188 | 10 | return GrFPSuccess(std::move(outerFP)); |
189 | 10 | } |
190 | | #endif |
191 | | |
192 | | SK_FLATTENABLE_HOOKS(SkComposeColorFilter) |
193 | | |
194 | | protected: |
195 | 0 | void flatten(SkWriteBuffer& buffer) const override { |
196 | 0 | buffer.writeFlattenable(fOuter.get()); |
197 | 0 | buffer.writeFlattenable(fInner.get()); |
198 | 0 | } |
199 | | |
200 | | private: |
201 | | SkComposeColorFilter(sk_sp<SkColorFilter> outer, sk_sp<SkColorFilter> inner) |
202 | | : fOuter(as_CFB_sp(std::move(outer))) |
203 | | , fInner(as_CFB_sp(std::move(inner))) |
204 | 52.9k | {} |
205 | | |
206 | | sk_sp<SkColorFilterBase> fOuter; |
207 | | sk_sp<SkColorFilterBase> fInner; |
208 | | |
209 | | friend class SkColorFilter; |
210 | | |
211 | | using INHERITED = SkColorFilter; |
212 | | }; |
213 | | |
214 | 4 | sk_sp<SkFlattenable> SkComposeColorFilter::CreateProc(SkReadBuffer& buffer) { |
215 | 4 | sk_sp<SkColorFilter> outer(buffer.readColorFilter()); |
216 | 4 | sk_sp<SkColorFilter> inner(buffer.readColorFilter()); |
217 | 4 | return outer ? outer->makeComposed(std::move(inner)) : inner; |
218 | 4 | } |
219 | | |
220 | 58.2k | sk_sp<SkColorFilter> SkColorFilter::makeComposed(sk_sp<SkColorFilter> inner) const { |
221 | 58.2k | if (!inner) { |
222 | 5.29k | return sk_ref_sp(this); |
223 | 5.29k | } |
224 | | |
225 | 52.9k | return sk_sp<SkColorFilter>(new SkComposeColorFilter(sk_ref_sp(this), std::move(inner))); |
226 | 52.9k | } |
227 | | |
228 | | /////////////////////////////////////////////////////////////////////////////////////////////////// |
229 | | |
230 | | class SkSRGBGammaColorFilter : public SkColorFilterBase { |
231 | | public: |
232 | | enum class Direction { |
233 | | kLinearToSRGB, |
234 | | kSRGBToLinear, |
235 | | }; |
236 | 2 | SkSRGBGammaColorFilter(Direction dir) : fDir(dir), fSteps([&]{ |
237 | | // We handle premul/unpremul separately, so here just always upm->upm. |
238 | 2 | if (dir == Direction::kLinearToSRGB) { |
239 | 1 | return SkColorSpaceXformSteps{sk_srgb_linear_singleton(), kUnpremul_SkAlphaType, |
240 | 1 | sk_srgb_singleton(), kUnpremul_SkAlphaType}; |
241 | 1 | } else { |
242 | 1 | return SkColorSpaceXformSteps{sk_srgb_singleton(), kUnpremul_SkAlphaType, |
243 | 1 | sk_srgb_linear_singleton(), kUnpremul_SkAlphaType}; |
244 | 1 | } |
245 | 2 | }()) {} |
246 | | |
247 | | #if SK_SUPPORT_GPU |
248 | | GrFPResult asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP, |
249 | | GrRecordingContext* context, |
250 | 0 | const GrColorInfo& dstColorInfo) const override { |
251 | | // wish our caller would let us know if our input was opaque... |
252 | 0 | constexpr SkAlphaType alphaType = kPremul_SkAlphaType; |
253 | 0 | switch (fDir) { |
254 | 0 | case Direction::kLinearToSRGB: |
255 | 0 | return GrFPSuccess(GrColorSpaceXformEffect::Make( |
256 | 0 | std::move(inputFP), |
257 | 0 | sk_srgb_linear_singleton(), alphaType, |
258 | 0 | sk_srgb_singleton(), alphaType)); |
259 | 0 | case Direction::kSRGBToLinear: |
260 | 0 | return GrFPSuccess(GrColorSpaceXformEffect::Make( |
261 | 0 | std::move(inputFP), |
262 | 0 | sk_srgb_singleton(), alphaType, |
263 | 0 | sk_srgb_linear_singleton(), alphaType)); |
264 | 0 | } |
265 | 0 | SkUNREACHABLE; |
266 | 0 | } |
267 | | #endif |
268 | | |
269 | 23.4k | bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override { |
270 | 23.4k | if (!shaderIsOpaque) { |
271 | 23.4k | rec.fPipeline->append(SkRasterPipeline::unpremul); |
272 | 23.4k | } |
273 | | |
274 | 23.4k | fSteps.apply(rec.fPipeline); |
275 | | |
276 | 23.4k | if (!shaderIsOpaque) { |
277 | 23.4k | rec.fPipeline->append(SkRasterPipeline::premul); |
278 | 23.4k | } |
279 | 23.4k | return true; |
280 | 23.4k | } |
281 | | |
282 | | skvm::Color onProgram(skvm::Builder* p, skvm::Color c, const SkColorInfo& dst, |
283 | 0 | skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override { |
284 | 0 | return premul(fSteps.program(p, uniforms, unpremul(c))); |
285 | 0 | } |
286 | | |
287 | | SK_FLATTENABLE_HOOKS(SkSRGBGammaColorFilter) |
288 | | |
289 | | protected: |
290 | 0 | void flatten(SkWriteBuffer& buffer) const override { |
291 | 0 | buffer.write32(static_cast<uint32_t>(fDir)); |
292 | 0 | } |
293 | | |
294 | | private: |
295 | | const Direction fDir; |
296 | | SkColorSpaceXformSteps fSteps; |
297 | | |
298 | | friend class SkColorFilter; |
299 | | using INHERITED = SkColorFilterBase; |
300 | | }; |
301 | | |
302 | 0 | sk_sp<SkFlattenable> SkSRGBGammaColorFilter::CreateProc(SkReadBuffer& buffer) { |
303 | 0 | uint32_t dir = buffer.read32(); |
304 | 0 | if (!buffer.validate(dir <= 1)) { |
305 | 0 | return nullptr; |
306 | 0 | } |
307 | 0 | return sk_sp<SkFlattenable>(new SkSRGBGammaColorFilter(static_cast<Direction>(dir))); |
308 | 0 | } |
309 | | |
310 | | template <SkSRGBGammaColorFilter::Direction dir> |
311 | 8.62k | sk_sp<SkColorFilter> MakeSRGBGammaCF() { |
312 | 8.62k | static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir); |
313 | 8.62k | return sk_ref_sp(gSingleton); |
314 | 8.62k | } sk_sp<SkColorFilter> MakeSRGBGammaCF<(SkSRGBGammaColorFilter::Direction)0>() Line | Count | Source | 311 | 2.16k | sk_sp<SkColorFilter> MakeSRGBGammaCF() { | 312 | 2.16k | static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir); | 313 | 2.16k | return sk_ref_sp(gSingleton); | 314 | 2.16k | } |
sk_sp<SkColorFilter> MakeSRGBGammaCF<(SkSRGBGammaColorFilter::Direction)1>() Line | Count | Source | 311 | 6.46k | sk_sp<SkColorFilter> MakeSRGBGammaCF() { | 312 | 6.46k | static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir); | 313 | 6.46k | return sk_ref_sp(gSingleton); | 314 | 6.46k | } |
|
315 | | |
316 | 2.16k | sk_sp<SkColorFilter> SkColorFilters::LinearToSRGBGamma() { |
317 | 2.16k | return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kLinearToSRGB>(); |
318 | 2.16k | } |
319 | | |
320 | 6.46k | sk_sp<SkColorFilter> SkColorFilters::SRGBToLinearGamma() { |
321 | 6.46k | return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kSRGBToLinear>(); |
322 | 6.46k | } |
323 | | |
324 | | struct SkWorkingFormatColorFilter : public SkColorFilterBase { |
325 | | sk_sp<SkColorFilter> fChild; |
326 | | skcms_TransferFunction fTF; bool fUseDstTF = true; |
327 | | skcms_Matrix3x3 fGamut; bool fUseDstGamut = true; |
328 | | SkAlphaType fAT; bool fUseDstAT = true; |
329 | | |
330 | | SkWorkingFormatColorFilter(sk_sp<SkColorFilter> child, |
331 | | const skcms_TransferFunction* tf, |
332 | | const skcms_Matrix3x3* gamut, |
333 | 35.8k | const SkAlphaType* at) { |
334 | 35.8k | fChild = std::move(child); |
335 | 35.8k | if (tf) { fTF = *tf; fUseDstTF = false; } |
336 | 35.8k | if (gamut) { fGamut = *gamut; fUseDstGamut = false; } |
337 | 35.8k | if (at) { fAT = *at; fUseDstAT = false; } |
338 | 35.8k | } |
339 | | |
340 | | |
341 | 48.4k | sk_sp<SkColorSpace> workingFormat(const sk_sp<SkColorSpace>& dstCS, SkAlphaType* at) const { |
342 | 48.4k | skcms_TransferFunction tf = fTF; |
343 | 48.4k | skcms_Matrix3x3 gamut = fGamut; |
344 | | |
345 | 48.4k | if (fUseDstTF ) { SkAssertResult(dstCS->isNumericalTransferFn(&tf)); } |
346 | 48.4k | if (fUseDstGamut) { SkAssertResult(dstCS->toXYZD50 (&gamut)); } |
347 | | |
348 | 48.4k | *at = fUseDstAT ? kPremul_SkAlphaType : fAT; |
349 | 48.4k | return SkColorSpace::MakeRGB(tf, gamut); |
350 | 48.4k | } |
351 | | |
352 | | #if SK_SUPPORT_GPU |
353 | | GrFPResult asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP, |
354 | | GrRecordingContext* context, |
355 | 167 | const GrColorInfo& dstColorInfo) const override { |
356 | 167 | sk_sp<SkColorSpace> dstCS = dstColorInfo.refColorSpace(); |
357 | 167 | if (!dstCS) { dstCS = SkColorSpace::MakeSRGB(); } |
358 | | |
359 | 167 | SkAlphaType workingAT; |
360 | 167 | sk_sp<SkColorSpace> workingCS = this->workingFormat(dstCS, &workingAT); |
361 | | |
362 | 167 | GrColorInfo dst = {dstColorInfo.colorType(), dstColorInfo.alphaType(), dstCS}, |
363 | 167 | working = {dstColorInfo.colorType(), workingAT, workingCS}; |
364 | | |
365 | 167 | auto [ok, fp] = as_CFB(fChild)->asFragmentProcessor( |
366 | 167 | GrColorSpaceXformEffect::Make(std::move(inputFP), dst,working), context, working); |
367 | | |
368 | 167 | return ok ? GrFPSuccess(GrColorSpaceXformEffect::Make(std::move(fp), working,dst)) |
369 | 0 | : GrFPFailure(std::move(fp)); |
370 | 167 | } |
371 | | #endif |
372 | | |
373 | 49.9k | bool onAppendStages(const SkStageRec&, bool) const override { return false; } |
374 | | |
375 | | skvm::Color onProgram(skvm::Builder* p, skvm::Color c, const SkColorInfo& rawDst, |
376 | 43.5k | skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override { |
377 | 43.5k | sk_sp<SkColorSpace> dstCS = rawDst.refColorSpace(); |
378 | 43.5k | if (!dstCS) { dstCS = SkColorSpace::MakeSRGB(); } |
379 | | |
380 | 43.5k | SkAlphaType workingAT; |
381 | 43.5k | sk_sp<SkColorSpace> workingCS = this->workingFormat(dstCS, &workingAT); |
382 | | |
383 | 43.5k | SkColorInfo dst = {rawDst.colorType(), kPremul_SkAlphaType, dstCS}, |
384 | 43.5k | working = {rawDst.colorType(), workingAT, workingCS}; |
385 | | |
386 | 43.5k | c = SkColorSpaceXformSteps{dst,working}.program(p, uniforms, c); |
387 | 43.5k | c = as_CFB(fChild)->program(p, c, working, uniforms, alloc); |
388 | 43.5k | return c ? SkColorSpaceXformSteps{working,dst}.program(p, uniforms, c) |
389 | 0 | : c; |
390 | 43.5k | } |
391 | | |
392 | | SkPMColor4f onFilterColor4f(const SkPMColor4f& origColor, |
393 | 4.70k | SkColorSpace* rawDstCS) const override { |
394 | 4.70k | sk_sp<SkColorSpace> dstCS = sk_ref_sp(rawDstCS); |
395 | 4.70k | if (!dstCS) { dstCS = SkColorSpace::MakeSRGB(); } |
396 | | |
397 | 4.70k | SkAlphaType workingAT; |
398 | 4.70k | sk_sp<SkColorSpace> workingCS = this->workingFormat(dstCS, &workingAT); |
399 | | |
400 | 4.70k | SkColorInfo dst = {kUnknown_SkColorType, kPremul_SkAlphaType, dstCS}, |
401 | 4.70k | working = {kUnknown_SkColorType, workingAT, workingCS}; |
402 | | |
403 | 4.70k | SkPMColor4f color = origColor; |
404 | 4.70k | SkColorSpaceXformSteps{dst,working}.apply(color.vec()); |
405 | 4.70k | color = as_CFB(fChild)->onFilterColor4f(color, working.colorSpace()); |
406 | 4.70k | SkColorSpaceXformSteps{working,dst}.apply(color.vec()); |
407 | 4.70k | return color; |
408 | 4.70k | } |
409 | | |
410 | 206k | bool onIsAlphaUnchanged() const override { return fChild->isAlphaUnchanged(); } |
411 | | |
412 | | SK_FLATTENABLE_HOOKS(SkWorkingFormatColorFilter) |
413 | 0 | void flatten(SkWriteBuffer& buffer) const override { |
414 | 0 | buffer.writeFlattenable(fChild.get()); |
415 | 0 | buffer.writeBool(fUseDstTF); |
416 | 0 | buffer.writeBool(fUseDstGamut); |
417 | 0 | buffer.writeBool(fUseDstAT); |
418 | 0 | if (!fUseDstTF) { buffer.writeScalarArray(&fTF.g, 7); } |
419 | 0 | if (!fUseDstGamut) { buffer.writeScalarArray(&fGamut.vals[0][0], 9); } |
420 | 0 | if (!fUseDstAT) { buffer.writeInt(fAT); } |
421 | 0 | } |
422 | | }; |
423 | | |
424 | 0 | sk_sp<SkFlattenable> SkWorkingFormatColorFilter::CreateProc(SkReadBuffer& buffer) { |
425 | 0 | sk_sp<SkColorFilter> child = buffer.readColorFilter(); |
426 | 0 | bool useDstTF = buffer.readBool(), |
427 | 0 | useDstGamut = buffer.readBool(), |
428 | 0 | useDstAT = buffer.readBool(); |
429 | |
|
430 | 0 | skcms_TransferFunction tf; |
431 | 0 | skcms_Matrix3x3 gamut; |
432 | 0 | SkAlphaType at; |
433 | |
|
434 | 0 | if (!useDstTF) { buffer.readScalarArray(&tf.g, 7); } |
435 | 0 | if (!useDstGamut) { buffer.readScalarArray(&gamut.vals[0][0], 9); } |
436 | 0 | if (!useDstAT) { at = buffer.read32LE(kLastEnum_SkAlphaType); } |
437 | |
|
438 | 0 | return SkColorFilters::WithWorkingFormat(std::move(child), |
439 | 0 | useDstTF ? nullptr : &tf, |
440 | 0 | useDstGamut ? nullptr : &gamut, |
441 | 0 | useDstAT ? nullptr : &at); |
442 | 0 | } |
443 | | |
444 | | sk_sp<SkColorFilter> SkColorFilters::WithWorkingFormat(sk_sp<SkColorFilter> child, |
445 | | const skcms_TransferFunction* tf, |
446 | | const skcms_Matrix3x3* gamut, |
447 | 35.8k | const SkAlphaType* at) { |
448 | 35.8k | return sk_make_sp<SkWorkingFormatColorFilter>(std::move(child), tf, gamut, at); |
449 | 35.8k | } |
450 | | |
451 | | /////////////////////////////////////////////////////////////////////////////////////////////////// |
452 | | |
453 | | sk_sp<SkColorFilter> SkColorFilters::Lerp(float weight, sk_sp<SkColorFilter> cf0, |
454 | 7.29k | sk_sp<SkColorFilter> cf1) { |
455 | 7.29k | #ifdef SK_ENABLE_SKSL |
456 | 7.29k | if (!cf0 && !cf1) { |
457 | 0 | return nullptr; |
458 | 0 | } |
459 | 7.29k | if (SkScalarIsNaN(weight)) { |
460 | 0 | return nullptr; |
461 | 0 | } |
462 | | |
463 | 7.29k | if (cf0 == cf1) { |
464 | 0 | return cf0; // or cf1 |
465 | 0 | } |
466 | | |
467 | 7.29k | if (weight <= 0) { |
468 | 0 | return cf0; |
469 | 0 | } |
470 | 7.29k | if (weight >= 1) { |
471 | 3.25k | return cf1; |
472 | 3.25k | } |
473 | | |
474 | 4.04k | sk_sp<SkRuntimeEffect> effect = SkMakeCachedRuntimeEffect( |
475 | 4.04k | SkRuntimeEffect::MakeForColorFilter, |
476 | 4.04k | "uniform colorFilter cf0;" |
477 | 4.04k | "uniform colorFilter cf1;" |
478 | 4.04k | "uniform half weight;" |
479 | 4.04k | "half4 main(half4 color) {" |
480 | 4.04k | "return mix(sample(cf0, color), sample(cf1, color), weight);" |
481 | 4.04k | "}" |
482 | 4.04k | ); |
483 | 4.04k | SkASSERT(effect); |
484 | | |
485 | 4.04k | sk_sp<SkColorFilter> inputs[] = {cf0,cf1}; |
486 | 4.04k | return effect->makeColorFilter(SkData::MakeWithCopy(&weight, sizeof(weight)), |
487 | 4.04k | inputs, SK_ARRAY_COUNT(inputs)); |
488 | | #else |
489 | | // TODO(skia:12197) |
490 | | return nullptr; |
491 | | #endif |
492 | 4.04k | } |
493 | | |
494 | | /////////////////////////////////////////////////////////////////////////////////////////////////// |
495 | | |
496 | | #include "src/core/SkModeColorFilter.h" |
497 | | |
498 | 3 | void SkColorFilterBase::RegisterFlattenables() { |
499 | 3 | SK_REGISTER_FLATTENABLE(SkComposeColorFilter); |
500 | 3 | SK_REGISTER_FLATTENABLE(SkModeColorFilter); |
501 | 3 | SK_REGISTER_FLATTENABLE(SkSRGBGammaColorFilter); |
502 | 3 | SK_REGISTER_FLATTENABLE(SkWorkingFormatColorFilter); |
503 | 3 | } |