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 "SkPixelRef.h"
     11 
     12 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
     13     switch (bm.config()) {
     14         case SkBitmap::kA8_Config:
     15         case SkBitmap::kRGB_565_Config:
     16         case SkBitmap::kIndex8_Config:
     17         case SkBitmap::kARGB_8888_Config:
     18     //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
     19                 return true;
     20         default:
     21             break;
     22     }
     23     return false;
     24 }
     25 
     26 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
     27                                        TileMode tmx, TileMode tmy) {
     28     fRawBitmap = src;
     29     fState.fTileModeX = (uint8_t)tmx;
     30     fState.fTileModeY = (uint8_t)tmy;
     31     fFlags = 0; // computed in setContext
     32 }
     33 
     34 SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
     35         : INHERITED(buffer) {
     36     fRawBitmap.unflatten(buffer);
     37     fState.fTileModeX = buffer.readU8();
     38     fState.fTileModeY = buffer.readU8();
     39     fFlags = 0; // computed in setContext
     40 }
     41 
     42 void SkBitmapProcShader::beginSession() {
     43     this->INHERITED::beginSession();
     44 
     45     fRawBitmap.lockPixels();
     46 }
     47 
     48 void SkBitmapProcShader::endSession() {
     49     fRawBitmap.unlockPixels();
     50 
     51     this->INHERITED::endSession();
     52 }
     53 
     54 SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
     55                                                    SkMatrix* texM,
     56                                                    TileMode xy[],
     57                                        SkScalar* twoPointRadialParams) const {
     58     if (texture) {
     59         *texture = fRawBitmap;
     60     }
     61     if (texM) {
     62         texM->reset();
     63     }
     64     if (xy) {
     65         xy[0] = (TileMode)fState.fTileModeX;
     66         xy[1] = (TileMode)fState.fTileModeY;
     67     }
     68     return kDefault_BitmapType;
     69 }
     70 
     71 void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) {
     72     this->INHERITED::flatten(buffer);
     73 
     74     fRawBitmap.flatten(buffer);
     75     buffer.write8(fState.fTileModeX);
     76     buffer.write8(fState.fTileModeY);
     77 }
     78 
     79 static bool only_scale_and_translate(const SkMatrix& matrix) {
     80     unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
     81     return (matrix.getType() & ~mask) == 0;
     82 }
     83 
     84 bool SkBitmapProcShader::isOpaque() const {
     85     return fRawBitmap.isOpaque();
     86 }
     87 
     88 bool SkBitmapProcShader::setContext(const SkBitmap& device,
     89                                     const SkPaint& paint,
     90                                     const SkMatrix& matrix) {
     91     // do this first, so we have a correct inverse matrix
     92     if (!this->INHERITED::setContext(device, paint, matrix)) {
     93         return false;
     94     }
     95 
     96     fState.fOrigBitmap = fRawBitmap;
     97     fState.fOrigBitmap.lockPixels();
     98     if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
     99         fState.fOrigBitmap.unlockPixels();
    100         return false;
    101     }
    102 
    103     if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
    104         return false;
    105     }
    106 
    107     const SkBitmap& bitmap = *fState.fBitmap;
    108     bool bitmapIsOpaque = bitmap.isOpaque();
    109 
    110     // update fFlags
    111     uint32_t flags = 0;
    112     if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
    113         flags |= kOpaqueAlpha_Flag;
    114     }
    115 
    116     switch (bitmap.config()) {
    117         case SkBitmap::kRGB_565_Config:
    118             flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
    119             break;
    120         case SkBitmap::kIndex8_Config:
    121         case SkBitmap::kARGB_8888_Config:
    122             if (bitmapIsOpaque) {
    123                 flags |= kHasSpan16_Flag;
    124             }
    125             break;
    126         case SkBitmap::kA8_Config:
    127             break;  // never set kHasSpan16_Flag
    128         default:
    129             break;
    130     }
    131 
    132     if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
    133         // gradients can auto-dither in their 16bit sampler, but we don't so
    134         // we clear the flag here.
    135         flags &= ~kHasSpan16_Flag;
    136     }
    137 
    138     // if we're only 1-pixel heigh, and we don't rotate, then we can claim this
    139     if (1 == bitmap.height() &&
    140             only_scale_and_translate(this->getTotalInverse())) {
    141         flags |= kConstInY32_Flag;
    142         if (flags & kHasSpan16_Flag) {
    143             flags |= kConstInY16_Flag;
    144         }
    145     }
    146 
    147     fFlags = flags;
    148     return true;
    149 }
    150 
    151 #define BUF_MAX     128
    152 
    153 #define TEST_BUFFER_OVERRITEx
    154 
    155 #ifdef TEST_BUFFER_OVERRITE
    156     #define TEST_BUFFER_EXTRA   32
    157     #define TEST_PATTERN    0x88888888
    158 #else
    159     #define TEST_BUFFER_EXTRA   0
    160 #endif
    161 
    162 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
    163     const SkBitmapProcState& state = fState;
    164     if (state.fShaderProc32) {
    165         state.fShaderProc32(state, x, y, dstC, count);
    166         return;
    167     }
    168 
    169     uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
    170     SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
    171     SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32;
    172     int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
    173 
    174     SkASSERT(state.fBitmap->getPixels());
    175     SkASSERT(state.fBitmap->pixelRef() == NULL ||
    176              state.fBitmap->pixelRef()->isLocked());
    177 
    178     for (;;) {
    179         int n = count;
    180         if (n > max) {
    181             n = max;
    182         }
    183         SkASSERT(n > 0 && n < BUF_MAX*2);
    184 #ifdef TEST_BUFFER_OVERRITE
    185         for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
    186             buffer[BUF_MAX + i] = TEST_PATTERN;
    187         }
    188 #endif
    189         mproc(state, buffer, n, x, y);
    190 #ifdef TEST_BUFFER_OVERRITE
    191         for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
    192             SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
    193         }
    194 #endif
    195         sproc(state, buffer, n, dstC);
    196 
    197         if ((count -= n) == 0) {
    198             break;
    199         }
    200         SkASSERT(count > 0);
    201         x += n;
    202         dstC += n;
    203     }
    204 }
    205 
    206 void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
    207     const SkBitmapProcState& state = fState;
    208     if (state.fShaderProc16) {
    209         state.fShaderProc16(state, x, y, dstC, count);
    210         return;
    211     }
    212 
    213     uint32_t buffer[BUF_MAX];
    214     SkBitmapProcState::MatrixProc   mproc = state.fMatrixProc;
    215     SkBitmapProcState::SampleProc16 sproc = state.fSampleProc16;
    216     int max = fState.maxCountForBufferSize(sizeof(buffer));
    217 
    218     SkASSERT(state.fBitmap->getPixels());
    219     SkASSERT(state.fBitmap->pixelRef() == NULL ||
    220              state.fBitmap->pixelRef()->isLocked());
    221 
    222     for (;;) {
    223         int n = count;
    224         if (n > max) {
    225             n = max;
    226         }
    227         mproc(state, buffer, n, x, y);
    228         sproc(state, buffer, n, dstC);
    229 
    230         if ((count -= n) == 0) {
    231             break;
    232         }
    233         x += n;
    234         dstC += n;
    235     }
    236 }
    237 
    238 ///////////////////////////////////////////////////////////////////////////////
    239 
    240 #include "SkUnPreMultiply.h"
    241 #include "SkColorShader.h"
    242 #include "SkEmptyShader.h"
    243 
    244 // returns true and set color if the bitmap can be drawn as a single color
    245 // (for efficiency)
    246 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
    247     if (1 != bm.width() || 1 != bm.height()) {
    248         return false;
    249     }
    250 
    251     SkAutoLockPixels alp(bm);
    252     if (!bm.readyToDraw()) {
    253         return false;
    254     }
    255 
    256     switch (bm.config()) {
    257         case SkBitmap::kARGB_8888_Config:
    258             *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
    259             return true;
    260         case SkBitmap::kRGB_565_Config:
    261             *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
    262             return true;
    263         case SkBitmap::kIndex8_Config:
    264             *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
    265             return true;
    266         default: // just skip the other configs for now
    267             break;
    268     }
    269     return false;
    270 }
    271 
    272 #include "SkTemplatesPriv.h"
    273 
    274 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
    275                                        TileMode tmx, TileMode tmy,
    276                                        void* storage, size_t storageSize) {
    277     SkShader* shader;
    278     SkColor color;
    279     if (src.isNull()) {
    280         SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
    281     }
    282     else if (canUseColorShader(src, &color)) {
    283         SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
    284                               (color));
    285     } else {
    286         SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
    287                               storageSize, (src, tmx, tmy));
    288     }
    289     return shader;
    290 }
    291 
    292 SK_DEFINE_FLATTENABLE_REGISTRAR(SkBitmapProcShader)
    293 
    294 ///////////////////////////////////////////////////////////////////////////////
    295 
    296 static const char* gTileModeName[] = {
    297     "clamp", "repeat", "mirror"
    298 };
    299 
    300 bool SkBitmapProcShader::toDumpString(SkString* str) const {
    301     str->printf("BitmapShader: [%d %d %d",
    302                 fRawBitmap.width(), fRawBitmap.height(),
    303                 fRawBitmap.bytesPerPixel());
    304 
    305     // add the pixelref
    306     SkPixelRef* pr = fRawBitmap.pixelRef();
    307     if (pr) {
    308         const char* uri = pr->getURI();
    309         if (uri) {
    310             str->appendf(" \"%s\"", uri);
    311         }
    312     }
    313 
    314     // add the (optional) matrix
    315     {
    316         SkMatrix m;
    317         if (this->getLocalMatrix(&m)) {
    318             SkString info;
    319             m.toDumpString(&info);
    320             str->appendf(" %s", info.c_str());
    321         }
    322     }
    323 
    324     str->appendf(" [%s %s]]",
    325                  gTileModeName[fState.fTileModeX],
    326                  gTileModeName[fState.fTileModeY]);
    327     return true;
    328 }
    329 
    330