1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
883e939bcb79790f5ae3b28c398fbcf034675a6e5Herb Derby#include "SkArenaAlloc.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkComposeShader.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorFilter.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
12573f22b3bd295bb2e3b9e6ab41f5dfeb557897f9reed@google.com#include "SkColorShader.h"
138b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
148b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
1576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com#include "SkString.h"
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
177d954ad797176afedb9262fdea4507d0fc60eb9dMike Reedsk_sp<SkShader> SkShader::MakeComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src,
187d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed                                            SkBlendMode mode) {
197d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    if (!src || !dst) {
207d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        return nullptr;
217d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    }
227d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    if (SkBlendMode::kSrc == mode) {
237d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        return src;
247d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    }
257d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    if (SkBlendMode::kDst == mode) {
267d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        return dst;
277d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    }
287d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode));
297d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed}
307d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed
3182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com///////////////////////////////////////////////////////////////////////////////
3282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkAutoAlphaRestore {
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
3582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fAlpha = paint->getAlpha();
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fPaint = paint;
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        paint->setAlpha(newAlpha);
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
4182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    ~SkAutoAlphaRestore() {
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fPaint->setAlpha(fAlpha);
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPaint*    fPaint;
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint8_t     fAlpha;
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
48e61a86cfa00ea393ecc4a71fca94e1d476a37ecccommit-bot@chromium.org#define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore)
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5060c9b58b3214b0154c931656e91e39b230e987d8reedsk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) {
518a21c9fe7f5fef9e87115defef27bd7218419f28reed    sk_sp<SkShader> shaderA(buffer.readShader());
528a21c9fe7f5fef9e87115defef27bd7218419f28reed    sk_sp<SkShader> shaderB(buffer.readShader());
537d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    SkBlendMode mode;
547d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    if (buffer.isVersionLT(SkReadBuffer::kXfermodeToBlendMode2_Version)) {
557d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        sk_sp<SkXfermode> xfer = buffer.readXfermode();
567d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        mode = xfer ? xfer->blend() : SkBlendMode::kSrcOver;
577d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    } else {
587d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        mode = (SkBlendMode)buffer.read32();
597d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    }
608a21c9fe7f5fef9e87115defef27bd7218419f28reed    if (!shaderA || !shaderB) {
6196fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
629fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
637d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    return sk_make_sp<SkComposeShader>(std::move(shaderA), std::move(shaderB), mode);
649fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
659fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
668b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkComposeShader::flatten(SkWriteBuffer& buffer) const {
678a21c9fe7f5fef9e87115defef27bd7218419f28reed    buffer.writeFlattenable(fShaderA.get());
688a21c9fe7f5fef9e87115defef27bd7218419f28reed    buffer.writeFlattenable(fShaderB.get());
697d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    buffer.write32((int)fMode);
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7283e939bcb79790f5ae3b28c398fbcf034675a6e5Herb DerbySkShader::Context* SkComposeShader::onMakeContext(
7383e939bcb79790f5ae3b28c398fbcf034675a6e5Herb Derby    const ContextRec& rec, SkArenaAlloc* alloc) const
7483e939bcb79790f5ae3b28c398fbcf034675a6e5Herb Derby{
75e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    // we preconcat our localMatrix (if any) with the device matrix
76e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    // before calling our sub-shaders
77e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    SkMatrix tmpM;
78e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    tmpM.setConcat(*rec.fMatrix, this->getLocalMatrix());
799a40803f2bc0ed14c30bdd2213945b01d9c4c977skia.committer@gmail.com
801ab536f16164795782a75b11efcb17541cbc2e26commit-bot@chromium.org    // Our sub-shaders need to see opaque, so by combining them we don't double-alphatize the
811ab536f16164795782a75b11efcb17541cbc2e26commit-bot@chromium.org    // result. ComposeShader itself will respect the alpha, and post-apply it after calling the
821ab536f16164795782a75b11efcb17541cbc2e26commit-bot@chromium.org    // sub-shaders.
831ab536f16164795782a75b11efcb17541cbc2e26commit-bot@chromium.org    SkPaint opaquePaint(*rec.fPaint);
841ab536f16164795782a75b11efcb17541cbc2e26commit-bot@chromium.org    opaquePaint.setAlpha(0xFF);
85edda70e020630103270c815b7499e8b02271875dskia.committer@gmail.com
86e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    ContextRec newRec(rec);
87e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    newRec.fMatrix = &tmpM;
881ab536f16164795782a75b11efcb17541cbc2e26commit-bot@chromium.org    newRec.fPaint = &opaquePaint;
89e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org
9083e939bcb79790f5ae3b28c398fbcf034675a6e5Herb Derby    SkShader::Context* contextA = fShaderA->makeContext(newRec, alloc);
9183e939bcb79790f5ae3b28c398fbcf034675a6e5Herb Derby    SkShader::Context* contextB = fShaderB->makeContext(newRec, alloc);
92ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org    if (!contextA || !contextB) {
9396fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
94ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org    }
9587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
9683e939bcb79790f5ae3b28c398fbcf034675a6e5Herb Derby    return alloc->make<ComposeShaderContext>(*this, rec, contextA, contextB);
97a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com}
98a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com
9987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkComposeShader::ComposeShaderContext::ComposeShaderContext(
100e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org        const SkComposeShader& shader, const ContextRec& rec,
10187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        SkShader::Context* contextA, SkShader::Context* contextB)
102e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    : INHERITED(shader, rec)
10387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    , fShaderContextA(contextA)
10487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    , fShaderContextB(contextB) {}
10587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
106795905562d1bd8bbedcf47f6a00efb220ec8bbe0commit-bot@chromium.orgbool SkComposeShader::asACompose(ComposeRec* rec) const {
107795905562d1bd8bbedcf47f6a00efb220ec8bbe0commit-bot@chromium.org    if (rec) {
108faba3715b8ddfaa0ce4df79bc8006e9bc7694e5bMike Reed        rec->fShaderA   = fShaderA.get();
109faba3715b8ddfaa0ce4df79bc8006e9bc7694e5bMike Reed        rec->fShaderB   = fShaderB.get();
1107d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        rec->fBlendMode = fMode;
111795905562d1bd8bbedcf47f6a00efb220ec8bbe0commit-bot@chromium.org    }
112795905562d1bd8bbedcf47f6a00efb220ec8bbe0commit-bot@chromium.org    return true;
113795905562d1bd8bbedcf47f6a00efb220ec8bbe0commit-bot@chromium.org}
114795905562d1bd8bbedcf47f6a00efb220ec8bbe0commit-bot@chromium.org
115795905562d1bd8bbedcf47f6a00efb220ec8bbe0commit-bot@chromium.org
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// larger is better (fewer times we have to loop), but we shouldn't
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// take up too much stack-space (each element is 4 bytes)
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define TMP_COLOR_COUNT     64
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
12187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    SkShader::Context* shaderContextA = fShaderContextA;
12287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    SkShader::Context* shaderContextB = fShaderContextB;
1237d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    SkBlendMode        mode = static_cast<const SkComposeShader&>(fShader).fMode;
12487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    unsigned           scale = SkAlpha255To256(this->getPaintAlpha());
12582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPMColor   tmp[TMP_COLOR_COUNT];
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1287d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    SkXfermode* xfer = SkXfermode::Peek(mode);
1297d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    if (nullptr == xfer) {   // implied SRC_OVER
130c4cae85752e3e486cf4eac8cd8128f57b6f40563reed@android.com        // TODO: when we have a good test-case, should use SkBlitRow::Proc32
131c4cae85752e3e486cf4eac8cd8128f57b6f40563reed@android.com        // for these loops
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int n = count;
13482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            if (n > TMP_COLOR_COUNT) {
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                n = TMP_COLOR_COUNT;
13682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            }
13782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
13887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            shaderContextA->shadeSpan(x, y, result, n);
13987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            shaderContextB->shadeSpan(x, y, tmp, n);
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            if (256 == scale) {
14282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                for (int i = 0; i < n; i++) {
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    result[i] = SkPMSrcOver(tmp[i], result[i]);
14482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                }
14582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            } else {
14682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                for (int i = 0; i < n; i++) {
14782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                    result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
14882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                                            scale);
14982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                }
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
15182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            result += n;
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            x += n;
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            count -= n;
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } while (count > 0);
15682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    } else {    // use mode for the composition
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int n = count;
15982065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            if (n > TMP_COLOR_COUNT) {
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                n = TMP_COLOR_COUNT;
16182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            }
16282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
16387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            shaderContextA->shadeSpan(x, y, result, n);
16487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            shaderContextB->shadeSpan(x, y, tmp, n);
1657d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed            xfer->xfer32(result, tmp, n, nullptr);
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1671ab536f16164795782a75b11efcb17541cbc2e26commit-bot@chromium.org            if (256 != scale) {
16882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                for (int i = 0; i < n; i++) {
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    result[i] = SkAlphaMulQ(result[i], scale);
17082065d667f64e232bcde2ad849756a6096fcbe6freed@google.com                }
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            result += n;
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            x += n;
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            count -= n;
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } while (count > 0);
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
17976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
18073fa61670d95c52250a660a2cec618ab77716934wangyix#if SK_SUPPORT_GPU
18173fa61670d95c52250a660a2cec618ab77716934wangyix
182036fd8e6f66b53cf87a5f91083cae82f0aeb3635wangyix#include "effects/GrConstColorProcessor.h"
183809e5afdd95962465a51e3dbab707abf9d594fabwangyix#include "effects/GrXfermodeFragmentProcessor.h"
18473fa61670d95c52250a660a2cec618ab77716934wangyix
18573fa61670d95c52250a660a2cec618ab77716934wangyix/////////////////////////////////////////////////////////////////////
18673fa61670d95c52250a660a2cec618ab77716934wangyix
187839345d63466a4209a0985654ec033624821fd78brianosmansk_sp<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(const AsFPArgs& args) const {
1887d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    switch (fMode) {
1897d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        case SkBlendMode::kClear:
190618d304eb394d64779be0ecdc5eff898242faa8fBrian Osman            return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
19106ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman                                               GrConstColorProcessor::kIgnore_InputMode);
19273fa61670d95c52250a660a2cec618ab77716934wangyix            break;
1937d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        case SkBlendMode::kSrc:
194839345d63466a4209a0985654ec033624821fd78brianosman            return fShaderB->asFragmentProcessor(args);
19573fa61670d95c52250a660a2cec618ab77716934wangyix            break;
1967d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        case SkBlendMode::kDst:
197839345d63466a4209a0985654ec033624821fd78brianosman            return fShaderA->asFragmentProcessor(args);
19873fa61670d95c52250a660a2cec618ab77716934wangyix            break;
19973fa61670d95c52250a660a2cec618ab77716934wangyix        default:
200839345d63466a4209a0985654ec033624821fd78brianosman            sk_sp<GrFragmentProcessor> fpA(fShaderA->asFragmentProcessor(args));
20106ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman            if (!fpA) {
20273fa61670d95c52250a660a2cec618ab77716934wangyix                return nullptr;
20373fa61670d95c52250a660a2cec618ab77716934wangyix            }
204839345d63466a4209a0985654ec033624821fd78brianosman            sk_sp<GrFragmentProcessor> fpB(fShaderB->asFragmentProcessor(args));
20506ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman            if (!fpB) {
20673fa61670d95c52250a660a2cec618ab77716934wangyix                return nullptr;
20773fa61670d95c52250a660a2cec618ab77716934wangyix            }
20806ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman            return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
2097d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed                                                                      std::move(fpA), fMode);
21073fa61670d95c52250a660a2cec618ab77716934wangyix    }
21173fa61670d95c52250a660a2cec618ab77716934wangyix}
21273fa61670d95c52250a660a2cec618ab77716934wangyix#endif
21373fa61670d95c52250a660a2cec618ab77716934wangyix
2140f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
21576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.comvoid SkComposeShader::toString(SkString* str) const {
21676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append("SkComposeShader: (");
21776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
21876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append("ShaderA: ");
21976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    fShaderA->toString(str);
22076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(" ShaderB: ");
22176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    fShaderB->toString(str);
2227d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    if (SkBlendMode::kSrcOver != fMode) {
2237d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        str->appendf(" Xfermode: %s", SkXfermode::ModeName(fMode));
2248464a960b83e3577bfa419693b3b27dfad82c8c8halcanary    }
22576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
22676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    this->INHERITED::toString(str);
22776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
22876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(")");
22976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com}
23076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com#endif
231