diff options
Diffstat (limited to 'src/core/SkComposeShader.cpp')
-rw-r--r-- | src/core/SkComposeShader.cpp | 311 |
1 files changed, 0 insertions, 311 deletions
diff --git a/src/core/SkComposeShader.cpp b/src/core/SkComposeShader.cpp deleted file mode 100644 index 7735494291..0000000000 --- a/src/core/SkComposeShader.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/* - * 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 "SkColorPriv.h" -#include "SkColorShader.h" -#include "SkRasterPipeline.h" -#include "SkReadBuffer.h" -#include "SkWriteBuffer.h" -#include "SkString.h" -#include "../jumper/SkJumper.h" - -sk_sp<SkShader> SkShader::MakeComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src, - SkBlendMode mode) { - if (!src || !dst) { - return nullptr; - } - if (SkBlendMode::kSrc == mode) { - return src; - } - if (SkBlendMode::kDst == mode) { - return dst; - } - return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode)); -} - -/////////////////////////////////////////////////////////////////////////////// - -class SkAutoAlphaRestore { -public: - SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) { - fAlpha = paint->getAlpha(); - fPaint = paint; - paint->setAlpha(newAlpha); - } - - ~SkAutoAlphaRestore() { - fPaint->setAlpha(fAlpha); - } -private: - SkPaint* fPaint; - uint8_t fAlpha; -}; -#define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore) - -sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) { - sk_sp<SkShader> shaderA(buffer.readShader()); - sk_sp<SkShader> shaderB(buffer.readShader()); - SkBlendMode mode; - if (buffer.isVersionLT(SkReadBuffer::kXfermodeToBlendMode2_Version)) { - sk_sp<SkXfermode> xfer = buffer.readXfermode(); - mode = xfer ? xfer->blend() : SkBlendMode::kSrcOver; - } else { - mode = (SkBlendMode)buffer.read32(); - } - if (!shaderA || !shaderB) { - return nullptr; - } - return sk_make_sp<SkComposeShader>(std::move(shaderA), std::move(shaderB), mode); -} - -void SkComposeShader::flatten(SkWriteBuffer& buffer) const { - buffer.writeFlattenable(fShaderA.get()); - buffer.writeFlattenable(fShaderB.get()); - buffer.write32((int)fMode); -} - -SkShaderBase::Context* SkComposeShader::onMakeContext( - const ContextRec& rec, SkArenaAlloc* alloc) const -{ - // we preconcat our localMatrix (if any) with the device matrix - // before calling our sub-shaders - SkMatrix tmpM; - tmpM.setConcat(*rec.fMatrix, this->getLocalMatrix()); - - // Our sub-shaders need to see opaque, so by combining them we don't double-alphatize the - // result. ComposeShader itself will respect the alpha, and post-apply it after calling the - // sub-shaders. - SkPaint opaquePaint(*rec.fPaint); - opaquePaint.setAlpha(0xFF); - - ContextRec newRec(rec); - newRec.fMatrix = &tmpM; - newRec.fPaint = &opaquePaint; - - SkShaderBase::Context* contextA = as_SB(fShaderA)->makeContext(newRec, alloc); - SkShaderBase::Context* contextB = as_SB(fShaderB)->makeContext(newRec, alloc); - if (!contextA || !contextB) { - return nullptr; - } - - return alloc->make<ComposeShaderContext>(*this, rec, contextA, contextB); -} - -sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const { - return SkShader::MakeComposeShader(xformer->apply(fShaderA.get()), - xformer->apply(fShaderB.get()), fMode); -} - -SkComposeShader::ComposeShaderContext::ComposeShaderContext( - const SkComposeShader& shader, const ContextRec& rec, - SkShaderBase::Context* contextA, SkShaderBase::Context* contextB) - : INHERITED(shader, rec) - , fShaderContextA(contextA) - , fShaderContextB(contextB) {} - -bool SkComposeShader::asACompose(ComposeRec* rec) const { - if (rec) { - rec->fShaderA = fShaderA.get(); - rec->fShaderB = fShaderB.get(); - rec->fBlendMode = fMode; - } - return true; -} - -bool SkComposeShader::isRasterPipelineOnly() const { - return as_SB(fShaderA)->isRasterPipelineOnly() || as_SB(fShaderB)->isRasterPipelineOnly(); -} - -bool SkComposeShader::onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* dstCS, - SkArenaAlloc* alloc, const SkMatrix& ctm, - const SkPaint& paint, const SkMatrix* localM) const { - struct Storage { - float fXY[4 * SkJumper_kMaxStride]; - float fRGBA[4 * SkJumper_kMaxStride]; - float fAlpha; - }; - auto storage = alloc->make<Storage>(); - - // We need to save off device x,y (inputs to shader), since after calling fShaderA they - // will be smashed, and I'll need them again for fShaderB. store_rgba saves off 4 registers - // even though we only need to save r,g. - pipeline->append(SkRasterPipeline::store_rgba, storage->fXY); - if (!as_SB(fShaderB)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) { // SRC - return false; - } - // This outputs r,g,b,a, which we'll need later when we apply the mode, but we save it off now - // since fShaderB will overwrite them. - pipeline->append(SkRasterPipeline::store_rgba, storage->fRGBA); - // Now we restore the device x,y for the next shader - pipeline->append(SkRasterPipeline::load_rgba, storage->fXY); - if (!as_SB(fShaderA)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) { // DST - return false; - } - // We now have our logical 'dst' in r,g,b,a, but we need it in dr,dg,db,da for the mode - // so we have to shuttle them. If we had a stage the would load_into_dst, then we could - // reverse the two shader invocations, and avoid this move... - pipeline->append(SkRasterPipeline::move_src_dst); - pipeline->append(SkRasterPipeline::load_rgba, storage->fRGBA); - - // Idea: should time this, and see if it helps to have custom versions of the overflow modes - // that do their own clamping, avoiding the overhead of an extra stage. - SkBlendMode_AppendStages(fMode, pipeline); - if (SkBlendMode_CanOverflow(fMode)) { - pipeline->append(SkRasterPipeline::clamp_a); - } - return true; -} - -// larger is better (fewer times we have to loop), but we shouldn't -// take up too much stack-space (each element is 4 bytes) -#define TMP_COLOR_COUNT 64 - -void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { - auto* shaderContextA = fShaderContextA; - auto* shaderContextB = fShaderContextB; - SkBlendMode mode = static_cast<const SkComposeShader&>(fShader).fMode; - unsigned scale = SkAlpha255To256(this->getPaintAlpha()); - - SkPMColor tmp[TMP_COLOR_COUNT]; - - SkXfermode* xfer = SkXfermode::Peek(mode); - if (nullptr == xfer) { // implied SRC_OVER - // TODO: when we have a good test-case, should use SkBlitRow::Proc32 - // for these loops - do { - int n = count; - if (n > TMP_COLOR_COUNT) { - n = TMP_COLOR_COUNT; - } - - shaderContextA->shadeSpan(x, y, result, n); - shaderContextB->shadeSpan(x, y, tmp, n); - - if (256 == scale) { - for (int i = 0; i < n; i++) { - result[i] = SkPMSrcOver(tmp[i], result[i]); - } - } else { - for (int i = 0; i < n; i++) { - result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), - scale); - } - } - - result += n; - x += n; - count -= n; - } while (count > 0); - } else { // use mode for the composition - do { - int n = count; - if (n > TMP_COLOR_COUNT) { - n = TMP_COLOR_COUNT; - } - - shaderContextA->shadeSpan(x, y, result, n); - shaderContextB->shadeSpan(x, y, tmp, n); - xfer->xfer32(result, tmp, n, nullptr); - - if (256 != scale) { - for (int i = 0; i < n; i++) { - result[i] = SkAlphaMulQ(result[i], scale); - } - } - - result += n; - x += n; - count -= n; - } while (count > 0); - } -} - -void SkComposeShader::ComposeShaderContext::shadeSpan4f(int x, int y, SkPM4f result[], int count) { - auto* shaderContextA = fShaderContextA; - auto* shaderContextB = fShaderContextB; - SkBlendMode mode = static_cast<const SkComposeShader&>(fShader).fMode; - unsigned alpha = this->getPaintAlpha(); - Sk4f scale(alpha * (1.0f / 255)); - - SkPM4f tmp[TMP_COLOR_COUNT]; - - SkXfermodeProc4f xfer = SkXfermode::GetProc4f(mode); - do { - int n = SkTMin(count, TMP_COLOR_COUNT); - - shaderContextA->shadeSpan4f(x, y, result, n); - shaderContextB->shadeSpan4f(x, y, tmp, n); - if (255 == alpha) { - for (int i = 0; i < n; ++i) { - result[i] = xfer(tmp[i], result[i]); - } - } else { - for (int i = 0; i < n; ++i) { - (xfer(tmp[i], result[i]).to4f() * scale).store(result + i); - } - } - result += n; - x += n; - count -= n; - } while (count > 0); -} - -#if SK_SUPPORT_GPU - -#include "effects/GrConstColorProcessor.h" -#include "effects/GrXfermodeFragmentProcessor.h" - -///////////////////////////////////////////////////////////////////// - -sk_sp<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(const AsFPArgs& args) const { - switch (fMode) { - case SkBlendMode::kClear: - return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), - GrConstColorProcessor::kIgnore_InputMode); - break; - case SkBlendMode::kSrc: - return as_SB(fShaderB)->asFragmentProcessor(args); - break; - case SkBlendMode::kDst: - return as_SB(fShaderA)->asFragmentProcessor(args); - break; - default: - sk_sp<GrFragmentProcessor> fpA(as_SB(fShaderA)->asFragmentProcessor(args)); - if (!fpA) { - return nullptr; - } - sk_sp<GrFragmentProcessor> fpB(as_SB(fShaderB)->asFragmentProcessor(args)); - if (!fpB) { - return nullptr; - } - return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), - std::move(fpA), fMode); - } -} -#endif - -#ifndef SK_IGNORE_TO_STRING -void SkComposeShader::toString(SkString* str) const { - str->append("SkComposeShader: ("); - - str->append("ShaderA: "); - as_SB(fShaderA)->toString(str); - str->append(" ShaderB: "); - as_SB(fShaderB)->toString(str); - if (SkBlendMode::kSrcOver != fMode) { - str->appendf(" Xfermode: %s", SkXfermode::ModeName(fMode)); - } - - this->INHERITED::toString(str); - - str->append(")"); -} -#endif |