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 25 SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) { 26 fShaderA = sA; sA->ref(); 27 fShaderB = sB; sB->ref(); 28 // mode may be null 29 fMode = mode; 30 SkSafeRef(mode); 31 } 32 33 SkComposeShader::SkComposeShader(SkFlattenableReadBuffer& buffer) : 34 INHERITED(buffer) { 35 fShaderA = static_cast<SkShader*>(buffer.readFlattenable()); 36 fShaderB = static_cast<SkShader*>(buffer.readFlattenable()); 37 fMode = static_cast<SkXfermode*>(buffer.readFlattenable()); 38 } 39 40 SkComposeShader::~SkComposeShader() { 41 SkSafeUnref(fMode); 42 fShaderB->unref(); 43 fShaderA->unref(); 44 } 45 46 void SkComposeShader::beginSession() { 47 this->INHERITED::beginSession(); 48 fShaderA->beginSession(); 49 fShaderB->beginSession(); 50 } 51 52 void SkComposeShader::endSession() { 53 fShaderA->endSession(); 54 fShaderB->endSession(); 55 this->INHERITED::endSession(); 56 } 57 58 class SkAutoAlphaRestore { 59 public: 60 SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) { 61 fAlpha = paint->getAlpha(); 62 fPaint = paint; 63 paint->setAlpha(newAlpha); 64 } 65 66 ~SkAutoAlphaRestore() { 67 fPaint->setAlpha(fAlpha); 68 } 69 private: 70 SkPaint* fPaint; 71 uint8_t fAlpha; 72 }; 73 74 void SkComposeShader::flatten(SkFlattenableWriteBuffer& buffer) { 75 this->INHERITED::flatten(buffer); 76 buffer.writeFlattenable(fShaderA); 77 buffer.writeFlattenable(fShaderB); 78 buffer.writeFlattenable(fMode); 79 } 80 81 /* We call setContext on our two worker shaders. However, we 82 always let them see opaque alpha, and if the paint really 83 is translucent, then we apply that after the fact. 84 */ 85 bool SkComposeShader::setContext(const SkBitmap& device, 86 const SkPaint& paint, 87 const SkMatrix& matrix) { 88 if (!this->INHERITED::setContext(device, paint, matrix)) { 89 return false; 90 } 91 92 // we preconcat our localMatrix (if any) with the device matrix 93 // before calling our sub-shaders 94 95 SkMatrix tmpM; 96 97 (void)this->getLocalMatrix(&tmpM); 98 tmpM.setConcat(matrix, tmpM); 99 100 SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF); 101 102 return fShaderA->setContext(device, paint, tmpM) && 103 fShaderB->setContext(device, paint, tmpM); 104 } 105 106 // larger is better (fewer times we have to loop), but we shouldn't 107 // take up too much stack-space (each element is 4 bytes) 108 #define TMP_COLOR_COUNT 64 109 110 void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) { 111 SkShader* shaderA = fShaderA; 112 SkShader* shaderB = fShaderB; 113 SkXfermode* mode = fMode; 114 unsigned scale = SkAlpha255To256(this->getPaintAlpha()); 115 116 SkPMColor tmp[TMP_COLOR_COUNT]; 117 118 if (NULL == mode) { // implied SRC_OVER 119 // TODO: when we have a good test-case, should use SkBlitRow::Proc32 120 // for these loops 121 do { 122 int n = count; 123 if (n > TMP_COLOR_COUNT) { 124 n = TMP_COLOR_COUNT; 125 } 126 127 shaderA->shadeSpan(x, y, result, n); 128 shaderB->shadeSpan(x, y, tmp, n); 129 130 if (256 == scale) { 131 for (int i = 0; i < n; i++) { 132 result[i] = SkPMSrcOver(tmp[i], result[i]); 133 } 134 } else { 135 for (int i = 0; i < n; i++) { 136 result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), 137 scale); 138 } 139 } 140 141 result += n; 142 x += n; 143 count -= n; 144 } while (count > 0); 145 } else { // use mode for the composition 146 do { 147 int n = count; 148 if (n > TMP_COLOR_COUNT) { 149 n = TMP_COLOR_COUNT; 150 } 151 152 shaderA->shadeSpan(x, y, result, n); 153 shaderB->shadeSpan(x, y, tmp, n); 154 mode->xfer32(result, tmp, n, NULL); 155 156 if (256 == scale) { 157 for (int i = 0; i < n; i++) { 158 result[i] = SkAlphaMulQ(result[i], scale); 159 } 160 } 161 162 result += n; 163 x += n; 164 count -= n; 165 } while (count > 0); 166 } 167 } 168 169