Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      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 #include "SkBitmapProcShader.h"
      9 #include "SkColorPriv.h"
     10 #include "SkFlattenableBuffers.h"
     11 #include "SkPixelRef.h"
     12 
     13 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
     14     switch (bm.config()) {
     15         case SkBitmap::kA8_Config:
     16         case SkBitmap::kRGB_565_Config:
     17         case SkBitmap::kIndex8_Config:
     18         case SkBitmap::kARGB_8888_Config:
     19     //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
     20                 return true;
     21         default:
     22             break;
     23     }
     24     return false;
     25 }
     26 
     27 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
     28                                        TileMode tmx, TileMode tmy) {
     29     fRawBitmap = src;
     30     fState.fTileModeX = (uint8_t)tmx;
     31     fState.fTileModeY = (uint8_t)tmy;
     32     fFlags = 0; // computed in setContext
     33 }
     34 
     35 SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
     36         : INHERITED(buffer) {
     37     buffer.readBitmap(&fRawBitmap);
     38     fRawBitmap.setImmutable();
     39     fState.fTileModeX = buffer.readUInt();
     40     fState.fTileModeY = buffer.readUInt();
     41     fFlags = 0; // computed in setContext
     42 }
     43 
     44 SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
     45                                                    SkMatrix* texM,
     46                                                    TileMode xy[]) const {
     47     if (texture) {
     48         *texture = fRawBitmap;
     49     }
     50     if (texM) {
     51         texM->reset();
     52     }
     53     if (xy) {
     54         xy[0] = (TileMode)fState.fTileModeX;
     55         xy[1] = (TileMode)fState.fTileModeY;
     56     }
     57     return kDefault_BitmapType;
     58 }
     59 
     60 void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const {
     61     this->INHERITED::flatten(buffer);
     62 
     63     buffer.writeBitmap(fRawBitmap);
     64     buffer.writeUInt(fState.fTileModeX);
     65     buffer.writeUInt(fState.fTileModeY);
     66 }
     67 
     68 static bool only_scale_and_translate(const SkMatrix& matrix) {
     69     unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
     70     return (matrix.getType() & ~mask) == 0;
     71 }
     72 
     73 bool SkBitmapProcShader::isOpaque() const {
     74     return fRawBitmap.isOpaque();
     75 }
     76 
     77 bool SkBitmapProcShader::setContext(const SkBitmap& device,
     78                                     const SkPaint& paint,
     79                                     const SkMatrix& matrix) {
     80     // do this first, so we have a correct inverse matrix
     81     if (!this->INHERITED::setContext(device, paint, matrix)) {
     82         return false;
     83     }
     84 
     85     fState.fOrigBitmap = fRawBitmap;
     86     fState.fOrigBitmap.lockPixels();
     87     if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
     88         fState.fOrigBitmap.unlockPixels();
     89         this->INHERITED::endContext();
     90         return false;
     91     }
     92 
     93     if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
     94         fState.fOrigBitmap.unlockPixels();
     95         this->INHERITED::endContext();
     96         return false;
     97     }
     98 
     99     const SkBitmap& bitmap = *fState.fBitmap;
    100     bool bitmapIsOpaque = bitmap.isOpaque();
    101 
    102     // update fFlags
    103     uint32_t flags = 0;
    104     if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
    105         flags |= kOpaqueAlpha_Flag;
    106     }
    107 
    108     switch (bitmap.config()) {
    109         case SkBitmap::kRGB_565_Config:
    110             flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
    111             break;
    112         case SkBitmap::kIndex8_Config:
    113         case SkBitmap::kARGB_8888_Config:
    114             if (bitmapIsOpaque) {
    115                 flags |= kHasSpan16_Flag;
    116             }
    117             break;
    118         case SkBitmap::kA8_Config:
    119             break;  // never set kHasSpan16_Flag
    120         default:
    121             break;
    122     }
    123 
    124     if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
    125         // gradients can auto-dither in their 16bit sampler, but we don't so
    126         // we clear the flag here.
    127         flags &= ~kHasSpan16_Flag;
    128     }
    129 
    130     // if we're only 1-pixel high, and we don't rotate, then we can claim this
    131     if (1 == bitmap.height() &&
    132             only_scale_and_translate(this->getTotalInverse())) {
    133         flags |= kConstInY32_Flag;
    134         if (flags & kHasSpan16_Flag) {
    135             flags |= kConstInY16_Flag;
    136         }
    137     }
    138 
    139     fFlags = flags;
    140     return true;
    141 }
    142 
    143 void SkBitmapProcShader::endContext() {
    144     fState.fOrigBitmap.unlockPixels();
    145     this->INHERITED::endContext();
    146 }
    147 
    148 #define BUF_MAX     128
    149 
    150 #define TEST_BUFFER_OVERRITEx
    151 
    152 #ifdef TEST_BUFFER_OVERRITE
    153     #define TEST_BUFFER_EXTRA   32
    154     #define TEST_PATTERN    0x88888888
    155 #else
    156     #define TEST_BUFFER_EXTRA   0
    157 #endif
    158 
    159 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
    160     const SkBitmapProcState& state = fState;
    161     if (state.getShaderProc32()) {
    162         state.getShaderProc32()(state, x, y, dstC, count);
    163         return;
    164     }
    165 
    166     uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
    167     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    168     SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
    169     int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
    170 
    171     SkASSERT(state.fBitmap->getPixels());
    172     SkASSERT(state.fBitmap->pixelRef() == NULL ||
    173              state.fBitmap->pixelRef()->isLocked());
    174 
    175     for (;;) {
    176         int n = count;
    177         if (n > max) {
    178             n = max;
    179         }
    180         SkASSERT(n > 0 && n < BUF_MAX*2);
    181 #ifdef TEST_BUFFER_OVERRITE
    182         for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
    183             buffer[BUF_MAX + i] = TEST_PATTERN;
    184         }
    185 #endif
    186         mproc(state, buffer, n, x, y);
    187 #ifdef TEST_BUFFER_OVERRITE
    188         for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
    189             SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
    190         }
    191 #endif
    192         sproc(state, buffer, n, dstC);
    193 
    194         if ((count -= n) == 0) {
    195             break;
    196         }
    197         SkASSERT(count > 0);
    198         x += n;
    199         dstC += n;
    200     }
    201 }
    202 
    203 SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
    204     if (fState.getShaderProc32()) {
    205         *ctx = &fState;
    206         return (ShadeProc)fState.getShaderProc32();
    207     }
    208     return NULL;
    209 }
    210 
    211 void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
    212     const SkBitmapProcState& state = fState;
    213     if (state.getShaderProc16()) {
    214         state.getShaderProc16()(state, x, y, dstC, count);
    215         return;
    216     }
    217 
    218     uint32_t buffer[BUF_MAX];
    219     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    220     SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
    221     int max = fState.maxCountForBufferSize(sizeof(buffer));
    222 
    223     SkASSERT(state.fBitmap->getPixels());
    224     SkASSERT(state.fBitmap->pixelRef() == NULL ||
    225              state.fBitmap->pixelRef()->isLocked());
    226 
    227     for (;;) {
    228         int n = count;
    229         if (n > max) {
    230             n = max;
    231         }
    232         mproc(state, buffer, n, x, y);
    233         sproc(state, buffer, n, dstC);
    234 
    235         if ((count -= n) == 0) {
    236             break;
    237         }
    238         x += n;
    239         dstC += n;
    240     }
    241 }
    242 
    243 ///////////////////////////////////////////////////////////////////////////////
    244 
    245 #include "SkUnPreMultiply.h"
    246 #include "SkColorShader.h"
    247 #include "SkEmptyShader.h"
    248 
    249 // returns true and set color if the bitmap can be drawn as a single color
    250 // (for efficiency)
    251 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
    252     if (1 != bm.width() || 1 != bm.height()) {
    253         return false;
    254     }
    255 
    256     SkAutoLockPixels alp(bm);
    257     if (!bm.readyToDraw()) {
    258         return false;
    259     }
    260 
    261     switch (bm.config()) {
    262         case SkBitmap::kARGB_8888_Config:
    263             *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
    264             return true;
    265         case SkBitmap::kRGB_565_Config:
    266             *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
    267             return true;
    268         case SkBitmap::kIndex8_Config:
    269             *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
    270             return true;
    271         default: // just skip the other configs for now
    272             break;
    273     }
    274     return false;
    275 }
    276 
    277 #include "SkTemplatesPriv.h"
    278 
    279 static bool bitmapIsTooBig(const SkBitmap& bm) {
    280     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
    281     // communicates between its matrix-proc and its sampler-proc. Until we can
    282     // widen that, we have to reject bitmaps that are larger.
    283     //
    284     const int maxSize = 65535;
    285 
    286     return bm.width() > maxSize || bm.height() > maxSize;
    287 }
    288 
    289 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
    290                                        TileMode tmx, TileMode tmy,
    291                                        void* storage, size_t storageSize) {
    292     SkShader* shader;
    293     SkColor color;
    294     if (src.isNull() || bitmapIsTooBig(src)) {
    295         SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
    296     }
    297     else if (canUseColorShader(src, &color)) {
    298         SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
    299                               (color));
    300     } else {
    301         SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
    302                               storageSize, (src, tmx, tmy));
    303     }
    304     return shader;
    305 }
    306 
    307 ///////////////////////////////////////////////////////////////////////////////
    308 
    309 #ifdef SK_DEVELOPER
    310 void SkBitmapProcShader::toString(SkString* str) const {
    311     static const char* gTileModeName[SkShader::kTileModeCount] = {
    312         "clamp", "repeat", "mirror"
    313     };
    314 
    315     str->append("BitmapShader: (");
    316 
    317     str->appendf("(%s, %s)",
    318                  gTileModeName[fState.fTileModeX],
    319                  gTileModeName[fState.fTileModeY]);
    320 
    321     str->append(" ");
    322     fRawBitmap.toString(str);
    323 
    324     this->INHERITED::toString(str);
    325 
    326     str->append(")");
    327 }
    328 #endif
    329 
    330 ///////////////////////////////////////////////////////////////////////////////
    331 
    332 #if SK_SUPPORT_GPU
    333 
    334 #include "GrTextureAccess.h"
    335 #include "effects/GrSimpleTextureEffect.h"
    336 #include "SkGr.h"
    337 
    338 GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
    339     SkMatrix matrix;
    340     matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
    341 
    342     if (this->hasLocalMatrix()) {
    343         SkMatrix inverse;
    344         if (!this->getLocalMatrix().invert(&inverse)) {
    345             return NULL;
    346         }
    347         matrix.preConcat(inverse);
    348     }
    349     SkShader::TileMode tm[] = {
    350         (TileMode)fState.fTileModeX,
    351         (TileMode)fState.fTileModeY,
    352     };
    353 
    354     // Must set wrap and filter on the sampler before requesting a texture.
    355     GrTextureParams params(tm, paint.isFilterBitmap());
    356     GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, &params);
    357 
    358     if (NULL == texture) {
    359         SkDebugf("Couldn't convert bitmap to texture.\n");
    360         return NULL;
    361     }
    362 
    363     GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params);
    364     GrUnlockAndUnrefCachedBitmapTexture(texture);
    365     return effect;
    366 }
    367 #endif
    368