• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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