180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2006 The Android Open Source Project
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkComposeShader.h"
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkColorFilter.h"
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkColorPriv.h"
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkColorShader.h"
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkFlattenableBuffers.h"
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkXfermode.h"
16d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger#include "SkString.h"
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////////////////
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) {
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fShaderA = sA;  sA->ref();
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fShaderB = sB;  sB->ref();
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // mode may be null
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fMode = mode;
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkSafeRef(mode);
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkComposeShader::SkComposeShader(SkFlattenableReadBuffer& buffer) :
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    INHERITED(buffer) {
300a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    fShaderA = buffer.readShader();
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (NULL == fShaderA) {
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fShaderA = SkNEW_ARGS(SkColorShader, (0));
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
340a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    fShaderB = buffer.readShader();
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (NULL == fShaderB) {
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fShaderB = SkNEW_ARGS(SkColorShader, (0));
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
380a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    fMode = buffer.readXfermode();
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkComposeShader::~SkComposeShader() {
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkSafeUnref(fMode);
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fShaderB->unref();
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fShaderA->unref();
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass SkAutoAlphaRestore {
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic:
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fAlpha = paint->getAlpha();
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fPaint = paint;
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        paint->setAlpha(newAlpha);
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    ~SkAutoAlphaRestore() {
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fPaint->setAlpha(fAlpha);
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate:
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPaint*    fPaint;
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    uint8_t     fAlpha;
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru};
62910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger#define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore)
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkComposeShader::flatten(SkFlattenableWriteBuffer& buffer) const {
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->INHERITED::flatten(buffer);
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    buffer.writeFlattenable(fShaderA);
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    buffer.writeFlattenable(fShaderB);
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    buffer.writeFlattenable(fMode);
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*  We call setContext on our two worker shaders. However, we
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    always let them see opaque alpha, and if the paint really
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    is translucent, then we apply that after the fact.
74363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
75363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    We need to keep the calls to setContext/endContext balanced, since if we
76363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    return false, our endContext() will not be called.
77363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger */
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool SkComposeShader::setContext(const SkBitmap& device,
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                 const SkPaint& paint,
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                 const SkMatrix& matrix) {
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!this->INHERITED::setContext(device, paint, matrix)) {
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // we preconcat our localMatrix (if any) with the device matrix
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // before calling our sub-shaders
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkMatrix tmpM;
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
90363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    tmpM.setConcat(matrix, this->getLocalMatrix());
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkAutoAlphaRestore  restore(const_cast<SkPaint*>(&paint), 0xFF);
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
94363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    bool setContextA = fShaderA->setContext(device, paint, tmpM);
95363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    bool setContextB = fShaderB->setContext(device, paint, tmpM);
96363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if (!setContextA || !setContextB) {
97363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        if (setContextB) {
98363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            fShaderB->endContext();
99363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        }
100363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        else if (setContextA) {
101363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            fShaderA->endContext();
102363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        }
103363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        this->INHERITED::endContext();
104363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        return false;
105363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
106363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    return true;
107363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
108363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
109363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid SkComposeShader::endContext() {
110363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    fShaderB->endContext();
111363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    fShaderA->endContext();
112363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    this->INHERITED::endContext();
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// larger is better (fewer times we have to loop), but we shouldn't
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// take up too much stack-space (each element is 4 bytes)
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define TMP_COLOR_COUNT     64
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkShader*   shaderA = fShaderA;
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkShader*   shaderB = fShaderB;
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkXfermode* mode = fMode;
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    unsigned    scale = SkAlpha255To256(this->getPaintAlpha());
12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPMColor   tmp[TMP_COLOR_COUNT];
12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (NULL == mode) {   // implied SRC_OVER
12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // TODO: when we have a good test-case, should use SkBlitRow::Proc32
12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // for these loops
13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        do {
13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            int n = count;
13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (n > TMP_COLOR_COUNT) {
13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                n = TMP_COLOR_COUNT;
13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            shaderA->shadeSpan(x, y, result, n);
13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            shaderB->shadeSpan(x, y, tmp, n);
13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (256 == scale) {
14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                for (int i = 0; i < n; i++) {
14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    result[i] = SkPMSrcOver(tmp[i], result[i]);
14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                }
14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            } else {
14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                for (int i = 0; i < n; i++) {
14580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                            scale);
14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                }
14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            result += n;
15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            x += n;
15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            count -= n;
15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } while (count > 0);
15480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {    // use mode for the composition
15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        do {
15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            int n = count;
15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (n > TMP_COLOR_COUNT) {
15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                n = TMP_COLOR_COUNT;
15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            shaderA->shadeSpan(x, y, result, n);
16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            shaderB->shadeSpan(x, y, tmp, n);
16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            mode->xfer32(result, tmp, n, NULL);
16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (256 == scale) {
16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                for (int i = 0; i < n; i++) {
16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    result[i] = SkAlphaMulQ(result[i], scale);
16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                }
16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            result += n;
17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            x += n;
17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            count -= n;
17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } while (count > 0);
17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
177d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
178d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger#ifdef SK_DEVELOPER
179d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenbergervoid SkComposeShader::toString(SkString* str) const {
180d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append("SkComposeShader: (");
181d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
182d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append("ShaderA: ");
183d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    fShaderA->toString(str);
184d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append(" ShaderB: ");
185d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    fShaderB->toString(str);
186d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append(" Xfermode: ");
187096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    fMode->toString(str);
188d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
189d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    this->INHERITED::toString(str);
190d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
191d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append(")");
192d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger}
193d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger#endif
194