blob: 2dee742d807fa31e4449d4dc22aeb67d02f0fec8 [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
Herb Derby83e939b2017-02-07 14:25:11 -05008#include "SkArenaAlloc.h"
Mike Reed9959f722017-05-15 09:34:22 -04009#include "SkBlendModePriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkComposeShader.h"
11#include "SkColorFilter.h"
Cary Clarka4083c92017-09-15 11:59:23 -040012#include "SkColorData.h"
reed@google.com573f22b2011-11-30 19:17:15 +000013#include "SkColorShader.h"
Mike Reed9959f722017-05-15 09:34:22 -040014#include "SkRasterPipeline.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000015#include "SkReadBuffer.h"
16#include "SkWriteBuffer.h"
robertphillips@google.com76f9e932013-01-15 20:17:47 +000017#include "SkString.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000018
Mike Reed01b2b832017-06-09 10:51:52 -040019sk_sp<SkShader> SkShader::MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode,
20 float lerpT) {
21 if (!src || !dst || SkScalarIsNaN(lerpT)) {
Mike Reed7d954ad2016-10-28 15:42:34 -040022 return nullptr;
23 }
Mike Reed01b2b832017-06-09 10:51:52 -040024 lerpT = SkScalarPin(lerpT, 0, 1);
25
26 if (lerpT == 0) {
Mike Reed7d954ad2016-10-28 15:42:34 -040027 return dst;
Mike Reed01b2b832017-06-09 10:51:52 -040028 } else if (lerpT == 1) {
29 if (mode == SkBlendMode::kSrc) {
30 return src;
31 }
32 if (mode == SkBlendMode::kDst) {
33 return dst;
34 }
Mike Reed7d954ad2016-10-28 15:42:34 -040035 }
Mike Reed01b2b832017-06-09 10:51:52 -040036 return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode, lerpT));
Mike Reed7d954ad2016-10-28 15:42:34 -040037}
38
reed@google.com82065d62011-02-07 15:30:46 +000039///////////////////////////////////////////////////////////////////////////////
40
reed60c9b582016-04-03 09:11:13 -070041sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) {
Mike Reed01b2b832017-06-09 10:51:52 -040042 sk_sp<SkShader> dst(buffer.readShader());
43 sk_sp<SkShader> src(buffer.readShader());
44 unsigned mode = buffer.read32();
Mike Reedc5166a92018-01-03 13:17:18 -050045 float lerp = buffer.readScalar();
Mike Reed01b2b832017-06-09 10:51:52 -040046
47 // check for valid mode before we cast to the enum type
Mike Reedc5166a92018-01-03 13:17:18 -050048 if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
halcanary96fcdcc2015-08-27 07:41:13 -070049 return nullptr;
reed9fa60da2014-08-21 07:59:51 -070050 }
Mike Reed01b2b832017-06-09 10:51:52 -040051 return MakeCompose(std::move(dst), std::move(src), static_cast<SkBlendMode>(mode), lerp);
reed9fa60da2014-08-21 07:59:51 -070052}
53
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000054void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
Mike Reed01b2b832017-06-09 10:51:52 -040055 buffer.writeFlattenable(fDst.get());
56 buffer.writeFlattenable(fSrc.get());
Mike Reed7d954ad2016-10-28 15:42:34 -040057 buffer.write32((int)fMode);
Mike Reed01b2b832017-06-09 10:51:52 -040058 buffer.writeScalar(fLerpT);
reed@android.com8a1c16f2008-12-17 15:59:43 +000059}
60
Mike Klein2814d912017-05-10 12:35:51 -040061sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
Mike Reed01b2b832017-06-09 10:51:52 -040062 return MakeCompose(xformer->apply(fDst.get()), xformer->apply(fSrc.get()),
63 fMode, fLerpT);
Mike Klein2814d912017-05-10 12:35:51 -040064}
65
Mike Reeda6aaa302017-06-09 10:29:40 -040066#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
commit-bot@chromium.org79590552014-05-13 18:14:45 +000067bool SkComposeShader::asACompose(ComposeRec* rec) const {
Mike Reed01b2b832017-06-09 10:51:52 -040068 if (!this->isJustMode()) {
69 return false;
70 }
71
commit-bot@chromium.org79590552014-05-13 18:14:45 +000072 if (rec) {
Mike Reed01b2b832017-06-09 10:51:52 -040073 rec->fShaderA = fDst.get();
74 rec->fShaderB = fSrc.get();
Mike Reed7d954ad2016-10-28 15:42:34 -040075 rec->fBlendMode = fMode;
commit-bot@chromium.org79590552014-05-13 18:14:45 +000076 }
77 return true;
78}
Mike Reeda6aaa302017-06-09 10:29:40 -040079#endif
commit-bot@chromium.org79590552014-05-13 18:14:45 +000080
Mike Reed1d8c42e2017-08-29 14:58:19 -040081bool SkComposeShader::onAppendStages(const StageRec& rec) const {
Mike Reed9959f722017-05-15 09:34:22 -040082 struct Storage {
Mike Kleinb11ab572018-10-24 06:42:14 -040083 float fRGBA[4 * SkRasterPipeline_kMaxStride];
Mike Reed9959f722017-05-15 09:34:22 -040084 float fAlpha;
85 };
Mike Reed1d8c42e2017-08-29 14:58:19 -040086 auto storage = rec.fAlloc->make<Storage>();
Mike Reed9959f722017-05-15 09:34:22 -040087
Mike Reed1d8c42e2017-08-29 14:58:19 -040088 if (!as_SB(fSrc)->appendStages(rec)) {
Mike Reed9959f722017-05-15 09:34:22 -040089 return false;
90 }
91 // This outputs r,g,b,a, which we'll need later when we apply the mode, but we save it off now
92 // since fShaderB will overwrite them.
Mike Reed1d8c42e2017-08-29 14:58:19 -040093 rec.fPipeline->append(SkRasterPipeline::store_rgba, storage->fRGBA);
Mike Klein5df94d52017-06-01 14:43:51 -040094
Mike Reed1d8c42e2017-08-29 14:58:19 -040095 if (!as_SB(fDst)->appendStages(rec)) {
Mike Reed9959f722017-05-15 09:34:22 -040096 return false;
97 }
Mike Reed01b2b832017-06-09 10:51:52 -040098 // We now have our logical 'dst' in r,g,b,a, but we need it in dr,dg,db,da for the mode/lerp
Mike Reed9959f722017-05-15 09:34:22 -040099 // so we have to shuttle them. If we had a stage the would load_into_dst, then we could
100 // reverse the two shader invocations, and avoid this move...
Mike Reed1d8c42e2017-08-29 14:58:19 -0400101 rec.fPipeline->append(SkRasterPipeline::move_src_dst);
102 rec.fPipeline->append(SkRasterPipeline::load_rgba, storage->fRGBA);
Mike Reed9959f722017-05-15 09:34:22 -0400103
Mike Reed01b2b832017-06-09 10:51:52 -0400104 if (!this->isJustLerp()) {
Mike Reed1d8c42e2017-08-29 14:58:19 -0400105 SkBlendMode_AppendStages(fMode, rec.fPipeline);
Mike Reed01b2b832017-06-09 10:51:52 -0400106 }
107 if (!this->isJustMode()) {
Mike Reed1d8c42e2017-08-29 14:58:19 -0400108 rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fLerpT);
Mike Reed9959f722017-05-15 09:34:22 -0400109 }
110 return true;
111}
commit-bot@chromium.org79590552014-05-13 18:14:45 +0000112
wangyix73fa6162015-09-01 09:45:08 -0700113#if SK_SUPPORT_GPU
114
wangyix036fd8e2015-09-08 15:23:34 -0700115#include "effects/GrConstColorProcessor.h"
wangyix809e5af2015-09-09 12:58:32 -0700116#include "effects/GrXfermodeFragmentProcessor.h"
wangyix73fa6162015-09-01 09:45:08 -0700117
118/////////////////////////////////////////////////////////////////////
119
Brian Salomonaff329b2017-08-11 09:40:37 -0400120std::unique_ptr<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -0500121 const GrFPArgs& args) const {
Mike Reed01b2b832017-06-09 10:51:52 -0400122 if (this->isJustMode()) {
123 SkASSERT(fMode != SkBlendMode::kSrc && fMode != SkBlendMode::kDst); // caught in factory
124 if (fMode == SkBlendMode::kClear) {
Brian Osmanf28e55d2018-10-03 16:35:54 -0400125 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
Ethan Nicholase9d172a2017-11-20 12:12:24 -0500126 GrConstColorProcessor::InputMode::kIgnore);
Mike Reed01b2b832017-06-09 10:51:52 -0400127 }
wangyix73fa6162015-09-01 09:45:08 -0700128 }
Mike Reed01b2b832017-06-09 10:51:52 -0400129
Brian Salomonaff329b2017-08-11 09:40:37 -0400130 std::unique_ptr<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args));
Mike Reed01b2b832017-06-09 10:51:52 -0400131 if (!fpA) {
132 return nullptr;
133 }
Brian Salomonaff329b2017-08-11 09:40:37 -0400134 std::unique_ptr<GrFragmentProcessor> fpB(as_SB(fSrc)->asFragmentProcessor(args));
Mike Reed01b2b832017-06-09 10:51:52 -0400135 if (!fpB) {
136 return nullptr;
137 }
138 // TODO: account for fLerpT when it is < 1
139 return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
140 std::move(fpA), fMode);
wangyix73fa6162015-09-01 09:45:08 -0700141}
142#endif