3 * Copyright 2006 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "SkComposeShader.h"
11 #include "SkColorFilter.h"
12 #include "SkColorPriv.h"
13 #include "SkColorShader.h"
14 #include "SkReadBuffer.h"
15 #include "SkWriteBuffer.h"
16 #include "SkXfermode.h"
19 ///////////////////////////////////////////////////////////////////////////////
21 SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) {
22 fShaderA = sA; sA->ref();
23 fShaderB = sB; sB->ref();
29 SkComposeShader::SkComposeShader(SkReadBuffer& buffer) :
31 fShaderA = buffer.readShader();
32 if (NULL == fShaderA) {
33 fShaderA = SkNEW_ARGS(SkColorShader, (0));
35 fShaderB = buffer.readShader();
36 if (NULL == fShaderB) {
37 fShaderB = SkNEW_ARGS(SkColorShader, (0));
39 fMode = buffer.readXfermode();
42 SkComposeShader::~SkComposeShader() {
48 class SkAutoAlphaRestore {
50 SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
51 fAlpha = paint->getAlpha();
53 paint->setAlpha(newAlpha);
56 ~SkAutoAlphaRestore() {
57 fPaint->setAlpha(fAlpha);
63 #define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore)
65 void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
66 this->INHERITED::flatten(buffer);
67 buffer.writeFlattenable(fShaderA);
68 buffer.writeFlattenable(fShaderB);
69 buffer.writeFlattenable(fMode);
72 /* We call setContext on our two worker shaders. However, we
73 always let them see opaque alpha, and if the paint really
74 is translucent, then we apply that after the fact.
76 We need to keep the calls to setContext/endContext balanced, since if we
77 return false, our endContext() will not be called.
79 bool SkComposeShader::setContext(const SkBitmap& device,
81 const SkMatrix& matrix) {
82 if (!this->INHERITED::setContext(device, paint, matrix)) {
86 // we preconcat our localMatrix (if any) with the device matrix
87 // before calling our sub-shaders
91 tmpM.setConcat(matrix, this->getLocalMatrix());
93 SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF);
95 bool setContextA = fShaderA->setContext(device, paint, tmpM);
96 bool setContextB = fShaderB->setContext(device, paint, tmpM);
97 if (!setContextA || !setContextB) {
99 fShaderB->endContext();
101 else if (setContextA) {
102 fShaderA->endContext();
104 this->INHERITED::endContext();
110 void SkComposeShader::endContext() {
111 fShaderB->endContext();
112 fShaderA->endContext();
113 this->INHERITED::endContext();
116 // larger is better (fewer times we have to loop), but we shouldn't
117 // take up too much stack-space (each element is 4 bytes)
118 #define TMP_COLOR_COUNT 64
120 void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
121 SkShader* shaderA = fShaderA;
122 SkShader* shaderB = fShaderB;
123 SkXfermode* mode = fMode;
124 unsigned scale = SkAlpha255To256(this->getPaintAlpha());
126 SkPMColor tmp[TMP_COLOR_COUNT];
128 if (NULL == mode) { // implied SRC_OVER
129 // TODO: when we have a good test-case, should use SkBlitRow::Proc32
133 if (n > TMP_COLOR_COUNT) {
137 shaderA->shadeSpan(x, y, result, n);
138 shaderB->shadeSpan(x, y, tmp, n);
141 for (int i = 0; i < n; i++) {
142 result[i] = SkPMSrcOver(tmp[i], result[i]);
145 for (int i = 0; i < n; i++) {
146 result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
155 } else { // use mode for the composition
158 if (n > TMP_COLOR_COUNT) {
162 shaderA->shadeSpan(x, y, result, n);
163 shaderB->shadeSpan(x, y, tmp, n);
164 mode->xfer32(result, tmp, n, NULL);
167 for (int i = 0; i < n; i++) {
168 result[i] = SkAlphaMulQ(result[i], scale);
180 void SkComposeShader::toString(SkString* str) const {
181 str->append("SkComposeShader: (");
183 str->append("ShaderA: ");
184 fShaderA->toString(str);
185 str->append(" ShaderB: ");
186 fShaderB->toString(str);
187 str->append(" Xfermode: ");
188 fMode->toString(str);
190 this->INHERITED::toString(str);