blob: 0095a9509c4e6448d0baea5d80d5c25cd93612f6 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkMallocPixelRef.h"
9#include "include/core/SkPaint.h"
10#include "include/core/SkPicture.h"
11#include "include/core/SkScalar.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040012#include "src/core/SkArenaAlloc.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/core/SkColorSpacePriv.h"
14#include "src/core/SkColorSpaceXformSteps.h"
15#include "src/core/SkRasterPipeline.h"
16#include "src/core/SkReadBuffer.h"
17#include "src/core/SkTLazy.h"
18#include "src/core/SkWriteBuffer.h"
19#include "src/shaders/SkBitmapProcShader.h"
20#include "src/shaders/SkColorShader.h"
21#include "src/shaders/SkEmptyShader.h"
22#include "src/shaders/SkPictureShader.h"
23#include "src/shaders/SkShaderBase.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000024
bungeman06ca8ec2016-06-09 08:01:03 -070025#if SK_SUPPORT_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "src/gpu/GrFragmentProcessor.h"
bungeman06ca8ec2016-06-09 08:01:03 -070027#endif
28
Florin Malita4aed1382017-05-25 10:38:07 -040029SkShaderBase::SkShaderBase(const SkMatrix* localMatrix)
30 : fLocalMatrix(localMatrix ? *localMatrix : SkMatrix::I()) {
mtklein435eba72014-12-01 12:06:24 -080031 // Pre-cache so future calls to fLocalMatrix.getType() are threadsafe.
32 (void)fLocalMatrix.getType();
reed@android.com8a1c16f2008-12-17 15:59:43 +000033}
34
Mike Kleinde2244c2018-12-04 11:16:08 -050035SkShaderBase::~SkShaderBase() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000036
Florin Malita4aed1382017-05-25 10:38:07 -040037void SkShaderBase::flatten(SkWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 this->INHERITED::flatten(buffer);
commit-bot@chromium.org5970f622014-05-12 20:42:21 +000039 bool hasLocalM = !fLocalMatrix.isIdentity();
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000040 buffer.writeBool(hasLocalM);
41 if (hasLocalM) {
42 buffer.writeMatrix(fLocalMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +000043 }
44}
45
Florin Malitac6c5ead2018-04-11 15:33:40 -040046SkTCopyOnFirstWrite<SkMatrix>
47SkShaderBase::totalLocalMatrix(const SkMatrix* preLocalMatrix,
48 const SkMatrix* postLocalMatrix) const {
49 SkTCopyOnFirstWrite<SkMatrix> m(fLocalMatrix);
50
51 if (preLocalMatrix) {
52 m.writable()->preConcat(*preLocalMatrix);
53 }
54
55 if (postLocalMatrix) {
56 m.writable()->postConcat(*postLocalMatrix);
57 }
58
59 return m;
60}
61
Florin Malita4aed1382017-05-25 10:38:07 -040062bool SkShaderBase::computeTotalInverse(const SkMatrix& ctm,
63 const SkMatrix* outerLocalMatrix,
64 SkMatrix* totalInverse) const {
Florin Malitac6c5ead2018-04-11 15:33:40 -040065 return SkMatrix::Concat(ctm, *this->totalLocalMatrix(outerLocalMatrix)).invert(totalInverse);
reed@android.com8a1c16f2008-12-17 15:59:43 +000066}
67
Florin Malita4aed1382017-05-25 10:38:07 -040068bool SkShaderBase::asLuminanceColor(SkColor* colorPtr) const {
reed8367b8c2014-08-22 08:30:20 -070069 SkColor storage;
halcanary96fcdcc2015-08-27 07:41:13 -070070 if (nullptr == colorPtr) {
reed8367b8c2014-08-22 08:30:20 -070071 colorPtr = &storage;
72 }
73 if (this->onAsLuminanceColor(colorPtr)) {
74 *colorPtr = SkColorSetA(*colorPtr, 0xFF); // we only return opaque
75 return true;
76 }
77 return false;
78}
79
Florin Malita4aed1382017-05-25 10:38:07 -040080SkShaderBase::Context* SkShaderBase::makeContext(const ContextRec& rec, SkArenaAlloc* alloc) const {
Mike Reede92aae62018-10-17 10:21:51 -040081#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Florin Malitaaf2769d2018-04-04 13:46:35 -040082 // We always fall back to raster pipeline when perspective is present.
83 if (rec.fMatrix->hasPerspective() ||
84 fLocalMatrix.hasPerspective() ||
85 (rec.fLocalMatrix && rec.fLocalMatrix->hasPerspective()) ||
86 !this->computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, nullptr)) {
87 return nullptr;
88 }
89
90 return this->onMakeContext(rec, alloc);
Mike Reede92aae62018-10-17 10:21:51 -040091#else
92 return nullptr;
93#endif
commit-bot@chromium.orgf3e50592014-04-30 23:29:02 +000094}
95
Florin Malita4aed1382017-05-25 10:38:07 -040096SkShaderBase::Context::Context(const SkShaderBase& shader, const ContextRec& rec)
commit-bot@chromium.org80116dc2014-05-06 17:16:03 +000097 : fShader(shader), fCTM(*rec.fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000098{
Florin Malitaaf2769d2018-04-04 13:46:35 -040099 // We should never use a context with perspective.
Florin Malita5769dd22017-07-12 13:31:25 -0400100 SkASSERT(!rec.fMatrix->hasPerspective());
101 SkASSERT(!rec.fLocalMatrix || !rec.fLocalMatrix->hasPerspective());
Florin Malitaaf2769d2018-04-04 13:46:35 -0400102 SkASSERT(!shader.getLocalMatrix().hasPerspective());
Florin Malita7d022e02017-05-15 15:06:39 -0400103
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000104 // Because the context parameters must be valid at this point, we know that the matrix is
105 // invertible.
Florin Malita26368c32017-05-08 13:03:24 -0400106 SkAssertResult(fShader.computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, &fTotalInverse));
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000107
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000108 fPaintAlpha = rec.fPaint->getAlpha();
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000109}
110
Florin Malita4aed1382017-05-25 10:38:07 -0400111SkShaderBase::Context::~Context() {}
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000112
Mike Reed011d1662019-02-28 17:19:25 -0500113bool SkShaderBase::ContextRec::isLegacyCompatible(SkColorSpace* shaderColorSpace) const {
Mike Klein49982b42019-03-28 09:46:48 -0500114 return !SkColorSpaceXformSteps::Required(shaderColorSpace, fDstColorSpace);
Mike Reed011d1662019-02-28 17:19:25 -0500115}
116
Mike Reedfae8fce2019-04-03 10:27:45 -0400117SkImage* SkShader::isAImage(SkMatrix* localMatrix, SkTileMode xy[2]) const {
Florin Malita4aed1382017-05-25 10:38:07 -0400118 return as_SB(this)->onIsAImage(localMatrix, xy);
119}
120
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000121SkShader::GradientType SkShader::asAGradient(GradientInfo* info) const {
122 return kNone_GradientType;
123}
124
bungeman06ca8ec2016-06-09 08:01:03 -0700125#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500126std::unique_ptr<GrFragmentProcessor> SkShaderBase::asFragmentProcessor(const GrFPArgs&) const {
bsalomonc21b09e2015-08-28 18:46:56 -0700127 return nullptr;
rileya@google.com03c1c352012-07-20 20:02:43 +0000128}
bungeman06ca8ec2016-06-09 08:01:03 -0700129#endif
rileya@google.com03c1c352012-07-20 20:02:43 +0000130
Mike Reed7656b2c2019-04-08 11:48:20 -0400131sk_sp<SkShader> SkShaderBase::makeAsALocalMatrixShader(SkMatrix*) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700132 return nullptr;
commit-bot@chromium.org8fae2132014-05-07 22:26:37 +0000133}
134
Mike Reedc8bea7d2019-04-09 13:55:36 -0400135sk_sp<SkShader> SkShaders::Empty() { return sk_make_sp<SkEmptyShader>(); }
136sk_sp<SkShader> SkShaders::Color(SkColor color) { return sk_make_sp<SkColorShader>(color); }
reed8367b8c2014-08-22 08:30:20 -0700137
Mike Reed50acf8f2019-04-08 13:20:23 -0400138sk_sp<SkShader> SkBitmap::makeShader(SkTileMode tmx, SkTileMode tmy, const SkMatrix* lm) const {
139 if (lm && !lm->invert(nullptr)) {
140 return nullptr;
141 }
142 return SkMakeBitmapShader(*this, tmx, tmy, lm, kIfMutable_SkCopyPixelsMode);
143}
144
145sk_sp<SkShader> SkBitmap::makeShader(const SkMatrix* lm) const {
146 return this->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, lm);
147}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148
Mike Reed1386b2d2019-03-13 21:15:05 -0400149bool SkShaderBase::appendStages(const SkStageRec& rec) const {
Mike Reed1d8c42e2017-08-29 14:58:19 -0400150 return this->onAppendStages(rec);
Florin Malita9206c762017-01-30 12:08:05 -0500151}
152
Mike Reed1386b2d2019-03-13 21:15:05 -0400153bool SkShaderBase::onAppendStages(const SkStageRec& rec) const {
Mike Klein541cbd42019-01-30 13:11:33 -0500154 // SkShader::Context::shadeSpan() handles the paint opacity internally,
Mike Reed6867eee2017-06-02 13:25:15 -0400155 // but SkRasterPipelineBlitter applies it as a separate stage.
Mike Klein541cbd42019-01-30 13:11:33 -0500156 // We skip the internal shadeSpan() step by forcing the paint opaque.
Mike Reed1d8c42e2017-08-29 14:58:19 -0400157 SkTCopyOnFirstWrite<SkPaint> opaquePaint(rec.fPaint);
158 if (rec.fPaint.getAlpha() != SK_AlphaOPAQUE) {
Mike Reed6867eee2017-06-02 13:25:15 -0400159 opaquePaint.writable()->setAlpha(SK_AlphaOPAQUE);
160 }
161
Mike Klein894328d2019-03-21 10:06:38 -0500162 ContextRec cr(*opaquePaint, rec.fCTM, rec.fLocalM, rec.fDstColorType, sk_srgb_singleton());
Mike Reed6867eee2017-06-02 13:25:15 -0400163
Mike Kleinb11ab572018-10-24 06:42:14 -0400164 struct CallbackCtx : SkRasterPipeline_CallbackCtx {
Mike Kleinb0b2c962019-03-21 10:33:51 -0500165 sk_sp<const SkShader> shader;
166 Context* ctx;
Mike Reed6867eee2017-06-02 13:25:15 -0400167 };
Mike Reed1d8c42e2017-08-29 14:58:19 -0400168 auto cb = rec.fAlloc->make<CallbackCtx>();
Mike Kleinb0b2c962019-03-21 10:33:51 -0500169 cb->shader = sk_ref_sp(this);
170 cb->ctx = as_SB(this)->makeContext(cr, rec.fAlloc);
Mike Kleinb11ab572018-10-24 06:42:14 -0400171 cb->fn = [](SkRasterPipeline_CallbackCtx* self, int active_pixels) {
Mike Reed6867eee2017-06-02 13:25:15 -0400172 auto c = (CallbackCtx*)self;
173 int x = (int)c->rgba[0],
Mike Klein541cbd42019-01-30 13:11:33 -0500174 y = (int)c->rgba[1];
175 SkPMColor tmp[SkRasterPipeline_kMaxStride];
176 c->ctx->shadeSpan(x,y, tmp, active_pixels);
177
178 for (int i = 0; i < active_pixels; i++) {
179 auto rgba_4f = SkPMColor4f::FromPMColor(tmp[i]);
180 memcpy(c->rgba + 4*i, rgba_4f.vec(), 4*sizeof(float));
181 }
Mike Reed6867eee2017-06-02 13:25:15 -0400182 };
183
184 if (cb->ctx) {
Mike Kleine8de0242018-03-10 12:37:11 -0500185 rec.fPipeline->append(SkRasterPipeline::seed_shader);
Mike Reed1d8c42e2017-08-29 14:58:19 -0400186 rec.fPipeline->append(SkRasterPipeline::callback, cb);
Mike Klein894328d2019-03-21 10:06:38 -0500187 rec.fAlloc->make<SkColorSpaceXformSteps>(sk_srgb_singleton(), kPremul_SkAlphaType,
188 rec.fDstCS, kPremul_SkAlphaType)
189 ->apply(rec.fPipeline, true);
Mike Reed6867eee2017-06-02 13:25:15 -0400190 return true;
191 }
Mike Klein44d32792017-05-10 12:29:38 -0400192 return false;
193}
194
reed0ccc62d2016-05-04 13:09:39 -0700195///////////////////////////////////////////////////////////////////////////////////////////////////
reed830dfd82016-03-16 12:29:01 -0700196
reed60c9b582016-04-03 09:11:13 -0700197sk_sp<SkFlattenable> SkEmptyShader::CreateProc(SkReadBuffer&) {
Mike Reedc8bea7d2019-04-09 13:55:36 -0400198 return SkShaders::Empty();
reed9fa60da2014-08-21 07:59:51 -0700199}