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 "SkXfermode.h"
15
16 ///////////////////////////////////////////////////////////////////////////////
17
SkComposeShader(SkShader * sA,SkShader * sB,SkXfermode * mode)18 SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) {
19 fShaderA = sA; sA->ref();
20 fShaderB = sB; sB->ref();
21 // mode may be null
22 fMode = mode;
23 SkSafeRef(mode);
24 }
25
SkComposeShader(SkFlattenableReadBuffer & buffer)26 SkComposeShader::SkComposeShader(SkFlattenableReadBuffer& buffer) :
27 INHERITED(buffer) {
28 fShaderA = static_cast<SkShader*>(buffer.readFlattenable());
29 if (NULL == fShaderA) {
30 fShaderA = SkNEW_ARGS(SkColorShader, (0));
31 }
32 fShaderB = static_cast<SkShader*>(buffer.readFlattenable());
33 if (NULL == fShaderB) {
34 fShaderB = SkNEW_ARGS(SkColorShader, (0));
35 }
36 fMode = static_cast<SkXfermode*>(buffer.readFlattenable());
37 }
38
~SkComposeShader()39 SkComposeShader::~SkComposeShader() {
40 SkSafeUnref(fMode);
41 fShaderB->unref();
42 fShaderA->unref();
43 }
44
beginSession()45 void SkComposeShader::beginSession() {
46 this->INHERITED::beginSession();
47 fShaderA->beginSession();
48 fShaderB->beginSession();
49 }
50
endSession()51 void SkComposeShader::endSession() {
52 fShaderA->endSession();
53 fShaderB->endSession();
54 this->INHERITED::endSession();
55 }
56
57 class SkAutoAlphaRestore {
58 public:
SkAutoAlphaRestore(SkPaint * paint,uint8_t newAlpha)59 SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
60 fAlpha = paint->getAlpha();
61 fPaint = paint;
62 paint->setAlpha(newAlpha);
63 }
64
~SkAutoAlphaRestore()65 ~SkAutoAlphaRestore() {
66 fPaint->setAlpha(fAlpha);
67 }
68 private:
69 SkPaint* fPaint;
70 uint8_t fAlpha;
71 };
72
flatten(SkFlattenableWriteBuffer & buffer)73 void SkComposeShader::flatten(SkFlattenableWriteBuffer& buffer) {
74 this->INHERITED::flatten(buffer);
75 buffer.writeFlattenable(fShaderA);
76 buffer.writeFlattenable(fShaderB);
77 buffer.writeFlattenable(fMode);
78 }
79
80 /* We call setContext on our two worker shaders. However, we
81 always let them see opaque alpha, and if the paint really
82 is translucent, then we apply that after the fact.
83 */
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)84 bool SkComposeShader::setContext(const SkBitmap& device,
85 const SkPaint& paint,
86 const SkMatrix& matrix) {
87 if (!this->INHERITED::setContext(device, paint, matrix)) {
88 return false;
89 }
90
91 // we preconcat our localMatrix (if any) with the device matrix
92 // before calling our sub-shaders
93
94 SkMatrix tmpM;
95
96 (void)this->getLocalMatrix(&tmpM);
97 tmpM.setConcat(matrix, tmpM);
98
99 SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF);
100
101 return fShaderA->setContext(device, paint, tmpM) &&
102 fShaderB->setContext(device, paint, tmpM);
103 }
104
105 // larger is better (fewer times we have to loop), but we shouldn't
106 // take up too much stack-space (each element is 4 bytes)
107 #define TMP_COLOR_COUNT 64
108
shadeSpan(int x,int y,SkPMColor result[],int count)109 void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
110 SkShader* shaderA = fShaderA;
111 SkShader* shaderB = fShaderB;
112 SkXfermode* mode = fMode;
113 unsigned scale = SkAlpha255To256(this->getPaintAlpha());
114
115 SkPMColor tmp[TMP_COLOR_COUNT];
116
117 if (NULL == mode) { // implied SRC_OVER
118 // TODO: when we have a good test-case, should use SkBlitRow::Proc32
119 // for these loops
120 do {
121 int n = count;
122 if (n > TMP_COLOR_COUNT) {
123 n = TMP_COLOR_COUNT;
124 }
125
126 shaderA->shadeSpan(x, y, result, n);
127 shaderB->shadeSpan(x, y, tmp, n);
128
129 if (256 == scale) {
130 for (int i = 0; i < n; i++) {
131 result[i] = SkPMSrcOver(tmp[i], result[i]);
132 }
133 } else {
134 for (int i = 0; i < n; i++) {
135 result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
136 scale);
137 }
138 }
139
140 result += n;
141 x += n;
142 count -= n;
143 } while (count > 0);
144 } else { // use mode for the composition
145 do {
146 int n = count;
147 if (n > TMP_COLOR_COUNT) {
148 n = TMP_COLOR_COUNT;
149 }
150
151 shaderA->shadeSpan(x, y, result, n);
152 shaderB->shadeSpan(x, y, tmp, n);
153 mode->xfer32(result, tmp, n, NULL);
154
155 if (256 == scale) {
156 for (int i = 0; i < n; i++) {
157 result[i] = SkAlphaMulQ(result[i], scale);
158 }
159 }
160
161 result += n;
162 x += n;
163 count -= n;
164 } while (count > 0);
165 }
166 }
167
168