• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 Google LLC
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 "src/effects/colorfilters/SkWorkingFormatColorFilter.h"
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkColorType.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/private/base/SkAssert.h"
16 #include "modules/skcms/skcms.h"
17 #include "src/base/SkArenaAlloc.h"
18 #include "src/core/SkColorFilterPriv.h"
19 #include "src/core/SkColorSpaceXformSteps.h"
20 #include "src/core/SkEffectPriv.h"
21 #include "src/core/SkReadBuffer.h"
22 #include "src/core/SkWriteBuffer.h"
23 #include "src/effects/colorfilters/SkColorFilterBase.h"
24 
25 #include <utility>
26 
SkWorkingFormatColorFilter(sk_sp<SkColorFilter> child,const skcms_TransferFunction * tf,const skcms_Matrix3x3 * gamut,const SkAlphaType * at)27 SkWorkingFormatColorFilter::SkWorkingFormatColorFilter(sk_sp<SkColorFilter> child,
28                                                        const skcms_TransferFunction* tf,
29                                                        const skcms_Matrix3x3* gamut,
30                                                        const SkAlphaType* at) {
31     fChild = std::move(child);
32     if (tf) {
33         fTF = *tf;
34         fUseDstTF = false;
35     }
36     if (gamut) {
37         fGamut = *gamut;
38         fUseDstGamut = false;
39     }
40     if (at) {
41         fAT = *at;
42         fUseDstAT = false;
43     }
44 }
45 
workingFormat(const sk_sp<SkColorSpace> & dstCS,SkAlphaType * at) const46 sk_sp<SkColorSpace> SkWorkingFormatColorFilter::workingFormat(const sk_sp<SkColorSpace>& dstCS,
47                                                               SkAlphaType* at) const {
48     skcms_TransferFunction tf = fTF;
49     skcms_Matrix3x3 gamut = fGamut;
50 
51     if (fUseDstTF) {
52         SkAssertResult(dstCS->isNumericalTransferFn(&tf));
53     }
54     if (fUseDstGamut) {
55         SkAssertResult(dstCS->toXYZD50(&gamut));
56     }
57 
58     *at = fUseDstAT ? kPremul_SkAlphaType : fAT;
59     return SkColorSpace::MakeRGB(tf, gamut);
60 }
61 
appendStages(const SkStageRec & rec,bool shaderIsOpaque) const62 bool SkWorkingFormatColorFilter::appendStages(const SkStageRec& rec, bool shaderIsOpaque) const {
63     sk_sp<SkColorSpace> dstCS = sk_ref_sp(rec.fDstCS);
64 
65     if (!dstCS) {
66         dstCS = SkColorSpace::MakeSRGB();
67     }
68 
69     SkAlphaType workingAT;
70     sk_sp<SkColorSpace> workingCS = this->workingFormat(dstCS, &workingAT);
71 
72     SkColorInfo dst = {rec.fDstColorType, kPremul_SkAlphaType, dstCS},
73                 working = {rec.fDstColorType, workingAT, workingCS};
74 
75     const auto* dstToWorking = rec.fAlloc->make<SkColorSpaceXformSteps>(dst, working);
76     const auto* workingToDst = rec.fAlloc->make<SkColorSpaceXformSteps>(working, dst);
77 
78     // The paint color is in the destination color space, so *should* be coverted to working space.
79     // That's not necessary, though:
80     //   - Tinting alpha-only image shaders is the only effect that uses paint-color
81     //   - Alpha-only image shaders can't be reached from color-filters without SkSL
82     //   - SkSL disables paint-color tinting of alpha-only image shaders
83 
84     SkStageRec workingRec = {rec.fPipeline,
85                              rec.fAlloc,
86                              rec.fDstColorType,
87                              workingCS.get(),
88                              rec.fPaintColor,
89                              rec.fSurfaceProps};
90 
91     dstToWorking->apply(rec.fPipeline);
92     if (!as_CFB(fChild)->appendStages(workingRec, shaderIsOpaque)) {
93         return false;
94     }
95     workingToDst->apply(rec.fPipeline);
96     return true;
97 }
98 
onFilterColor4f(const SkPMColor4f & origColor,SkColorSpace * rawDstCS) const99 SkPMColor4f SkWorkingFormatColorFilter::onFilterColor4f(const SkPMColor4f& origColor,
100                                                         SkColorSpace* rawDstCS) const {
101     sk_sp<SkColorSpace> dstCS = sk_ref_sp(rawDstCS);
102     if (!dstCS) {
103         dstCS = SkColorSpace::MakeSRGB();
104     }
105 
106     SkAlphaType workingAT;
107     sk_sp<SkColorSpace> workingCS = this->workingFormat(dstCS, &workingAT);
108 
109     SkColorInfo dst = {kUnknown_SkColorType, kPremul_SkAlphaType, dstCS},
110                 working = {kUnknown_SkColorType, workingAT, workingCS};
111 
112     SkPMColor4f color = origColor;
113     SkColorSpaceXformSteps{dst, working}.apply(color.vec());
114     color = as_CFB(fChild)->onFilterColor4f(color, working.colorSpace());
115     SkColorSpaceXformSteps{working, dst}.apply(color.vec());
116     return color;
117 }
118 
onIsAlphaUnchanged() const119 bool SkWorkingFormatColorFilter::onIsAlphaUnchanged() const { return fChild->isAlphaUnchanged(); }
120 
flatten(SkWriteBuffer & buffer) const121 void SkWorkingFormatColorFilter::flatten(SkWriteBuffer& buffer) const {
122     buffer.writeFlattenable(fChild.get());
123     buffer.writeBool(fUseDstTF);
124     buffer.writeBool(fUseDstGamut);
125     buffer.writeBool(fUseDstAT);
126     if (!fUseDstTF) {
127         buffer.writeScalarArray(&fTF.g, 7);
128     }
129     if (!fUseDstGamut) {
130         buffer.writeScalarArray(&fGamut.vals[0][0], 9);
131     }
132     if (!fUseDstAT) {
133         buffer.writeInt(fAT);
134     }
135 }
136 
CreateProc(SkReadBuffer & buffer)137 sk_sp<SkFlattenable> SkWorkingFormatColorFilter::CreateProc(SkReadBuffer& buffer) {
138     sk_sp<SkColorFilter> child = buffer.readColorFilter();
139     bool useDstTF = buffer.readBool(), useDstGamut = buffer.readBool(),
140          useDstAT = buffer.readBool();
141 
142     skcms_TransferFunction tf;
143     skcms_Matrix3x3 gamut;
144     SkAlphaType at;
145 
146     if (!useDstTF) {
147         buffer.readScalarArray(&tf.g, 7);
148     }
149     if (!useDstGamut) {
150         buffer.readScalarArray(&gamut.vals[0][0], 9);
151     }
152     if (!useDstAT) {
153         at = buffer.read32LE(kLastEnum_SkAlphaType);
154     }
155 
156     return SkColorFilterPriv::WithWorkingFormat(std::move(child),
157                                                 useDstTF ? nullptr : &tf,
158                                                 useDstGamut ? nullptr : &gamut,
159                                                 useDstAT ? nullptr : &at);
160 }
161 
WithWorkingFormat(sk_sp<SkColorFilter> child,const skcms_TransferFunction * tf,const skcms_Matrix3x3 * gamut,const SkAlphaType * at)162 sk_sp<SkColorFilter> SkColorFilterPriv::WithWorkingFormat(sk_sp<SkColorFilter> child,
163                                                           const skcms_TransferFunction* tf,
164                                                           const skcms_Matrix3x3* gamut,
165                                                           const SkAlphaType* at) {
166     return sk_make_sp<SkWorkingFormatColorFilter>(std::move(child), tf, gamut, at);
167 }
168 
SkRegisterWorkingFormatColorFilterFlattenable()169 void SkRegisterWorkingFormatColorFilterFlattenable() {
170     SK_REGISTER_FLATTENABLE(SkWorkingFormatColorFilter);
171 }
172