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 8 #include "SkArenaAlloc.h" 9 #include "SkBlendModePriv.h" 10 #include "SkComposeShader.h" 11 #include "SkColorFilter.h" 12 #include "SkColorData.h" 13 #include "SkColorShader.h" 14 #include "SkRasterPipeline.h" 15 #include "SkReadBuffer.h" 16 #include "SkWriteBuffer.h" 17 #include "SkString.h" 18 #include "../jumper/SkJumper.h" 19 20 sk_sp<SkShader> SkShader::MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode, 21 float lerpT) { 22 if (!src || !dst || SkScalarIsNaN(lerpT)) { 23 return nullptr; 24 } 25 lerpT = SkScalarPin(lerpT, 0, 1); 26 27 if (lerpT == 0) { 28 return dst; 29 } else if (lerpT == 1) { 30 if (mode == SkBlendMode::kSrc) { 31 return src; 32 } 33 if (mode == SkBlendMode::kDst) { 34 return dst; 35 } 36 } 37 return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode, lerpT)); 38 } 39 40 /////////////////////////////////////////////////////////////////////////////// 41 42 sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) { 43 sk_sp<SkShader> dst(buffer.readShader()); 44 sk_sp<SkShader> src(buffer.readShader()); 45 unsigned mode = buffer.read32(); 46 float lerp = buffer.readScalar(); 47 48 // check for valid mode before we cast to the enum type 49 if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) { 50 return nullptr; 51 } 52 return MakeCompose(std::move(dst), std::move(src), static_cast<SkBlendMode>(mode), lerp); 53 } 54 55 void SkComposeShader::flatten(SkWriteBuffer& buffer) const { 56 buffer.writeFlattenable(fDst.get()); 57 buffer.writeFlattenable(fSrc.get()); 58 buffer.write32((int)fMode); 59 buffer.writeScalar(fLerpT); 60 } 61 62 sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 63 return MakeCompose(xformer->apply(fDst.get()), xformer->apply(fSrc.get()), 64 fMode, fLerpT); 65 } 66 67 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 68 bool SkComposeShader::asACompose(ComposeRec* rec) const { 69 if (!this->isJustMode()) { 70 return false; 71 } 72 73 if (rec) { 74 rec->fShaderA = fDst.get(); 75 rec->fShaderB = fSrc.get(); 76 rec->fBlendMode = fMode; 77 } 78 return true; 79 } 80 #endif 81 82 bool SkComposeShader::onAppendStages(const StageRec& rec) const { 83 struct Storage { 84 float fRGBA[4 * SkJumper_kMaxStride]; 85 float fAlpha; 86 }; 87 auto storage = rec.fAlloc->make<Storage>(); 88 89 if (!as_SB(fSrc)->appendStages(rec)) { 90 return false; 91 } 92 // This outputs r,g,b,a, which we'll need later when we apply the mode, but we save it off now 93 // since fShaderB will overwrite them. 94 rec.fPipeline->append(SkRasterPipeline::store_rgba, storage->fRGBA); 95 96 if (!as_SB(fDst)->appendStages(rec)) { 97 return false; 98 } 99 // We now have our logical 'dst' in r,g,b,a, but we need it in dr,dg,db,da for the mode/lerp 100 // so we have to shuttle them. If we had a stage the would load_into_dst, then we could 101 // reverse the two shader invocations, and avoid this move... 102 rec.fPipeline->append(SkRasterPipeline::move_src_dst); 103 rec.fPipeline->append(SkRasterPipeline::load_rgba, storage->fRGBA); 104 105 if (!this->isJustLerp()) { 106 SkBlendMode_AppendStages(fMode, rec.fPipeline); 107 } 108 if (!this->isJustMode()) { 109 rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fLerpT); 110 } 111 return true; 112 } 113 114 #if SK_SUPPORT_GPU 115 116 #include "effects/GrConstColorProcessor.h" 117 #include "effects/GrXfermodeFragmentProcessor.h" 118 119 ///////////////////////////////////////////////////////////////////// 120 121 std::unique_ptr<GrFragmentProcessor> SkComposeShader::asFragmentProcessor( 122 const GrFPArgs& args) const { 123 if (this->isJustMode()) { 124 SkASSERT(fMode != SkBlendMode::kSrc && fMode != SkBlendMode::kDst); // caught in factory 125 if (fMode == SkBlendMode::kClear) { 126 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), 127 GrConstColorProcessor::InputMode::kIgnore); 128 } 129 } 130 131 std::unique_ptr<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args)); 132 if (!fpA) { 133 return nullptr; 134 } 135 std::unique_ptr<GrFragmentProcessor> fpB(as_SB(fSrc)->asFragmentProcessor(args)); 136 if (!fpB) { 137 return nullptr; 138 } 139 // TODO: account for fLerpT when it is < 1 140 return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), 141 std::move(fpA), fMode); 142 } 143 #endif 144 145 #ifndef SK_IGNORE_TO_STRING 146 void SkComposeShader::toString(SkString* str) const { 147 str->append("SkComposeShader: ("); 148 149 str->append("dst: "); 150 as_SB(fDst)->toString(str); 151 str->append(" src: "); 152 as_SB(fSrc)->toString(str); 153 str->appendf(" mode: %s", SkBlendMode_Name(fMode)); 154 str->appendf(" lerpT: %g", fLerpT); 155 156 this->INHERITED::toString(str); 157 158 str->append(")"); 159 } 160 #endif 161