SkComposeShader.cpp revision e61a86cfa00ea393ecc4a71fca94e1d476a37ecc
1 2/* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10#include "SkComposeShader.h" 11#include "SkColorFilter.h" 12#include "SkColorPriv.h" 13#include "SkColorShader.h" 14#include "SkFlattenableBuffers.h" 15#include "SkXfermode.h" 16#include "SkString.h" 17 18/////////////////////////////////////////////////////////////////////////////// 19 20SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) { 21 fShaderA = sA; sA->ref(); 22 fShaderB = sB; sB->ref(); 23 // mode may be null 24 fMode = mode; 25 SkSafeRef(mode); 26} 27 28SkComposeShader::SkComposeShader(SkFlattenableReadBuffer& buffer) : 29 INHERITED(buffer) { 30 fShaderA = buffer.readShader(); 31 if (NULL == fShaderA) { 32 fShaderA = SkNEW_ARGS(SkColorShader, (0)); 33 } 34 fShaderB = buffer.readShader(); 35 if (NULL == fShaderB) { 36 fShaderB = SkNEW_ARGS(SkColorShader, (0)); 37 } 38 fMode = buffer.readXfermode(); 39} 40 41SkComposeShader::~SkComposeShader() { 42 SkSafeUnref(fMode); 43 fShaderB->unref(); 44 fShaderA->unref(); 45} 46 47class SkAutoAlphaRestore { 48public: 49 SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) { 50 fAlpha = paint->getAlpha(); 51 fPaint = paint; 52 paint->setAlpha(newAlpha); 53 } 54 55 ~SkAutoAlphaRestore() { 56 fPaint->setAlpha(fAlpha); 57 } 58private: 59 SkPaint* fPaint; 60 uint8_t fAlpha; 61}; 62#define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore) 63 64void SkComposeShader::flatten(SkFlattenableWriteBuffer& buffer) const { 65 this->INHERITED::flatten(buffer); 66 buffer.writeFlattenable(fShaderA); 67 buffer.writeFlattenable(fShaderB); 68 buffer.writeFlattenable(fMode); 69} 70 71/* We call setContext on our two worker shaders. However, we 72 always let them see opaque alpha, and if the paint really 73 is translucent, then we apply that after the fact. 74 75 We need to keep the calls to setContext/endContext balanced, since if we 76 return false, our endContext() will not be called. 77 */ 78bool SkComposeShader::setContext(const SkBitmap& device, 79 const SkPaint& paint, 80 const SkMatrix& matrix) { 81 if (!this->INHERITED::setContext(device, paint, matrix)) { 82 return false; 83 } 84 85 // we preconcat our localMatrix (if any) with the device matrix 86 // before calling our sub-shaders 87 88 SkMatrix tmpM; 89 90 tmpM.setConcat(matrix, this->getLocalMatrix()); 91 92 SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF); 93 94 bool setContextA = fShaderA->setContext(device, paint, tmpM); 95 bool setContextB = fShaderB->setContext(device, paint, tmpM); 96 if (!setContextA || !setContextB) { 97 if (setContextB) { 98 fShaderB->endContext(); 99 } 100 else if (setContextA) { 101 fShaderA->endContext(); 102 } 103 this->INHERITED::endContext(); 104 return false; 105 } 106 return true; 107} 108 109void SkComposeShader::endContext() { 110 fShaderB->endContext(); 111 fShaderA->endContext(); 112 this->INHERITED::endContext(); 113} 114 115// larger is better (fewer times we have to loop), but we shouldn't 116// take up too much stack-space (each element is 4 bytes) 117#define TMP_COLOR_COUNT 64 118 119void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) { 120 SkShader* shaderA = fShaderA; 121 SkShader* shaderB = fShaderB; 122 SkXfermode* mode = fMode; 123 unsigned scale = SkAlpha255To256(this->getPaintAlpha()); 124 125 SkPMColor tmp[TMP_COLOR_COUNT]; 126 127 if (NULL == mode) { // implied SRC_OVER 128 // TODO: when we have a good test-case, should use SkBlitRow::Proc32 129 // for these loops 130 do { 131 int n = count; 132 if (n > TMP_COLOR_COUNT) { 133 n = TMP_COLOR_COUNT; 134 } 135 136 shaderA->shadeSpan(x, y, result, n); 137 shaderB->shadeSpan(x, y, tmp, n); 138 139 if (256 == scale) { 140 for (int i = 0; i < n; i++) { 141 result[i] = SkPMSrcOver(tmp[i], result[i]); 142 } 143 } else { 144 for (int i = 0; i < n; i++) { 145 result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), 146 scale); 147 } 148 } 149 150 result += n; 151 x += n; 152 count -= n; 153 } while (count > 0); 154 } else { // use mode for the composition 155 do { 156 int n = count; 157 if (n > TMP_COLOR_COUNT) { 158 n = TMP_COLOR_COUNT; 159 } 160 161 shaderA->shadeSpan(x, y, result, n); 162 shaderB->shadeSpan(x, y, tmp, n); 163 mode->xfer32(result, tmp, n, NULL); 164 165 if (256 == scale) { 166 for (int i = 0; i < n; i++) { 167 result[i] = SkAlphaMulQ(result[i], scale); 168 } 169 } 170 171 result += n; 172 x += n; 173 count -= n; 174 } while (count > 0); 175 } 176} 177 178#ifdef SK_DEVELOPER 179void SkComposeShader::toString(SkString* str) const { 180 str->append("SkComposeShader: ("); 181 182 str->append("ShaderA: "); 183 fShaderA->toString(str); 184 str->append(" ShaderB: "); 185 fShaderB->toString(str); 186 str->append(" Xfermode: "); 187 fMode->toString(str); 188 189 this->INHERITED::toString(str); 190 191 str->append(")"); 192} 193#endif 194