| #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) { |
| const SkBitmapProcState& state = fState; |
| if (state.fShaderProc32) { |
| state.fShaderProc32(state, x, y, dstC, count); |
| return; |
| } |
| |
| uint32_t buffer[BUF_MAX]; |
| 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) { |
| const SkBitmapProcState& state = fState; |
| if (state.fShaderProc16) { |
| state.fShaderProc16(state, x, y, dstC, count); |
| return; |
| } |
| |
| uint32_t buffer[BUF_MAX]; |
| 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; |
| } |
| |