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