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
SkComposeShader(SkShader * sA,SkShader * sB,SkXfermode * mode)25 SkComposeShader::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
SkComposeShader(SkFlattenableReadBuffer & buffer)33 SkComposeShader::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
~SkComposeShader()41 SkComposeShader::~SkComposeShader()
42 {
43 fMode->safeUnref(); // may be null
44 fShaderB->unref();
45 fShaderA->unref();
46 }
47
beginSession()48 void SkComposeShader::beginSession()
49 {
50 this->INHERITED::beginSession();
51 fShaderA->beginSession();
52 fShaderB->beginSession();
53 }
54
endSession()55 void SkComposeShader::endSession()
56 {
57 fShaderA->endSession();
58 fShaderB->endSession();
59 this->INHERITED::endSession();
60 }
61
62 class SkAutoAlphaRestore {
63 public:
SkAutoAlphaRestore(SkPaint * paint,uint8_t newAlpha)64 SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha)
65 {
66 fAlpha = paint->getAlpha();
67 fPaint = paint;
68 paint->setAlpha(newAlpha);
69 }
~SkAutoAlphaRestore()70 ~SkAutoAlphaRestore()
71 {
72 fPaint->setAlpha(fAlpha);
73 }
74 private:
75 SkPaint* fPaint;
76 uint8_t fAlpha;
77 };
78
flatten(SkFlattenableWriteBuffer & buffer)79 void 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 */
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)91 bool 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
shadeSpan(int x,int y,SkPMColor result[],int count)116 void 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 do {
128 int n = count;
129 if (n > TMP_COLOR_COUNT)
130 n = TMP_COLOR_COUNT;
131
132 shaderA->shadeSpan(x, y, result, n);
133 shaderB->shadeSpan(x, y, tmp, n);
134
135 if (256 == scale)
136 {
137 for (int i = 0; i < n; i++)
138 result[i] = SkPMSrcOver(tmp[i], result[i]);
139 }
140 else
141 {
142 for (int i = 0; i < n; i++)
143 result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), scale);
144 }
145
146 result += n;
147 x += n;
148 count -= n;
149 } while (count > 0);
150 }
151 else // use mode for the composition
152 {
153 do {
154 int n = count;
155 if (n > TMP_COLOR_COUNT)
156 n = TMP_COLOR_COUNT;
157
158 shaderA->shadeSpan(x, y, result, n);
159 shaderB->shadeSpan(x, y, tmp, n);
160 mode->xfer32(result, tmp, n, NULL);
161
162 if (256 == scale)
163 {
164 for (int i = 0; i < n; i++)
165 result[i] = SkAlphaMulQ(result[i], scale);
166 }
167
168 result += n;
169 x += n;
170 count -= n;
171 } while (count > 0);
172 }
173 }
174
175