SkComposeShader.cpp revision c4cae85752e3e486cf4eac8cd8128f57b6f40563
1/* libs/graphics/effects/SkShaderExtras.cpp 2** 3** Copyright 2006, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18#include "SkComposeShader.h" 19#include "SkColorFilter.h" 20#include "SkColorPriv.h" 21#include "SkXfermode.h" 22 23////////////////////////////////////////////////////////////////////////////////////// 24 25SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) 26{ 27 fShaderA = sA; sA->ref(); 28 fShaderB = sB; sB->ref(); 29 // mode may be null 30 fMode = mode; mode->safeRef(); 31} 32 33SkComposeShader::SkComposeShader(SkFlattenableReadBuffer& buffer) : 34 INHERITED(buffer) 35{ 36 fShaderA = static_cast<SkShader*>(buffer.readFlattenable()); 37 fShaderB = static_cast<SkShader*>(buffer.readFlattenable()); 38 fMode = static_cast<SkXfermode*>(buffer.readFlattenable()); 39} 40 41SkComposeShader::~SkComposeShader() 42{ 43 fMode->safeUnref(); // may be null 44 fShaderB->unref(); 45 fShaderA->unref(); 46} 47 48void SkComposeShader::beginSession() 49{ 50 this->INHERITED::beginSession(); 51 fShaderA->beginSession(); 52 fShaderB->beginSession(); 53} 54 55void SkComposeShader::endSession() 56{ 57 fShaderA->endSession(); 58 fShaderB->endSession(); 59 this->INHERITED::endSession(); 60} 61 62class SkAutoAlphaRestore { 63public: 64 SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) 65 { 66 fAlpha = paint->getAlpha(); 67 fPaint = paint; 68 paint->setAlpha(newAlpha); 69 } 70 ~SkAutoAlphaRestore() 71 { 72 fPaint->setAlpha(fAlpha); 73 } 74private: 75 SkPaint* fPaint; 76 uint8_t fAlpha; 77}; 78 79void SkComposeShader::flatten(SkFlattenableWriteBuffer& buffer) 80{ 81 this->INHERITED::flatten(buffer); 82 buffer.writeFlattenable(fShaderA); 83 buffer.writeFlattenable(fShaderB); 84 buffer.writeFlattenable(fMode); 85} 86 87/* We call setContext on our two worker shaders. However, we 88 always let them see opaque alpha, and if the paint really 89 is translucent, then we apply that after the fact. 90*/ 91bool SkComposeShader::setContext(const SkBitmap& device, 92 const SkPaint& paint, 93 const SkMatrix& matrix) 94{ 95 if (!this->INHERITED::setContext(device, paint, matrix)) 96 return false; 97 98 // we preconcat our localMatrix (if any) with the device matrix 99 // before calling our sub-shaders 100 101 SkMatrix tmpM; 102 103 (void)this->getLocalMatrix(&tmpM); 104 tmpM.setConcat(matrix, tmpM); 105 106 SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF); 107 108 return fShaderA->setContext(device, paint, tmpM) && 109 fShaderB->setContext(device, paint, tmpM); 110} 111 112// larger is better (fewer times we have to loop), but we shouldn't 113// take up too much stack-space (each element is 4 bytes) 114#define TMP_COLOR_COUNT 64 115 116void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) 117{ 118 SkShader* shaderA = fShaderA; 119 SkShader* shaderB = fShaderB; 120 SkXfermode* mode = fMode; 121 unsigned scale = SkAlpha255To256(this->getPaintAlpha()); 122 123 SkPMColor tmp[TMP_COLOR_COUNT]; 124 125 if (NULL == mode) // implied SRC_OVER 126 { 127 // TODO: when we have a good test-case, should use SkBlitRow::Proc32 128 // for these loops 129 do { 130 int n = count; 131 if (n > TMP_COLOR_COUNT) 132 n = TMP_COLOR_COUNT; 133 134 shaderA->shadeSpan(x, y, result, n); 135 shaderB->shadeSpan(x, y, tmp, n); 136 137 if (256 == scale) 138 { 139 for (int i = 0; i < n; i++) 140 result[i] = SkPMSrcOver(tmp[i], result[i]); 141 } 142 else 143 { 144 for (int i = 0; i < n; i++) 145 result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), scale); 146 } 147 148 result += n; 149 x += n; 150 count -= n; 151 } while (count > 0); 152 } 153 else // use mode for the composition 154 { 155 do { 156 int n = count; 157 if (n > TMP_COLOR_COUNT) 158 n = TMP_COLOR_COUNT; 159 160 shaderA->shadeSpan(x, y, result, n); 161 shaderB->shadeSpan(x, y, tmp, n); 162 mode->xfer32(result, tmp, n, NULL); 163 164 if (256 == scale) 165 { 166 for (int i = 0; i < n; i++) 167 result[i] = SkAlphaMulQ(result[i], scale); 168 } 169 170 result += n; 171 x += n; 172 count -= n; 173 } while (count > 0); 174 } 175} 176 177