diff options
Diffstat (limited to 'skia/effects/SkShaderExtras.cpp')
-rw-r--r-- | skia/effects/SkShaderExtras.cpp | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/skia/effects/SkShaderExtras.cpp b/skia/effects/SkShaderExtras.cpp new file mode 100644 index 0000000..6bfe517 --- /dev/null +++ b/skia/effects/SkShaderExtras.cpp @@ -0,0 +1,174 @@ +/* libs/graphics/effects/SkShaderExtras.cpp +** +** Copyright 2006, Google Inc. +** +** 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 "SkShaderExtras.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 + { + 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); + } +} + |