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