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