• 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         // TODO: when we have a good test-case, should use SkBlitRow::Proc32
128         // for these loops
129         do {
130             int n = count;
131             if (n > TMP_COLOR_COUNT)
132                 n = TMP_COLOR_COUNT;
133 
134             shaderA->shadeSpan(x, y, result, n);
135             shaderB->shadeSpan(x, y, tmp, n);
136 
137             if (256 == scale)
138             {
139                 for (int i = 0; i < n; i++)
140                     result[i] = SkPMSrcOver(tmp[i], result[i]);
141             }
142             else
143             {
144                 for (int i = 0; i < n; i++)
145                     result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), scale);
146             }
147 
148             result += n;
149             x += n;
150             count -= n;
151         } while (count > 0);
152     }
153     else    // use mode for the composition
154     {
155         do {
156             int n = count;
157             if (n > TMP_COLOR_COUNT)
158                 n = TMP_COLOR_COUNT;
159 
160             shaderA->shadeSpan(x, y, result, n);
161             shaderB->shadeSpan(x, y, tmp, n);
162             mode->xfer32(result, tmp, n, NULL);
163 
164             if (256 == scale)
165             {
166                 for (int i = 0; i < n; i++)
167                     result[i] = SkAlphaMulQ(result[i], scale);
168             }
169 
170             result += n;
171             x += n;
172             count -= n;
173         } while (count > 0);
174     }
175 }
176 
177