aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkComposeShader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/SkComposeShader.cpp')
-rw-r--r--src/core/SkComposeShader.cpp311
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