#include "SkBitmapProcShader.h" #include "SkColorPriv.h" #include "SkPixelRef.h" bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) { switch (bm.config()) { case SkBitmap::kA8_Config: case SkBitmap::kRGB_565_Config: case SkBitmap::kIndex8_Config: case SkBitmap::kARGB_8888_Config: // if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx)) return true; default: break; } return false; } SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy) { fRawBitmap = src; fState.fTileModeX = (uint8_t)tmx; fState.fTileModeY = (uint8_t)tmy; fFlags = 0; // computed in setContext } SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { fRawBitmap.unflatten(buffer); fState.fTileModeX = buffer.readU8(); fState.fTileModeY = buffer.readU8(); fFlags = 0; // computed in setContext } void SkBitmapProcShader::beginSession() { this->INHERITED::beginSession(); fRawBitmap.lockPixels(); } void SkBitmapProcShader::endSession() { fRawBitmap.unlockPixels(); this->INHERITED::endSession(); } bool SkBitmapProcShader::asABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) { if (texture) { *texture = fRawBitmap; } if (texM) { texM->reset(); } if (xy) { xy[0] = (TileMode)fState.fTileModeX; xy[1] = (TileMode)fState.fTileModeY; } return true; } void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) { this->INHERITED::flatten(buffer); fRawBitmap.flatten(buffer); buffer.write8(fState.fTileModeX); buffer.write8(fState.fTileModeY); } static bool only_scale_and_translate(const SkMatrix& matrix) { unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; return (matrix.getType() & ~mask) == 0; } bool SkBitmapProcShader::setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix) { // do this first, so we have a correct inverse matrix if (!this->INHERITED::setContext(device, paint, matrix)) { return false; } fState.fOrigBitmap = fRawBitmap; fState.fOrigBitmap.lockPixels(); if (fState.fOrigBitmap.getPixels() == NULL) { fState.fOrigBitmap.unlockPixels(); return false; } if (!fState.chooseProcs(this->getTotalInverse(), paint)) { return false; } bool bitmapIsOpaque = fState.fBitmap->isOpaque(); // filtering doesn't guarantee that opaque stays opaque (finite precision) // so pretend we're not opaque if we're being asked to filter. If we had // more blit-procs, we could specialize on opaque src, and just OR in 0xFF // after the filter to be sure... if (paint.isFilterBitmap()) { bitmapIsOpaque = false; } // update fFlags fFlags = 0; if (bitmapIsOpaque && (255 == this->getPaintAlpha())) { fFlags |= kOpaqueAlpha_Flag; } switch (fState.fBitmap->config()) { case SkBitmap::kRGB_565_Config: fFlags |= (kHasSpan16_Flag | kIntrinsicly16_Flag); break; case SkBitmap::kIndex8_Config: case SkBitmap::kARGB_8888_Config: if (bitmapIsOpaque) { fFlags |= kHasSpan16_Flag; } break; case SkBitmap::kA8_Config: break; // never set kHasSpan16_Flag default: break; } // if we're only 1-pixel heigh, and we don't rotate, then we can claim this if (1 == fState.fBitmap->height() && only_scale_and_translate(this->getTotalInverse())) { fFlags |= kConstInY_Flag; } return true; } #define BUF_MAX 128 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { uint32_t buffer[BUF_MAX]; const SkBitmapProcState& state = fState; SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32; int max = fState.fDoFilter ? (BUF_MAX >> 1) : BUF_MAX; SkASSERT(state.fBitmap->getPixels()); SkASSERT(state.fBitmap->pixelRef() == NULL || state.fBitmap->pixelRef()->getLockCount()); for (;;) { int n = count; if (n > max) { n = max; } mproc(state, buffer, n, x, y); sproc(state, buffer, n, dstC); if ((count -= n) == 0) { break; } x += n; dstC += n; } } void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { uint32_t buffer[BUF_MAX]; const SkBitmapProcState& state = fState; SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; SkBitmapProcState::SampleProc16 sproc = state.fSampleProc16; int max = fState.fDoFilter ? (BUF_MAX >> 1) : BUF_MAX; SkASSERT(state.fBitmap->getPixels()); SkASSERT(state.fBitmap->pixelRef() == NULL || state.fBitmap->pixelRef()->getLockCount()); for (;;) { int n = count; if (n > max) { n = max; } mproc(state, buffer, n, x, y); sproc(state, buffer, n, dstC); if ((count -= n) == 0) { break; } x += n; dstC += n; } } /////////////////////////////////////////////////////////////////////////////// #include "SkTemplatesPriv.h" SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, void* storage, size_t storageSize) { SkShader* shader; SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage, storageSize, (src, tmx, tmy)); return shader; } static SkFlattenable::Registrar gBitmapProcShaderReg("SkBitmapProcShader", SkBitmapProcShader::CreateProc); /////////////////////////////////////////////////////////////////////////////// static const char* gTileModeName[] = { "clamp", "repeat", "mirror" }; bool SkBitmapProcShader::toDumpString(SkString* str) const { str->printf("BitmapShader: [%d %d %d", fRawBitmap.width(), fRawBitmap.height(), fRawBitmap.bytesPerPixel()); // add the pixelref SkPixelRef* pr = fRawBitmap.pixelRef(); if (pr) { const char* uri = pr->getURI(); if (uri) { str->appendf(" \"%s\"", uri); } } // add the (optional) matrix { SkMatrix m; if (this->getLocalMatrix(&m)) { SkString info; m.toDumpString(&info); str->appendf(" %s", info.c_str()); } } str->appendf(" [%s %s]]", gTileModeName[fState.fTileModeX], gTileModeName[fState.fTileModeY]); return true; }