/* * Copyright 2006 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkArenaAlloc.h" #include "SkBlendModePriv.h" #include "SkComposeShader.h" #include "SkColorFilter.h" #include "SkColorData.h" #include "SkColorShader.h" #include "SkRasterPipeline.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkString.h" sk_sp<SkShader> SkShader::MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode, float lerpT) { if (!src || !dst || SkScalarIsNaN(lerpT)) { return nullptr; } lerpT = SkScalarPin(lerpT, 0, 1); if (lerpT == 0) { return dst; } else if (lerpT == 1) { if (mode == SkBlendMode::kSrc) { return src; } if (mode == SkBlendMode::kDst) { return dst; } } return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode, lerpT)); } /////////////////////////////////////////////////////////////////////////////// sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) { sk_sp<SkShader> dst(buffer.readShader()); sk_sp<SkShader> src(buffer.readShader()); unsigned mode = buffer.read32(); float lerp = buffer.readScalar(); // check for valid mode before we cast to the enum type if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) { return nullptr; } return MakeCompose(std::move(dst), std::move(src), static_cast<SkBlendMode>(mode), lerp); } void SkComposeShader::flatten(SkWriteBuffer& buffer) const { buffer.writeFlattenable(fDst.get()); buffer.writeFlattenable(fSrc.get()); buffer.write32((int)fMode); buffer.writeScalar(fLerpT); } sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const { return MakeCompose(xformer->apply(fDst.get()), xformer->apply(fSrc.get()), fMode, fLerpT); } #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK bool SkComposeShader::asACompose(ComposeRec* rec) const { if (!this->isJustMode()) { return false; } if (rec) { rec->fShaderA = fDst.get(); rec->fShaderB = fSrc.get(); rec->fBlendMode = fMode; } return true; } #endif bool SkComposeShader::onAppendStages(const StageRec& rec) const { struct Storage { float fRGBA[4 * SkRasterPipeline_kMaxStride]; float fAlpha; }; auto storage = rec.fAlloc->make<Storage>(); if (!as_SB(fDst)->appendStages(rec)) { return false; } // This outputs r,g,b,a, which we'll need later when we apply the mode, so we save it off now rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRGBA); if (!as_SB(fSrc)->appendStages(rec)) { return false; } // r,g,b,a now have the right input for the next step (lerp and/or mode), but we need to // reload dr,dg,db,da from memory, since we stashed that from our fDst invocation earlier. rec.fPipeline->append(SkRasterPipeline::load_dst, storage->fRGBA); if (!this->isJustLerp()) { SkBlendMode_AppendStages(fMode, rec.fPipeline); } if (!this->isJustMode()) { rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fLerpT); } return true; } #if SK_SUPPORT_GPU #include "effects/GrConstColorProcessor.h" #include "effects/GrXfermodeFragmentProcessor.h" ///////////////////////////////////////////////////////////////////// std::unique_ptr<GrFragmentProcessor> SkComposeShader::asFragmentProcessor( const GrFPArgs& args) const { if (this->isJustMode()) { SkASSERT(fMode != SkBlendMode::kSrc && fMode != SkBlendMode::kDst); // caught in factory if (fMode == SkBlendMode::kClear) { return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT, GrConstColorProcessor::InputMode::kIgnore); } } std::unique_ptr<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args)); if (!fpA) { return nullptr; } std::unique_ptr<GrFragmentProcessor> fpB(as_SB(fSrc)->asFragmentProcessor(args)); if (!fpB) { return nullptr; } // TODO: account for fLerpT when it is < 1 return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), std::move(fpA), fMode); } #endif