1 /* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkComposeShader.h" 9 #include "SkColorFilter.h" 10 #include "SkColorPriv.h" 11 #include "SkColorShader.h" 12 #include "SkReadBuffer.h" 13 #include "SkWriteBuffer.h" 14 #include "SkXfermode.h" 15 #include "SkString.h" 16 17 /////////////////////////////////////////////////////////////////////////////// 18 19 SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) { 20 fShaderA = sA; sA->ref(); 21 fShaderB = sB; sB->ref(); 22 // mode may be null 23 fMode = mode; 24 SkSafeRef(mode); 25 } 26 27 SkComposeShader::~SkComposeShader() { 28 SkSafeUnref(fMode); 29 fShaderB->unref(); 30 fShaderA->unref(); 31 } 32 33 size_t SkComposeShader::contextSize(const ContextRec& rec) const { 34 return sizeof(ComposeShaderContext) 35 + fShaderA->contextSize(rec) 36 + fShaderB->contextSize(rec); 37 } 38 39 class SkAutoAlphaRestore { 40 public: 41 SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) { 42 fAlpha = paint->getAlpha(); 43 fPaint = paint; 44 paint->setAlpha(newAlpha); 45 } 46 47 ~SkAutoAlphaRestore() { 48 fPaint->setAlpha(fAlpha); 49 } 50 private: 51 SkPaint* fPaint; 52 uint8_t fAlpha; 53 }; 54 #define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore) 55 56 SkFlattenable* SkComposeShader::CreateProc(SkReadBuffer& buffer) { 57 SkAutoTUnref<SkShader> shaderA(buffer.readShader()); 58 SkAutoTUnref<SkShader> shaderB(buffer.readShader()); 59 SkAutoTUnref<SkXfermode> mode(buffer.readXfermode()); 60 if (!shaderA.get() || !shaderB.get()) { 61 return nullptr; 62 } 63 return new SkComposeShader(shaderA, shaderB, mode); 64 } 65 66 void SkComposeShader::flatten(SkWriteBuffer& buffer) const { 67 buffer.writeFlattenable(fShaderA); 68 buffer.writeFlattenable(fShaderB); 69 buffer.writeFlattenable(fMode); 70 } 71 72 template <typename T> void safe_call_destructor(T* obj) { 73 if (obj) { 74 obj->~T(); 75 } 76 } 77 78 SkShader::Context* SkComposeShader::onCreateContext(const ContextRec& rec, void* storage) const { 79 char* aStorage = (char*) storage + sizeof(ComposeShaderContext); 80 char* bStorage = aStorage + fShaderA->contextSize(rec); 81 82 // we preconcat our localMatrix (if any) with the device matrix 83 // before calling our sub-shaders 84 SkMatrix tmpM; 85 tmpM.setConcat(*rec.fMatrix, this->getLocalMatrix()); 86 87 // Our sub-shaders need to see opaque, so by combining them we don't double-alphatize the 88 // result. ComposeShader itself will respect the alpha, and post-apply it after calling the 89 // sub-shaders. 90 SkPaint opaquePaint(*rec.fPaint); 91 opaquePaint.setAlpha(0xFF); 92 93 ContextRec newRec(rec); 94 newRec.fMatrix = &tmpM; 95 newRec.fPaint = &opaquePaint; 96 97 SkShader::Context* contextA = fShaderA->createContext(newRec, aStorage); 98 SkShader::Context* contextB = fShaderB->createContext(newRec, bStorage); 99 if (!contextA || !contextB) { 100 safe_call_destructor(contextA); 101 safe_call_destructor(contextB); 102 return nullptr; 103 } 104 105 return new (storage) ComposeShaderContext(*this, rec, contextA, contextB); 106 } 107 108 SkComposeShader::ComposeShaderContext::ComposeShaderContext( 109 const SkComposeShader& shader, const ContextRec& rec, 110 SkShader::Context* contextA, SkShader::Context* contextB) 111 : INHERITED(shader, rec) 112 , fShaderContextA(contextA) 113 , fShaderContextB(contextB) {} 114 115 SkComposeShader::ComposeShaderContext::~ComposeShaderContext() { 116 fShaderContextA->~Context(); 117 fShaderContextB->~Context(); 118 } 119 120 bool SkComposeShader::asACompose(ComposeRec* rec) const { 121 if (rec) { 122 rec->fShaderA = fShaderA; 123 rec->fShaderB = fShaderB; 124 rec->fMode = fMode; 125 } 126 return true; 127 } 128 129 130 // larger is better (fewer times we have to loop), but we shouldn't 131 // take up too much stack-space (each element is 4 bytes) 132 #define TMP_COLOR_COUNT 64 133 134 void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { 135 SkShader::Context* shaderContextA = fShaderContextA; 136 SkShader::Context* shaderContextB = fShaderContextB; 137 SkXfermode* mode = static_cast<const SkComposeShader&>(fShader).fMode; 138 unsigned scale = SkAlpha255To256(this->getPaintAlpha()); 139 140 SkPMColor tmp[TMP_COLOR_COUNT]; 141 142 if (nullptr == mode) { // implied SRC_OVER 143 // TODO: when we have a good test-case, should use SkBlitRow::Proc32 144 // for these loops 145 do { 146 int n = count; 147 if (n > TMP_COLOR_COUNT) { 148 n = TMP_COLOR_COUNT; 149 } 150 151 shaderContextA->shadeSpan(x, y, result, n); 152 shaderContextB->shadeSpan(x, y, tmp, n); 153 154 if (256 == scale) { 155 for (int i = 0; i < n; i++) { 156 result[i] = SkPMSrcOver(tmp[i], result[i]); 157 } 158 } else { 159 for (int i = 0; i < n; i++) { 160 result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), 161 scale); 162 } 163 } 164 165 result += n; 166 x += n; 167 count -= n; 168 } while (count > 0); 169 } else { // use mode for the composition 170 do { 171 int n = count; 172 if (n > TMP_COLOR_COUNT) { 173 n = TMP_COLOR_COUNT; 174 } 175 176 shaderContextA->shadeSpan(x, y, result, n); 177 shaderContextB->shadeSpan(x, y, tmp, n); 178 mode->xfer32(result, tmp, n, nullptr); 179 180 if (256 != scale) { 181 for (int i = 0; i < n; i++) { 182 result[i] = SkAlphaMulQ(result[i], scale); 183 } 184 } 185 186 result += n; 187 x += n; 188 count -= n; 189 } while (count > 0); 190 } 191 } 192 193 #if SK_SUPPORT_GPU 194 195 #include "effects/GrConstColorProcessor.h" 196 #include "effects/GrXfermodeFragmentProcessor.h" 197 198 ///////////////////////////////////////////////////////////////////// 199 200 const GrFragmentProcessor* SkComposeShader::asFragmentProcessor(GrContext* context, 201 const SkMatrix& viewM, 202 const SkMatrix* localMatrix, 203 SkFilterQuality fq) const { 204 // Fragment processor will only support SkXfermode::Mode modes currently. 205 SkXfermode::Mode mode; 206 if (!(SkXfermode::AsMode(fMode, &mode))) { 207 return nullptr; 208 } 209 210 switch (mode) { 211 case SkXfermode::kClear_Mode: 212 return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, 213 GrConstColorProcessor::kIgnore_InputMode); 214 break; 215 case SkXfermode::kSrc_Mode: 216 return fShaderB->asFragmentProcessor(context, viewM, localMatrix, fq); 217 break; 218 case SkXfermode::kDst_Mode: 219 return fShaderA->asFragmentProcessor(context, viewM, localMatrix, fq); 220 break; 221 default: 222 SkAutoTUnref<const GrFragmentProcessor> fpA(fShaderA->asFragmentProcessor(context, 223 viewM, localMatrix, fq)); 224 if (!fpA.get()) { 225 return nullptr; 226 } 227 SkAutoTUnref<const GrFragmentProcessor> fpB(fShaderB->asFragmentProcessor(context, 228 viewM, localMatrix, fq)); 229 if (!fpB.get()) { 230 return nullptr; 231 } 232 return GrXfermodeFragmentProcessor::CreateFromTwoProcessors(fpB, fpA, mode); 233 } 234 } 235 #endif 236 237 #ifndef SK_IGNORE_TO_STRING 238 void SkComposeShader::toString(SkString* str) const { 239 str->append("SkComposeShader: ("); 240 241 str->append("ShaderA: "); 242 fShaderA->toString(str); 243 str->append(" ShaderB: "); 244 fShaderB->toString(str); 245 if (fMode) { 246 str->append(" Xfermode: "); 247 fMode->toString(str); 248 } 249 250 this->INHERITED::toString(str); 251 252 str->append(")"); 253 } 254 #endif 255 256 /////////////////////////////////////////////////////////////////////////////////////////////////// 257 258 SkShader* SkShader::CreateComposeShader(SkShader* dst, SkShader* src, SkXfermode* xfer) { 259 if (!dst || !src) { 260 return nullptr; 261 } 262 return new SkComposeShader(dst, src, xfer); 263 } 264 265 SkShader* SkShader::CreateComposeShader(SkShader* dst, SkShader* src, SkXfermode::Mode mode) { 266 SkAutoTUnref<SkXfermode> xfer(SkXfermode::Create(mode)); 267 return CreateComposeShader(dst, src, xfer); 268 } 269