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 19 sk_sp<SkShader> SkShader::MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode, 20 float lerpT) { 21 if (!src || !dst || SkScalarIsNaN(lerpT)) { 22 return nullptr; 23 } 24 lerpT = SkScalarPin(lerpT, 0, 1); 25 26 if (lerpT == 0) { 27 return dst; 28 } else if (lerpT == 1) { 29 if (mode == SkBlendMode::kSrc) { 30 return src; 31 } 32 if (mode == SkBlendMode::kDst) { 33 return dst; 34 } 35 } 36 return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode, lerpT)); 37 } 38 39 /////////////////////////////////////////////////////////////////////////////// 40 41 sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) { 42 sk_sp<SkShader> dst(buffer.readShader()); 43 sk_sp<SkShader> src(buffer.readShader()); 44 unsigned mode = buffer.read32(); 45 float lerp = buffer.readScalar(); 46 47 // check for valid mode before we cast to the enum type 48 if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) { 49 return nullptr; 50 } 51 return MakeCompose(std::move(dst), std::move(src), static_cast<SkBlendMode>(mode), lerp); 52 } 53 54 void SkComposeShader::flatten(SkWriteBuffer& buffer) const { 55 buffer.writeFlattenable(fDst.get()); 56 buffer.writeFlattenable(fSrc.get()); 57 buffer.write32((int)fMode); 58 buffer.writeScalar(fLerpT); 59 } 60 61 sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 62 return MakeCompose(xformer->apply(fDst.get()), xformer->apply(fSrc.get()), 63 fMode, fLerpT); 64 } 65 66 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 67 bool SkComposeShader::asACompose(ComposeRec* rec) const { 68 if (!this->isJustMode()) { 69 return false; 70 } 71 72 if (rec) { 73 rec->fShaderA = fDst.get(); 74 rec->fShaderB = fSrc.get(); 75 rec->fBlendMode = fMode; 76 } 77 return true; 78 } 79 #endif 80 81 bool SkComposeShader::onAppendStages(const StageRec& rec) const { 82 struct Storage { 83 float fRGBA[4 * SkRasterPipeline_kMaxStride]; 84 float fAlpha; 85 }; 86 auto storage = rec.fAlloc->make<Storage>(); 87 88 if (!as_SB(fDst)->appendStages(rec)) { 89 return false; 90 } 91 // This outputs r,g,b,a, which we'll need later when we apply the mode, so we save it off now 92 rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRGBA); 93 94 if (!as_SB(fSrc)->appendStages(rec)) { 95 return false; 96 } 97 // r,g,b,a now have the right input for the next step (lerp and/or mode), but we need to 98 // reload dr,dg,db,da from memory, since we stashed that from our fDst invocation earlier. 99 rec.fPipeline->append(SkRasterPipeline::load_dst, storage->fRGBA); 100 101 if (!this->isJustLerp()) { 102 SkBlendMode_AppendStages(fMode, rec.fPipeline); 103 } 104 if (!this->isJustMode()) { 105 rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fLerpT); 106 } 107 return true; 108 } 109 110 #if SK_SUPPORT_GPU 111 112 #include "effects/GrConstColorProcessor.h" 113 #include "effects/GrXfermodeFragmentProcessor.h" 114 115 ///////////////////////////////////////////////////////////////////// 116 117 std::unique_ptr<GrFragmentProcessor> SkComposeShader::asFragmentProcessor( 118 const GrFPArgs& args) const { 119 if (this->isJustMode()) { 120 SkASSERT(fMode != SkBlendMode::kSrc && fMode != SkBlendMode::kDst); // caught in factory 121 if (fMode == SkBlendMode::kClear) { 122 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT, 123 GrConstColorProcessor::InputMode::kIgnore); 124 } 125 } 126 127 std::unique_ptr<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args)); 128 if (!fpA) { 129 return nullptr; 130 } 131 std::unique_ptr<GrFragmentProcessor> fpB(as_SB(fSrc)->asFragmentProcessor(args)); 132 if (!fpB) { 133 return nullptr; 134 } 135 // TODO: account for fLerpT when it is < 1 136 return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), 137 std::move(fpA), fMode); 138 } 139 #endif 140