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