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 "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