/* libs/graphics/effects/SkShaderExtras.cpp ** ** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include "SkComposeShader.h" #include "SkColorFilter.h" #include "SkColorPriv.h" #include "SkXfermode.h" ////////////////////////////////////////////////////////////////////////////////////// SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) { fShaderA = sA; sA->ref(); fShaderB = sB; sB->ref(); // mode may be null fMode = mode; mode->safeRef(); } SkComposeShader::SkComposeShader(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { fShaderA = static_cast<SkShader*>(buffer.readFlattenable()); fShaderB = static_cast<SkShader*>(buffer.readFlattenable()); fMode = static_cast<SkXfermode*>(buffer.readFlattenable()); } SkComposeShader::~SkComposeShader() { fMode->safeUnref(); // may be null fShaderB->unref(); fShaderA->unref(); } void SkComposeShader::beginSession() { this->INHERITED::beginSession(); fShaderA->beginSession(); fShaderB->beginSession(); } void SkComposeShader::endSession() { fShaderA->endSession(); fShaderB->endSession(); this->INHERITED::endSession(); } class SkAutoAlphaRestore { public: SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) { fAlpha = paint->getAlpha(); fPaint = paint; paint->setAlpha(newAlpha); } ~SkAutoAlphaRestore() { fPaint->setAlpha(fAlpha); } private: SkPaint* fPaint; uint8_t fAlpha; }; void SkComposeShader::flatten(SkFlattenableWriteBuffer& buffer) { this->INHERITED::flatten(buffer); buffer.writeFlattenable(fShaderA); buffer.writeFlattenable(fShaderB); buffer.writeFlattenable(fMode); } /* We call setContext on our two worker shaders. However, we always let them see opaque alpha, and if the paint really is translucent, then we apply that after the fact. */ bool SkComposeShader::setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix) { if (!this->INHERITED::setContext(device, paint, matrix)) return false; // we preconcat our localMatrix (if any) with the device matrix // before calling our sub-shaders SkMatrix tmpM; (void)this->getLocalMatrix(&tmpM); tmpM.setConcat(matrix, tmpM); SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF); return fShaderA->setContext(device, paint, tmpM) && fShaderB->setContext(device, paint, tmpM); } // larger is better (fewer times we have to loop), but we shouldn't // take up too much stack-space (each element is 4 bytes) #define TMP_COLOR_COUNT 64 void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) { SkShader* shaderA = fShaderA; SkShader* shaderB = fShaderB; SkXfermode* mode = fMode; unsigned scale = SkAlpha255To256(this->getPaintAlpha()); SkPMColor tmp[TMP_COLOR_COUNT]; if (NULL == mode) // implied SRC_OVER { // TODO: when we have a good test-case, should use SkBlitRow::Proc32 // for these loops do { int n = count; if (n > TMP_COLOR_COUNT) n = TMP_COLOR_COUNT; shaderA->shadeSpan(x, y, result, n); shaderB->shadeSpan(x, y, tmp, n); if (256 == scale) { for (int i = 0; i < n; i++) result[i] = SkPMSrcOver(tmp[i], result[i]); } else { for (int i = 0; i < n; i++) result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), scale); } result += n; x += n; count -= n; } while (count > 0); } else // use mode for the composition { do { int n = count; if (n > TMP_COLOR_COUNT) n = TMP_COLOR_COUNT; shaderA->shadeSpan(x, y, result, n); shaderB->shadeSpan(x, y, tmp, n); mode->xfer32(result, tmp, n, NULL); if (256 == scale) { for (int i = 0; i < n; i++) result[i] = SkAlphaMulQ(result[i], scale); } result += n; x += n; count -= n; } while (count > 0); } }