11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
21cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2006 The Android Open Source Project
41cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
71cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */
81cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkComposeShader.h"
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorFilter.h"
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorPriv.h"
131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#include "SkColorShader.h"
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkXfermode.h"
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
1740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek SollenbergerSkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) {
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fShaderA = sA;  sA->ref();
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fShaderB = sB;  sB->ref();
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // mode may be null
2240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    fMode = mode;
2340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkSafeRef(mode);
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkComposeShader::SkComposeShader(SkFlattenableReadBuffer& buffer) :
2740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    INHERITED(buffer) {
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fShaderA = static_cast<SkShader*>(buffer.readFlattenable());
291cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (NULL == fShaderA) {
301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fShaderA = SkNEW_ARGS(SkColorShader, (0));
311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fShaderB = static_cast<SkShader*>(buffer.readFlattenable());
331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (NULL == fShaderB) {
341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fShaderB = SkNEW_ARGS(SkColorShader, (0));
351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fMode = static_cast<SkXfermode*>(buffer.readFlattenable());
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek SollenbergerSkComposeShader::~SkComposeShader() {
4040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkSafeUnref(fMode);
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fShaderB->unref();
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fShaderA->unref();
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergervoid SkComposeShader::beginSession() {
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->INHERITED::beginSession();
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fShaderA->beginSession();
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fShaderB->beginSession();
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergervoid SkComposeShader::endSession() {
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fShaderA->endSession();
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fShaderB->endSession();
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->INHERITED::endSession();
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkAutoAlphaRestore {
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
5940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fAlpha = paint->getAlpha();
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fPaint = paint;
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        paint->setAlpha(newAlpha);
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
6540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    ~SkAutoAlphaRestore() {
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fPaint->setAlpha(fAlpha);
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate:
690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPaint*    fPaint;
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    uint8_t     fAlpha;
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergervoid SkComposeShader::flatten(SkFlattenableWriteBuffer& buffer) {
740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->INHERITED::flatten(buffer);
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.writeFlattenable(fShaderA);
760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.writeFlattenable(fShaderB);
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.writeFlattenable(fMode);
780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*  We call setContext on our two worker shaders. However, we
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    always let them see opaque alpha, and if the paint really
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    is translucent, then we apply that after the fact.
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkComposeShader::setContext(const SkBitmap& device,
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                 const SkPaint& paint,
8640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                 const SkMatrix& matrix) {
8740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    if (!this->INHERITED::setContext(device, paint, matrix)) {
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
8940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // we preconcat our localMatrix (if any) with the device matrix
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // before calling our sub-shaders
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix tmpM;
9540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    (void)this->getLocalMatrix(&tmpM);
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    tmpM.setConcat(matrix, tmpM);
9840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoAlphaRestore  restore(const_cast<SkPaint*>(&paint), 0xFF);
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return  fShaderA->setContext(device, paint, tmpM) &&
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fShaderB->setContext(device, paint, tmpM);
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// larger is better (fewer times we have to loop), but we shouldn't
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// take up too much stack-space (each element is 4 bytes)
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define TMP_COLOR_COUNT     64
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergervoid SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkShader*   shaderA = fShaderA;
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkShader*   shaderB = fShaderB;
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkXfermode* mode = fMode;
1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unsigned    scale = SkAlpha255To256(this->getPaintAlpha());
11440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPMColor   tmp[TMP_COLOR_COUNT];
1160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    if (NULL == mode) {   // implied SRC_OVER
118d0195f840fa964da51f7a1192b432954794e660cMike Reed        // TODO: when we have a good test-case, should use SkBlitRow::Proc32
119d0195f840fa964da51f7a1192b432954794e660cMike Reed        // for these loops
1200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        do {
1210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int n = count;
12240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            if (n > TMP_COLOR_COUNT) {
1230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                n = TMP_COLOR_COUNT;
12440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            }
12540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            shaderA->shadeSpan(x, y, result, n);
1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            shaderB->shadeSpan(x, y, tmp, n);
1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            if (256 == scale) {
13040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                for (int i = 0; i < n; i++) {
1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    result[i] = SkPMSrcOver(tmp[i], result[i]);
13240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                }
13340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            } else {
13440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                for (int i = 0; i < n; i++) {
13540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                    result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
13640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                            scale);
13740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                }
1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
13940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            result += n;
1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            x += n;
1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            count -= n;
1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } while (count > 0);
14440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    } else {    // use mode for the composition
1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        do {
1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int n = count;
14740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            if (n > TMP_COLOR_COUNT) {
1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                n = TMP_COLOR_COUNT;
14940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            }
15040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            shaderA->shadeSpan(x, y, result, n);
1520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            shaderB->shadeSpan(x, y, tmp, n);
1530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            mode->xfer32(result, tmp, n, NULL);
1540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            if (256 == scale) {
15640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                for (int i = 0; i < n; i++) {
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    result[i] = SkAlphaMulQ(result[i], scale);
15840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                }
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            result += n;
1620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            x += n;
1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            count -= n;
1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } while (count > 0);
1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
16740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
168