xref: /aosp_15_r20/external/skia/src/shaders/SkWorkingColorSpaceShader.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/shaders/SkWorkingColorSpaceShader.h"
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkData.h"
14 #include "include/core/SkImageInfo.h"
15 #include "src/base/SkArenaAlloc.h"
16 #include "src/core/SkColorSpaceXformSteps.h"
17 #include "src/core/SkEffectPriv.h"
18 #include "src/core/SkReadBuffer.h"
19 #include "src/core/SkWriteBuffer.h"
20 #include "src/shaders/SkShaderBase.h"
21 
22 #include <utility>
23 
appendStages(const SkStageRec & rec,const SkShaders::MatrixRec & mRec) const24 bool SkWorkingColorSpaceShader::appendStages(const SkStageRec& rec,
25                                              const SkShaders::MatrixRec& mRec) const {
26     sk_sp<SkColorSpace> dstCS = sk_ref_sp(rec.fDstCS);
27     if (!dstCS) {
28         dstCS = SkColorSpace::MakeSRGB();
29     }
30 
31     SkColorInfo dst     = {rec.fDstColorType, kPremul_SkAlphaType, dstCS},
32                 working = {rec.fDstColorType, kPremul_SkAlphaType, fWorkingSpace};
33 
34     const auto* dstToWorking = rec.fAlloc->make<SkColorSpaceXformSteps>(dst, working);
35     const auto* workingToDst = rec.fAlloc->make<SkColorSpaceXformSteps>(working, dst);
36 
37     // Alpha-only image shaders reference the paint color, which is already in the destination
38     // color space. We need to transform it to the working space for consistency.
39     SkColor4f paintColorInWorkingSpace = rec.fPaintColor.makeOpaque();
40     dstToWorking->apply(paintColorInWorkingSpace.vec());
41 
42     SkStageRec workingRec = {rec.fPipeline,
43                              rec.fAlloc,
44                              rec.fDstColorType,
45                              fWorkingSpace.get(),
46                              paintColorInWorkingSpace,
47                              rec.fSurfaceProps};
48 
49     if (!as_SB(fShader)->appendStages(workingRec, mRec)) {
50         return false;
51     }
52 
53     workingToDst->apply(rec.fPipeline);
54     return true;
55 }
56 
flatten(SkWriteBuffer & buffer) const57 void SkWorkingColorSpaceShader::flatten(SkWriteBuffer& buffer) const {
58     buffer.writeFlattenable(fShader.get());
59     buffer.writeDataAsByteArray(fWorkingSpace->serialize().get());
60 }
61 
CreateProc(SkReadBuffer & buffer)62 sk_sp<SkFlattenable> SkWorkingColorSpaceShader::CreateProc(SkReadBuffer& buffer) {
63     sk_sp<SkShader> shader(buffer.readShader());
64     auto data = buffer.readByteArrayAsData();
65     if (!buffer.validate(data != nullptr)) {
66         return nullptr;
67     }
68     sk_sp<SkColorSpace> workingSpace = SkColorSpace::Deserialize(data->data(), data->size());
69     if (!buffer.validate(workingSpace != nullptr)) {
70         return nullptr;
71     }
72     return Make(std::move(shader), std::move(workingSpace));
73 }
74 
SkRegisterWorkingColorSpaceShaderFlattenable()75 void SkRegisterWorkingColorSpaceShaderFlattenable() {
76     SK_REGISTER_FLATTENABLE(SkWorkingColorSpaceShader);
77 }
78