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