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