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 "SkReadBuffer.h" 15 #include "SkWriteBuffer.h" 16 #include "SkXfermode.h" 17 #include "SkString.h" 18 19 /////////////////////////////////////////////////////////////////////////////// 20 21 SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) { 22 fShaderA = sA; sA->ref(); 23 fShaderB = sB; sB->ref(); 24 // mode may be null 25 fMode = mode; 26 SkSafeRef(mode); 27 } 28 29 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING 30 SkComposeShader::SkComposeShader(SkReadBuffer& buffer) : INHERITED(buffer) { 31 fShaderA = buffer.readShader(); 32 if (NULL == fShaderA) { 33 fShaderA = SkNEW_ARGS(SkColorShader, ((SkColor)0)); 34 } 35 fShaderB = buffer.readShader(); 36 if (NULL == fShaderB) { 37 fShaderB = SkNEW_ARGS(SkColorShader, ((SkColor)0)); 38 } 39 fMode = buffer.readXfermode(); 40 } 41 #endif 42 43 SkComposeShader::~SkComposeShader() { 44 SkSafeUnref(fMode); 45 fShaderB->unref(); 46 fShaderA->unref(); 47 } 48 49 size_t SkComposeShader::contextSize() const { 50 return sizeof(ComposeShaderContext) + fShaderA->contextSize() + fShaderB->contextSize(); 51 } 52 53 class SkAutoAlphaRestore { 54 public: 55 SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) { 56 fAlpha = paint->getAlpha(); 57 fPaint = paint; 58 paint->setAlpha(newAlpha); 59 } 60 61 ~SkAutoAlphaRestore() { 62 fPaint->setAlpha(fAlpha); 63 } 64 private: 65 SkPaint* fPaint; 66 uint8_t fAlpha; 67 }; 68 #define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore) 69 70 SkFlattenable* SkComposeShader::CreateProc(SkReadBuffer& buffer) { 71 SkAutoTUnref<SkShader> shaderA(buffer.readShader()); 72 SkAutoTUnref<SkShader> shaderB(buffer.readShader()); 73 SkAutoTUnref<SkXfermode> mode(buffer.readXfermode()); 74 if (!shaderA.get() || !shaderB.get()) { 75 return NULL; 76 } 77 return SkNEW_ARGS(SkComposeShader, (shaderA, shaderB, mode)); 78 } 79 80 void SkComposeShader::flatten(SkWriteBuffer& buffer) const { 81 buffer.writeFlattenable(fShaderA); 82 buffer.writeFlattenable(fShaderB); 83 buffer.writeFlattenable(fMode); 84 } 85 86 template <typename T> void safe_call_destructor(T* obj) { 87 if (obj) { 88 obj->~T(); 89 } 90 } 91 92 SkShader::Context* SkComposeShader::onCreateContext(const ContextRec& rec, void* storage) const { 93 char* aStorage = (char*) storage + sizeof(ComposeShaderContext); 94 char* bStorage = aStorage + fShaderA->contextSize(); 95 96 // we preconcat our localMatrix (if any) with the device matrix 97 // before calling our sub-shaders 98 SkMatrix tmpM; 99 tmpM.setConcat(*rec.fMatrix, this->getLocalMatrix()); 100 101 // Our sub-shaders need to see opaque, so by combining them we don't double-alphatize the 102 // result. ComposeShader itself will respect the alpha, and post-apply it after calling the 103 // sub-shaders. 104 SkPaint opaquePaint(*rec.fPaint); 105 opaquePaint.setAlpha(0xFF); 106 107 ContextRec newRec(rec); 108 newRec.fMatrix = &tmpM; 109 newRec.fPaint = &opaquePaint; 110 111 SkShader::Context* contextA = fShaderA->createContext(newRec, aStorage); 112 SkShader::Context* contextB = fShaderB->createContext(newRec, bStorage); 113 if (!contextA || !contextB) { 114 safe_call_destructor(contextA); 115 safe_call_destructor(contextB); 116 return NULL; 117 } 118 119 return SkNEW_PLACEMENT_ARGS(storage, ComposeShaderContext, (*this, rec, contextA, contextB)); 120 } 121 122 SkComposeShader::ComposeShaderContext::ComposeShaderContext( 123 const SkComposeShader& shader, const ContextRec& rec, 124 SkShader::Context* contextA, SkShader::Context* contextB) 125 : INHERITED(shader, rec) 126 , fShaderContextA(contextA) 127 , fShaderContextB(contextB) {} 128 129 SkComposeShader::ComposeShaderContext::~ComposeShaderContext() { 130 fShaderContextA->~Context(); 131 fShaderContextB->~Context(); 132 } 133 134 bool SkComposeShader::asACompose(ComposeRec* rec) const { 135 if (rec) { 136 rec->fShaderA = fShaderA; 137 rec->fShaderB = fShaderB; 138 rec->fMode = fMode; 139 } 140 return true; 141 } 142 143 144 // larger is better (fewer times we have to loop), but we shouldn't 145 // take up too much stack-space (each element is 4 bytes) 146 #define TMP_COLOR_COUNT 64 147 148 void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { 149 SkShader::Context* shaderContextA = fShaderContextA; 150 SkShader::Context* shaderContextB = fShaderContextB; 151 SkXfermode* mode = static_cast<const SkComposeShader&>(fShader).fMode; 152 unsigned scale = SkAlpha255To256(this->getPaintAlpha()); 153 154 #ifdef SK_BUILD_FOR_ANDROID 155 scale = 256; // ugh -- maintain old bug/behavior for now 156 #endif 157 158 SkPMColor tmp[TMP_COLOR_COUNT]; 159 160 if (NULL == mode) { // implied SRC_OVER 161 // TODO: when we have a good test-case, should use SkBlitRow::Proc32 162 // for these loops 163 do { 164 int n = count; 165 if (n > TMP_COLOR_COUNT) { 166 n = TMP_COLOR_COUNT; 167 } 168 169 shaderContextA->shadeSpan(x, y, result, n); 170 shaderContextB->shadeSpan(x, y, tmp, n); 171 172 if (256 == scale) { 173 for (int i = 0; i < n; i++) { 174 result[i] = SkPMSrcOver(tmp[i], result[i]); 175 } 176 } else { 177 for (int i = 0; i < n; i++) { 178 result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), 179 scale); 180 } 181 } 182 183 result += n; 184 x += n; 185 count -= n; 186 } while (count > 0); 187 } else { // use mode for the composition 188 do { 189 int n = count; 190 if (n > TMP_COLOR_COUNT) { 191 n = TMP_COLOR_COUNT; 192 } 193 194 shaderContextA->shadeSpan(x, y, result, n); 195 shaderContextB->shadeSpan(x, y, tmp, n); 196 mode->xfer32(result, tmp, n, NULL); 197 198 if (256 != scale) { 199 for (int i = 0; i < n; i++) { 200 result[i] = SkAlphaMulQ(result[i], scale); 201 } 202 } 203 204 result += n; 205 x += n; 206 count -= n; 207 } while (count > 0); 208 } 209 } 210 211 #ifndef SK_IGNORE_TO_STRING 212 void SkComposeShader::toString(SkString* str) const { 213 str->append("SkComposeShader: ("); 214 215 str->append("ShaderA: "); 216 fShaderA->toString(str); 217 str->append(" ShaderB: "); 218 fShaderB->toString(str); 219 str->append(" Xfermode: "); 220 fMode->toString(str); 221 222 this->INHERITED::toString(str); 223 224 str->append(")"); 225 } 226 #endif 227