| epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 1 | /* | 
 | 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 Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 8 | #include "include/core/SkColorFilter.h" | 
 | 9 | #include "include/core/SkString.h" | 
| Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 10 | #include "include/private/SkColorData.h" | 
| Ben Wagner | 729a23f | 2019-05-17 16:29:34 -0400 | [diff] [blame] | 11 | #include "src/core/SkArenaAlloc.h" | 
| Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 12 | #include "src/core/SkBlendModePriv.h" | 
 | 13 | #include "src/core/SkRasterPipeline.h" | 
 | 14 | #include "src/core/SkReadBuffer.h" | 
 | 15 | #include "src/core/SkWriteBuffer.h" | 
 | 16 | #include "src/shaders/SkColorShader.h" | 
 | 17 | #include "src/shaders/SkComposeShader.h" | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 18 |  | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 19 | namespace { | 
 | 20 |  | 
 | 21 | sk_sp<SkShader> wrap_lm(sk_sp<SkShader> shader, const SkMatrix* lm) { | 
 | 22 |     return (shader && lm) ? shader->makeWithLocalMatrix(*lm) : shader; | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 23 | } | 
 | 24 |  | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 25 | struct LocalMatrixStageRec final : public SkStageRec { | 
 | 26 |     LocalMatrixStageRec(const SkStageRec& rec, const SkMatrix& lm) | 
 | 27 |         : INHERITED(rec) { | 
 | 28 |         if (!lm.isIdentity()) { | 
 | 29 |             if (fLocalM) { | 
 | 30 |                 fStorage.setConcat(lm, *fLocalM); | 
 | 31 |                 fLocalM = fStorage.isIdentity() ? nullptr : &fStorage; | 
 | 32 |             } else { | 
 | 33 |                 fLocalM = &lm; | 
 | 34 |             } | 
 | 35 |         } | 
 | 36 |     } | 
 | 37 |  | 
 | 38 | private: | 
 | 39 |     SkMatrix fStorage; | 
 | 40 |  | 
 | 41 |     using INHERITED = SkStageRec; | 
 | 42 | }; | 
 | 43 |  | 
 | 44 | } // namespace | 
 | 45 |  | 
 | 46 | sk_sp<SkShader> SkShaders::Blend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src, | 
 | 47 |                                  const SkMatrix* lm) { | 
 | 48 |     switch (mode) { | 
 | 49 |         case SkBlendMode::kClear: return Color(0); | 
 | 50 |         case SkBlendMode::kDst:   return wrap_lm(std::move(dst), lm); | 
 | 51 |         case SkBlendMode::kSrc:   return wrap_lm(std::move(src), lm); | 
 | 52 |         default: break; | 
 | 53 |     } | 
 | 54 |     return sk_sp<SkShader>(new SkShader_Blend(mode, std::move(dst), std::move(src), lm)); | 
 | 55 | } | 
 | 56 |  | 
 | 57 | sk_sp<SkShader> SkShaders::Lerp(float weight, sk_sp<SkShader> dst, sk_sp<SkShader> src, | 
 | 58 |                                 const SkMatrix* lm) { | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 59 |     if (SkScalarIsNaN(weight)) { | 
| Mike Reed | 7d954ad | 2016-10-28 15:42:34 -0400 | [diff] [blame] | 60 |         return nullptr; | 
 | 61 |     } | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 62 |     if (dst == src || weight <= 0) { | 
 | 63 |         return wrap_lm(std::move(dst), lm); | 
| Mike Reed | 7d954ad | 2016-10-28 15:42:34 -0400 | [diff] [blame] | 64 |     } | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 65 |     if (weight >= 1) { | 
 | 66 |         return wrap_lm(std::move(src), lm); | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 67 |     } | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 68 |     return sk_sp<SkShader>(new SkShader_Lerp(weight, std::move(dst), std::move(src), lm)); | 
| Mike Reed | 7d954ad | 2016-10-28 15:42:34 -0400 | [diff] [blame] | 69 | } | 
 | 70 |  | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 71 | sk_sp<SkShader> SkShaders::Lerp(sk_sp<SkShader> red, sk_sp<SkShader> dst, sk_sp<SkShader> src, | 
 | 72 |                                 const SkMatrix* lm) { | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 73 |     if (!red) { | 
 | 74 |         return nullptr; | 
 | 75 |     } | 
 | 76 |     if (dst == src) { | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 77 |         return wrap_lm(std::move(dst), lm); | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 78 |     } | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 79 |     return sk_sp<SkShader>(new SkShader_LerpRed(std::move(red), std::move(dst), std::move(src), | 
 | 80 |                                                 lm)); | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 81 | } | 
 | 82 |  | 
| reed@google.com | 82065d6 | 2011-02-07 15:30:46 +0000 | [diff] [blame] | 83 | /////////////////////////////////////////////////////////////////////////////// | 
 | 84 |  | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 85 | static bool append_shader_or_paint(const SkStageRec& rec, SkShader* shader) { | 
 | 86 |     if (shader) { | 
 | 87 |         if (!as_SB(shader)->appendStages(rec)) { | 
 | 88 |             return false; | 
 | 89 |         } | 
 | 90 |     } else { | 
 | 91 |         rec.fPipeline->append_constant_color(rec.fAlloc, rec.fPaint.getColor4f().premul().vec()); | 
 | 92 |     } | 
 | 93 |     return true; | 
 | 94 | } | 
 | 95 |  | 
 | 96 | // Returns the output of e0, and leaves the output of e1 in r,g,b,a | 
 | 97 | static float* append_two_shaders(const SkStageRec& rec, SkShader* s0, SkShader* s1) { | 
 | 98 |     struct Storage { | 
 | 99 |         float   fRes0[4 * SkRasterPipeline_kMaxStride]; | 
 | 100 |     }; | 
 | 101 |     auto storage = rec.fAlloc->make<Storage>(); | 
 | 102 |  | 
 | 103 |     if (!append_shader_or_paint(rec, s0)) { | 
 | 104 |         return nullptr; | 
 | 105 |     } | 
 | 106 |     rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRes0); | 
 | 107 |  | 
 | 108 |     if (!append_shader_or_paint(rec, s1)) { | 
 | 109 |         return nullptr; | 
 | 110 |     } | 
 | 111 |     return storage->fRes0; | 
 | 112 | } | 
 | 113 |  | 
 | 114 | /////////////////////////////////////////////////////////////////////////////// | 
 | 115 |  | 
 | 116 | sk_sp<SkFlattenable> SkShader_Blend::CreateProc(SkReadBuffer& buffer) { | 
| Mike Reed | 01b2b83 | 2017-06-09 10:51:52 -0400 | [diff] [blame] | 117 |     sk_sp<SkShader> dst(buffer.readShader()); | 
 | 118 |     sk_sp<SkShader> src(buffer.readShader()); | 
 | 119 |     unsigned        mode = buffer.read32(); | 
| Mike Reed | 01b2b83 | 2017-06-09 10:51:52 -0400 | [diff] [blame] | 120 |  | 
 | 121 |     // check for valid mode before we cast to the enum type | 
| Mike Reed | c5166a9 | 2018-01-03 13:17:18 -0500 | [diff] [blame] | 122 |     if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) { | 
| halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 123 |         return nullptr; | 
| reed | 9fa60da | 2014-08-21 07:59:51 -0700 | [diff] [blame] | 124 |     } | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 125 |     return SkShaders::Blend(static_cast<SkBlendMode>(mode), std::move(dst), std::move(src)); | 
| reed | 9fa60da | 2014-08-21 07:59:51 -0700 | [diff] [blame] | 126 | } | 
 | 127 |  | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 128 | void SkShader_Blend::flatten(SkWriteBuffer& buffer) const { | 
| Mike Reed | 01b2b83 | 2017-06-09 10:51:52 -0400 | [diff] [blame] | 129 |     buffer.writeFlattenable(fDst.get()); | 
 | 130 |     buffer.writeFlattenable(fSrc.get()); | 
| Mike Reed | 7d954ad | 2016-10-28 15:42:34 -0400 | [diff] [blame] | 131 |     buffer.write32((int)fMode); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 132 | } | 
 | 133 |  | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 134 | bool SkShader_Blend::onAppendStages(const SkStageRec& orig_rec) const { | 
 | 135 |     const LocalMatrixStageRec rec(orig_rec, this->getLocalMatrix()); | 
 | 136 |  | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 137 |     float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get()); | 
 | 138 |     if (!res0) { | 
| Mike Reed | 9959f72 | 2017-05-15 09:34:22 -0400 | [diff] [blame] | 139 |         return false; | 
 | 140 |     } | 
| Mike Reed | 5e398c2 | 2019-03-08 11:50:35 -0500 | [diff] [blame] | 141 |  | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 142 |     rec.fPipeline->append(SkRasterPipeline::load_dst, res0); | 
 | 143 |     SkBlendMode_AppendStages(fMode, rec.fPipeline); | 
 | 144 |     return true; | 
 | 145 | } | 
 | 146 |  | 
 | 147 | sk_sp<SkFlattenable> SkShader_Lerp::CreateProc(SkReadBuffer& buffer) { | 
 | 148 |     sk_sp<SkShader> dst(buffer.readShader()); | 
 | 149 |     sk_sp<SkShader> src(buffer.readShader()); | 
 | 150 |     float t = buffer.readScalar(); | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 151 |     return buffer.isValid() ? SkShaders::Lerp(t, std::move(dst), std::move(src)) : nullptr; | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 152 | } | 
 | 153 |  | 
 | 154 | void SkShader_Lerp::flatten(SkWriteBuffer& buffer) const { | 
 | 155 |     buffer.writeFlattenable(fDst.get()); | 
 | 156 |     buffer.writeFlattenable(fSrc.get()); | 
 | 157 |     buffer.writeScalar(fWeight); | 
 | 158 | } | 
 | 159 |  | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 160 | bool SkShader_Lerp::onAppendStages(const SkStageRec& orig_rec) const { | 
 | 161 |     const LocalMatrixStageRec rec(orig_rec, this->getLocalMatrix()); | 
 | 162 |  | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 163 |     float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get()); | 
 | 164 |     if (!res0) { | 
| Mike Reed | 5e398c2 | 2019-03-08 11:50:35 -0500 | [diff] [blame] | 165 |         return false; | 
 | 166 |     } | 
| Mike Reed | 9959f72 | 2017-05-15 09:34:22 -0400 | [diff] [blame] | 167 |  | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 168 |     rec.fPipeline->append(SkRasterPipeline::load_dst, res0); | 
 | 169 |     rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fWeight); | 
| Mike Reed | 9959f72 | 2017-05-15 09:34:22 -0400 | [diff] [blame] | 170 |     return true; | 
 | 171 | } | 
| commit-bot@chromium.org | 7959055 | 2014-05-13 18:14:45 +0000 | [diff] [blame] | 172 |  | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 173 | sk_sp<SkFlattenable> SkShader_LerpRed::CreateProc(SkReadBuffer& buffer) { | 
 | 174 |     sk_sp<SkShader> dst(buffer.readShader()); | 
 | 175 |     sk_sp<SkShader> src(buffer.readShader()); | 
 | 176 |     sk_sp<SkShader> red(buffer.readShader()); | 
 | 177 |     return buffer.isValid() ? | 
 | 178 |            SkShaders::Lerp(std::move(red), std::move(dst), std::move(src)) : nullptr; | 
 | 179 | } | 
 | 180 |  | 
 | 181 | void SkShader_LerpRed::flatten(SkWriteBuffer& buffer) const { | 
 | 182 |     buffer.writeFlattenable(fDst.get()); | 
 | 183 |     buffer.writeFlattenable(fSrc.get()); | 
 | 184 |     buffer.writeFlattenable(fRed.get()); | 
 | 185 | } | 
 | 186 |  | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 187 | bool SkShader_LerpRed::onAppendStages(const SkStageRec& orig_rec) const { | 
 | 188 |     const LocalMatrixStageRec rec(orig_rec, this->getLocalMatrix()); | 
 | 189 |  | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 190 |     struct Storage { | 
 | 191 |         float   fRed[4 * SkRasterPipeline_kMaxStride]; | 
 | 192 |     }; | 
 | 193 |     auto storage = rec.fAlloc->make<Storage>(); | 
 | 194 |     if (!as_SB(fRed)->appendStages(rec)) { | 
 | 195 |         return false; | 
 | 196 |     } | 
 | 197 |     // actually, we just need the first (red) channel, but for now we store rgba | 
 | 198 |     rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRed); | 
 | 199 |  | 
 | 200 |     float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get()); | 
 | 201 |     if (!res0) { | 
 | 202 |         return false; | 
 | 203 |     } | 
 | 204 |  | 
 | 205 |     rec.fPipeline->append(SkRasterPipeline::load_dst, res0); | 
 | 206 |     rec.fPipeline->append(SkRasterPipeline::lerp_native, &storage->fRed[0]); | 
 | 207 |     return true; | 
 | 208 | } | 
 | 209 |  | 
| wangyix | 73fa616 | 2015-09-01 09:45:08 -0700 | [diff] [blame] | 210 | #if SK_SUPPORT_GPU | 
 | 211 |  | 
| Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 212 | #include "include/private/GrRecordingContext.h" | 
 | 213 | #include "src/gpu/effects/GrXfermodeFragmentProcessor.h" | 
 | 214 | #include "src/gpu/effects/generated/GrComposeLerpEffect.h" | 
 | 215 | #include "src/gpu/effects/generated/GrComposeLerpRedEffect.h" | 
 | 216 | #include "src/gpu/effects/generated/GrConstColorProcessor.h" | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 217 |  | 
 | 218 | static std::unique_ptr<GrFragmentProcessor> as_fp(const GrFPArgs& args, SkShader* shader) { | 
| Ethan Nicholas | ff4fb33 | 2019-04-09 16:28:19 -0400 | [diff] [blame] | 219 |     return shader ? as_SB(shader)->asFragmentProcessor(args) : nullptr; | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 220 | } | 
 | 221 |  | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 222 | std::unique_ptr<GrFragmentProcessor> SkShader_Blend::asFragmentProcessor( | 
 | 223 |         const GrFPArgs& orig_args) const { | 
 | 224 |     const GrFPArgs::WithPreLocalMatrix args(orig_args, this->getLocalMatrix()); | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 225 |     auto fpA = as_fp(args, fDst.get()); | 
 | 226 |     auto fpB = as_fp(args, fSrc.get()); | 
 | 227 |     if (!fpA || !fpB) { | 
| Mike Reed | 01b2b83 | 2017-06-09 10:51:52 -0400 | [diff] [blame] | 228 |         return nullptr; | 
 | 229 |     } | 
| Mike Reed | 01b2b83 | 2017-06-09 10:51:52 -0400 | [diff] [blame] | 230 |     return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), | 
 | 231 |                                                               std::move(fpA), fMode); | 
| wangyix | 73fa616 | 2015-09-01 09:45:08 -0700 | [diff] [blame] | 232 | } | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 233 |  | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 234 | std::unique_ptr<GrFragmentProcessor> SkShader_Lerp::asFragmentProcessor( | 
 | 235 |         const GrFPArgs& orig_args) const { | 
 | 236 |     const GrFPArgs::WithPreLocalMatrix args(orig_args, this->getLocalMatrix()); | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 237 |     auto fpA = as_fp(args, fDst.get()); | 
 | 238 |     auto fpB = as_fp(args, fSrc.get()); | 
| Ethan Nicholas | ff4fb33 | 2019-04-09 16:28:19 -0400 | [diff] [blame] | 239 |     return GrComposeLerpEffect::Make(std::move(fpA), std::move(fpB), fWeight); | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 240 | } | 
 | 241 |  | 
| Florin Malita | 9ab449a | 2019-07-09 13:22:50 -0400 | [diff] [blame] | 242 | std::unique_ptr<GrFragmentProcessor> SkShader_LerpRed::asFragmentProcessor( | 
 | 243 |         const GrFPArgs& orig_args) const { | 
 | 244 |     const GrFPArgs::WithPreLocalMatrix args(orig_args, this->getLocalMatrix()); | 
| Mike Reed | c8bea7d | 2019-04-09 13:55:36 -0400 | [diff] [blame] | 245 |     auto fpA = as_fp(args, fDst.get()); | 
 | 246 |     auto fpB = as_fp(args, fSrc.get()); | 
 | 247 |     auto red = as_SB(fRed)->asFragmentProcessor(args); | 
| Ethan Nicholas | ff4fb33 | 2019-04-09 16:28:19 -0400 | [diff] [blame] | 248 |     if (!red) { | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 249 |         return nullptr; | 
 | 250 |     } | 
| Ethan Nicholas | ff4fb33 | 2019-04-09 16:28:19 -0400 | [diff] [blame] | 251 |     return GrComposeLerpRedEffect::Make(std::move(fpA), std::move(fpB), std::move(red)); | 
| Mike Reed | 9b2c4e9 | 2019-04-02 09:54:14 -0400 | [diff] [blame] | 252 | } | 
| wangyix | 73fa616 | 2015-09-01 09:45:08 -0700 | [diff] [blame] | 253 | #endif |