Coverage Report

Created: 2021-08-22 09:07

/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
}