1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkComposeShader.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,194 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2006 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#include "SkComposeShader.h" 1.14 +#include "SkColorFilter.h" 1.15 +#include "SkColorPriv.h" 1.16 +#include "SkColorShader.h" 1.17 +#include "SkReadBuffer.h" 1.18 +#include "SkWriteBuffer.h" 1.19 +#include "SkXfermode.h" 1.20 +#include "SkString.h" 1.21 + 1.22 +/////////////////////////////////////////////////////////////////////////////// 1.23 + 1.24 +SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) { 1.25 + fShaderA = sA; sA->ref(); 1.26 + fShaderB = sB; sB->ref(); 1.27 + // mode may be null 1.28 + fMode = mode; 1.29 + SkSafeRef(mode); 1.30 +} 1.31 + 1.32 +SkComposeShader::SkComposeShader(SkReadBuffer& buffer) : 1.33 + INHERITED(buffer) { 1.34 + fShaderA = buffer.readShader(); 1.35 + if (NULL == fShaderA) { 1.36 + fShaderA = SkNEW_ARGS(SkColorShader, (0)); 1.37 + } 1.38 + fShaderB = buffer.readShader(); 1.39 + if (NULL == fShaderB) { 1.40 + fShaderB = SkNEW_ARGS(SkColorShader, (0)); 1.41 + } 1.42 + fMode = buffer.readXfermode(); 1.43 +} 1.44 + 1.45 +SkComposeShader::~SkComposeShader() { 1.46 + SkSafeUnref(fMode); 1.47 + fShaderB->unref(); 1.48 + fShaderA->unref(); 1.49 +} 1.50 + 1.51 +class SkAutoAlphaRestore { 1.52 +public: 1.53 + SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) { 1.54 + fAlpha = paint->getAlpha(); 1.55 + fPaint = paint; 1.56 + paint->setAlpha(newAlpha); 1.57 + } 1.58 + 1.59 + ~SkAutoAlphaRestore() { 1.60 + fPaint->setAlpha(fAlpha); 1.61 + } 1.62 +private: 1.63 + SkPaint* fPaint; 1.64 + uint8_t fAlpha; 1.65 +}; 1.66 +#define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore) 1.67 + 1.68 +void SkComposeShader::flatten(SkWriteBuffer& buffer) const { 1.69 + this->INHERITED::flatten(buffer); 1.70 + buffer.writeFlattenable(fShaderA); 1.71 + buffer.writeFlattenable(fShaderB); 1.72 + buffer.writeFlattenable(fMode); 1.73 +} 1.74 + 1.75 +/* We call setContext on our two worker shaders. However, we 1.76 + always let them see opaque alpha, and if the paint really 1.77 + is translucent, then we apply that after the fact. 1.78 + 1.79 + We need to keep the calls to setContext/endContext balanced, since if we 1.80 + return false, our endContext() will not be called. 1.81 + */ 1.82 +bool SkComposeShader::setContext(const SkBitmap& device, 1.83 + const SkPaint& paint, 1.84 + const SkMatrix& matrix) { 1.85 + if (!this->INHERITED::setContext(device, paint, matrix)) { 1.86 + return false; 1.87 + } 1.88 + 1.89 + // we preconcat our localMatrix (if any) with the device matrix 1.90 + // before calling our sub-shaders 1.91 + 1.92 + SkMatrix tmpM; 1.93 + 1.94 + tmpM.setConcat(matrix, this->getLocalMatrix()); 1.95 + 1.96 + SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF); 1.97 + 1.98 + bool setContextA = fShaderA->setContext(device, paint, tmpM); 1.99 + bool setContextB = fShaderB->setContext(device, paint, tmpM); 1.100 + if (!setContextA || !setContextB) { 1.101 + if (setContextB) { 1.102 + fShaderB->endContext(); 1.103 + } 1.104 + else if (setContextA) { 1.105 + fShaderA->endContext(); 1.106 + } 1.107 + this->INHERITED::endContext(); 1.108 + return false; 1.109 + } 1.110 + return true; 1.111 +} 1.112 + 1.113 +void SkComposeShader::endContext() { 1.114 + fShaderB->endContext(); 1.115 + fShaderA->endContext(); 1.116 + this->INHERITED::endContext(); 1.117 +} 1.118 + 1.119 +// larger is better (fewer times we have to loop), but we shouldn't 1.120 +// take up too much stack-space (each element is 4 bytes) 1.121 +#define TMP_COLOR_COUNT 64 1.122 + 1.123 +void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) { 1.124 + SkShader* shaderA = fShaderA; 1.125 + SkShader* shaderB = fShaderB; 1.126 + SkXfermode* mode = fMode; 1.127 + unsigned scale = SkAlpha255To256(this->getPaintAlpha()); 1.128 + 1.129 + SkPMColor tmp[TMP_COLOR_COUNT]; 1.130 + 1.131 + if (NULL == mode) { // implied SRC_OVER 1.132 + // TODO: when we have a good test-case, should use SkBlitRow::Proc32 1.133 + // for these loops 1.134 + do { 1.135 + int n = count; 1.136 + if (n > TMP_COLOR_COUNT) { 1.137 + n = TMP_COLOR_COUNT; 1.138 + } 1.139 + 1.140 + shaderA->shadeSpan(x, y, result, n); 1.141 + shaderB->shadeSpan(x, y, tmp, n); 1.142 + 1.143 + if (256 == scale) { 1.144 + for (int i = 0; i < n; i++) { 1.145 + result[i] = SkPMSrcOver(tmp[i], result[i]); 1.146 + } 1.147 + } else { 1.148 + for (int i = 0; i < n; i++) { 1.149 + result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), 1.150 + scale); 1.151 + } 1.152 + } 1.153 + 1.154 + result += n; 1.155 + x += n; 1.156 + count -= n; 1.157 + } while (count > 0); 1.158 + } else { // use mode for the composition 1.159 + do { 1.160 + int n = count; 1.161 + if (n > TMP_COLOR_COUNT) { 1.162 + n = TMP_COLOR_COUNT; 1.163 + } 1.164 + 1.165 + shaderA->shadeSpan(x, y, result, n); 1.166 + shaderB->shadeSpan(x, y, tmp, n); 1.167 + mode->xfer32(result, tmp, n, NULL); 1.168 + 1.169 + if (256 == scale) { 1.170 + for (int i = 0; i < n; i++) { 1.171 + result[i] = SkAlphaMulQ(result[i], scale); 1.172 + } 1.173 + } 1.174 + 1.175 + result += n; 1.176 + x += n; 1.177 + count -= n; 1.178 + } while (count > 0); 1.179 + } 1.180 +} 1.181 + 1.182 +#ifndef SK_IGNORE_TO_STRING 1.183 +void SkComposeShader::toString(SkString* str) const { 1.184 + str->append("SkComposeShader: ("); 1.185 + 1.186 + str->append("ShaderA: "); 1.187 + fShaderA->toString(str); 1.188 + str->append(" ShaderB: "); 1.189 + fShaderB->toString(str); 1.190 + str->append(" Xfermode: "); 1.191 + fMode->toString(str); 1.192 + 1.193 + this->INHERITED::toString(str); 1.194 + 1.195 + str->append(")"); 1.196 +} 1.197 +#endif