/*
|
* 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
|