blob: 354337ebf0c3ea7329e3f64d42215e4a6252fa02 [file] [log] [blame]
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +00001/*
2 * Copyright 2014 Google Inc.
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/core/SkTLazy.h"
9#include "src/shaders/SkLocalMatrixShader.h"
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000010
bungeman06ca8ec2016-06-09 08:01:03 -070011#if SK_SUPPORT_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/gpu/GrFragmentProcessor.h"
bungeman06ca8ec2016-06-09 08:01:03 -070013#endif
14
15#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -040016std::unique_ptr<GrFragmentProcessor> SkLocalMatrixShader::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -050017 const GrFPArgs& args) const {
Florin Malitac6c5ead2018-04-11 15:33:40 -040018 return as_SB(fProxyShader)->asFragmentProcessor(
19 GrFPArgs::WithPreLocalMatrix(args, this->getLocalMatrix()));
bungeman06ca8ec2016-06-09 08:01:03 -070020}
21#endif
22
reed60c9b582016-04-03 09:11:13 -070023sk_sp<SkFlattenable> SkLocalMatrixShader::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -070024 SkMatrix lm;
25 buffer.readMatrix(&lm);
reed8a21c9f2016-03-08 18:50:00 -080026 auto baseShader(buffer.readShader());
reedf880e452015-12-30 13:39:41 -080027 if (!baseShader) {
halcanary96fcdcc2015-08-27 07:41:13 -070028 return nullptr;
reed9fa60da2014-08-21 07:59:51 -070029 }
reed60c9b582016-04-03 09:11:13 -070030 return baseShader->makeWithLocalMatrix(lm);
reed9fa60da2014-08-21 07:59:51 -070031}
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000032
33void SkLocalMatrixShader::flatten(SkWriteBuffer& buffer) const {
reed9fa60da2014-08-21 07:59:51 -070034 buffer.writeMatrix(this->getLocalMatrix());
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000035 buffer.writeFlattenable(fProxyShader.get());
36}
37
Mike Reede92aae62018-10-17 10:21:51 -040038#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Florin Malita4aed1382017-05-25 10:38:07 -040039SkShaderBase::Context* SkLocalMatrixShader::onMakeContext(
Herb Derby83e939b2017-02-07 14:25:11 -050040 const ContextRec& rec, SkArenaAlloc* alloc) const
41{
Florin Malita325ea322018-04-04 14:17:30 -040042 SkTCopyOnFirstWrite<SkMatrix> lm(this->getLocalMatrix());
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000043 if (rec.fLocalMatrix) {
Florin Malita325ea322018-04-04 14:17:30 -040044 lm.writable()->preConcat(*rec.fLocalMatrix);
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000045 }
Florin Malita325ea322018-04-04 14:17:30 -040046
47 ContextRec newRec(rec);
48 newRec.fLocalMatrix = lm;
49
Florin Malita4aed1382017-05-25 10:38:07 -040050 return as_SB(fProxyShader)->makeContext(newRec, alloc);
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000051}
Mike Reede92aae62018-10-17 10:21:51 -040052#endif
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000053
Mike Reedfae8fce2019-04-03 10:27:45 -040054SkImage* SkLocalMatrixShader::onIsAImage(SkMatrix* outMatrix, SkTileMode* mode) const {
Matt Sarett547a7272017-04-12 11:52:47 -040055 SkMatrix imageMatrix;
56 SkImage* image = fProxyShader->isAImage(&imageMatrix, mode);
57 if (image && outMatrix) {
58 // Local matrix must be applied first so it is on the right side of the concat.
59 *outMatrix = SkMatrix::Concat(imageMatrix, this->getLocalMatrix());
60 }
61
62 return image;
63}
64
Mike Reed1386b2d2019-03-13 21:15:05 -040065bool SkLocalMatrixShader::onAppendStages(const SkStageRec& rec) const {
Florin Malita325ea322018-04-04 14:17:30 -040066 SkTCopyOnFirstWrite<SkMatrix> lm(this->getLocalMatrix());
Mike Reed1d8c42e2017-08-29 14:58:19 -040067 if (rec.fLocalM) {
Florin Malita325ea322018-04-04 14:17:30 -040068 lm.writable()->preConcat(*rec.fLocalM);
Florin Malita882ccaf2017-01-27 10:51:58 -050069 }
Florin Malita325ea322018-04-04 14:17:30 -040070
Mike Reed1386b2d2019-03-13 21:15:05 -040071 SkStageRec newRec = rec;
Florin Malita325ea322018-04-04 14:17:30 -040072 newRec.fLocalM = lm;
Mike Reed1d8c42e2017-08-29 14:58:19 -040073 return as_SB(fProxyShader)->appendStages(newRec);
Florin Malita882ccaf2017-01-27 10:51:58 -050074}
75
reed150835e2016-03-10 06:36:49 -080076sk_sp<SkShader> SkShader::makeWithLocalMatrix(const SkMatrix& localMatrix) const {
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000077 if (localMatrix.isIdentity()) {
reed150835e2016-03-10 06:36:49 -080078 return sk_ref_sp(const_cast<SkShader*>(this));
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000079 }
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +000080
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000081 const SkMatrix* lm = &localMatrix;
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +000082
Ben Wagnera8834bb2016-10-24 11:36:21 -040083 sk_sp<SkShader> baseShader;
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000084 SkMatrix otherLocalMatrix;
Florin Malita4aed1382017-05-25 10:38:07 -040085 sk_sp<SkShader> proxy(as_SB(this)->makeAsALocalMatrixShader(&otherLocalMatrix));
reedf880e452015-12-30 13:39:41 -080086 if (proxy) {
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000087 otherLocalMatrix.preConcat(localMatrix);
88 lm = &otherLocalMatrix;
Ben Wagnera8834bb2016-10-24 11:36:21 -040089 baseShader = proxy;
90 } else {
91 baseShader = sk_ref_sp(const_cast<SkShader*>(this));
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000092 }
skia.committer@gmail.comb2c82c92014-05-08 03:05:29 +000093
Ben Wagnera8834bb2016-10-24 11:36:21 -040094 return sk_make_sp<SkLocalMatrixShader>(std::move(baseShader), *lm);
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +000095}
Mike Reed121c2af2020-03-10 14:02:56 -040096
97////////////////////////////////////////////////////////////////////
98
99/**
100 * Replaces the CTM when used. Created to support clipShaders, which have to be evaluated
101 * using the CTM that was present at the time they were specified (which may be different
102 * from the CTM at the time something is drawn through the clip.
103 */
104class SkCTMShader final : public SkShaderBase {
105public:
106 SkCTMShader(sk_sp<SkShader> proxy, const SkMatrix& ctm)
107 : fProxyShader(std::move(proxy))
108 , fCTM(ctm)
109 {}
110
111 GradientType asAGradient(GradientInfo* info) const override {
112 return fProxyShader->asAGradient(info);
113 }
114
115#if SK_SUPPORT_GPU
116 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
117#endif
118
119protected:
120 void flatten(SkWriteBuffer&) const override { SkASSERT(false); }
121
122#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
123 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override { return nullptr; }
124#endif
125
126 bool onAppendStages(const SkStageRec&) const override;
127
128private:
129 SK_FLATTENABLE_HOOKS(SkCTMShader)
130
131 sk_sp<SkShader> fProxyShader;
132 SkMatrix fCTM;
133
134 typedef SkShaderBase INHERITED;
135};
136
137
138#if SK_SUPPORT_GPU
139std::unique_ptr<GrFragmentProcessor> SkCTMShader::asFragmentProcessor(
140 const GrFPArgs& args) const {
141 return as_SB(fProxyShader)->asFragmentProcessor(
142 GrFPArgs::WithPreLocalMatrix(args, this->getLocalMatrix()));
143}
144#endif
145
146sk_sp<SkFlattenable> SkCTMShader::CreateProc(SkReadBuffer& buffer) {
147 SkASSERT(false);
148 return nullptr;
149}
150
151bool SkCTMShader::onAppendStages(const SkStageRec& rec) const {
152 SkStageRec newRec = {
153 rec.fPipeline,
154 rec.fAlloc,
155 rec.fDstColorType,
156 rec.fDstCS,
157 rec.fPaint,
158 rec.fLocalM,
159 fCTM,
160 };
161 return as_SB(fProxyShader)->appendStages(newRec);
162}
163
164sk_sp<SkShader> SkShaderBase::makeWithCTM(const SkMatrix& postM) const {
165 return postM.isIdentity() ? sk_ref_sp(this)
166 : sk_sp<SkShader>(new SkCTMShader(sk_ref_sp(this), postM));
167}