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 :
18 0 : SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) {
19 0 : fShaderA = sA; sA->ref();
20 0 : fShaderB = sB; sB->ref();
21 : // mode may be null
22 0 : fMode = mode;
23 0 : SkSafeRef(mode);
24 0 : }
25 :
26 0 : SkComposeShader::SkComposeShader(SkFlattenableReadBuffer& buffer) :
27 0 : INHERITED(buffer) {
28 0 : fShaderA = static_cast<SkShader*>(buffer.readFlattenable());
29 0 : if (NULL == fShaderA) {
30 0 : fShaderA = SkNEW_ARGS(SkColorShader, (0));
31 : }
32 0 : fShaderB = static_cast<SkShader*>(buffer.readFlattenable());
33 0 : if (NULL == fShaderB) {
34 0 : fShaderB = SkNEW_ARGS(SkColorShader, (0));
35 : }
36 0 : fMode = static_cast<SkXfermode*>(buffer.readFlattenable());
37 0 : }
38 :
39 0 : SkComposeShader::~SkComposeShader() {
40 0 : SkSafeUnref(fMode);
41 0 : fShaderB->unref();
42 0 : fShaderA->unref();
43 0 : }
44 :
45 0 : void SkComposeShader::beginSession() {
46 0 : this->INHERITED::beginSession();
47 0 : fShaderA->beginSession();
48 0 : fShaderB->beginSession();
49 0 : }
50 :
51 0 : void SkComposeShader::endSession() {
52 0 : fShaderA->endSession();
53 0 : fShaderB->endSession();
54 0 : this->INHERITED::endSession();
55 0 : }
56 :
57 : class SkAutoAlphaRestore {
58 : public:
59 0 : SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
60 0 : fAlpha = paint->getAlpha();
61 0 : fPaint = paint;
62 0 : paint->setAlpha(newAlpha);
63 0 : }
64 :
65 0 : ~SkAutoAlphaRestore() {
66 0 : fPaint->setAlpha(fAlpha);
67 0 : }
68 : private:
69 : SkPaint* fPaint;
70 : uint8_t fAlpha;
71 : };
72 :
73 0 : void SkComposeShader::flatten(SkFlattenableWriteBuffer& buffer) {
74 0 : this->INHERITED::flatten(buffer);
75 0 : buffer.writeFlattenable(fShaderA);
76 0 : buffer.writeFlattenable(fShaderB);
77 0 : buffer.writeFlattenable(fMode);
78 0 : }
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 : */
84 0 : bool SkComposeShader::setContext(const SkBitmap& device,
85 : const SkPaint& paint,
86 : const SkMatrix& matrix) {
87 0 : if (!this->INHERITED::setContext(device, paint, matrix)) {
88 0 : 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 0 : (void)this->getLocalMatrix(&tmpM);
97 0 : tmpM.setConcat(matrix, tmpM);
98 :
99 0 : SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF);
100 :
101 0 : return fShaderA->setContext(device, paint, tmpM) &&
102 0 : 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 :
109 0 : void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
110 0 : SkShader* shaderA = fShaderA;
111 0 : SkShader* shaderB = fShaderB;
112 0 : SkXfermode* mode = fMode;
113 0 : unsigned scale = SkAlpha255To256(this->getPaintAlpha());
114 :
115 : SkPMColor tmp[TMP_COLOR_COUNT];
116 :
117 0 : if (NULL == mode) { // implied SRC_OVER
118 : // TODO: when we have a good test-case, should use SkBlitRow::Proc32
119 : // for these loops
120 0 : do {
121 0 : int n = count;
122 0 : if (n > TMP_COLOR_COUNT) {
123 0 : n = TMP_COLOR_COUNT;
124 : }
125 :
126 0 : shaderA->shadeSpan(x, y, result, n);
127 0 : shaderB->shadeSpan(x, y, tmp, n);
128 :
129 0 : if (256 == scale) {
130 0 : for (int i = 0; i < n; i++) {
131 0 : result[i] = SkPMSrcOver(tmp[i], result[i]);
132 : }
133 : } else {
134 0 : for (int i = 0; i < n; i++) {
135 0 : result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
136 0 : scale);
137 : }
138 : }
139 :
140 0 : result += n;
141 0 : x += n;
142 0 : count -= n;
143 : } while (count > 0);
144 : } else { // use mode for the composition
145 0 : do {
146 0 : int n = count;
147 0 : if (n > TMP_COLOR_COUNT) {
148 0 : n = TMP_COLOR_COUNT;
149 : }
150 :
151 0 : shaderA->shadeSpan(x, y, result, n);
152 0 : shaderB->shadeSpan(x, y, tmp, n);
153 0 : mode->xfer32(result, tmp, n, NULL);
154 :
155 0 : if (256 == scale) {
156 0 : for (int i = 0; i < n; i++) {
157 0 : result[i] = SkAlphaMulQ(result[i], scale);
158 : }
159 : }
160 :
161 0 : result += n;
162 0 : x += n;
163 0 : count -= n;
164 : } while (count > 0);
165 : }
166 0 : }
167 :
|