SkBitmapProcShader.cpp revision 4c1037238c8ebcef8c75b5d43730ed308a11102c
1#include "SkBitmapProcShader.h" 2#include "SkColorPriv.h" 3#include "SkPixelRef.h" 4 5bool 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 19SkBitmapProcShader::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 27SkBitmapProcShader::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 35void SkBitmapProcShader::beginSession() { 36 this->INHERITED::beginSession(); 37 38 fRawBitmap.lockPixels(); 39} 40 41void SkBitmapProcShader::endSession() { 42 fRawBitmap.unlockPixels(); 43 44 this->INHERITED::endSession(); 45} 46 47bool 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 62void 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 70static 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 75bool 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#define TEST_BUFFER_OVERRITEx 141 142#ifdef TEST_BUFFER_OVERRITE 143 #define TEST_BUFFER_EXTRA 32 144 #define TEST_PATTERN 0x88888888 145#else 146 #define TEST_BUFFER_EXTRA 0 147#endif 148 149void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 150 const SkBitmapProcState& state = fState; 151 if (state.fShaderProc32) { 152 state.fShaderProc32(state, x, y, dstC, count); 153 return; 154 } 155 156 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; 157 SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; 158 SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32; 159 int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); 160 161 SkASSERT(state.fBitmap->getPixels()); 162 SkASSERT(state.fBitmap->pixelRef() == NULL || 163 state.fBitmap->pixelRef()->getLockCount()); 164 165 for (;;) { 166 int n = count; 167 if (n > max) { 168 n = max; 169 } 170 SkASSERT(n > 0 && n < BUF_MAX*2); 171#ifdef TEST_BUFFER_OVERRITE 172 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) { 173 buffer[BUF_MAX + i] = TEST_PATTERN; 174 } 175#endif 176 mproc(state, buffer, n, x, y); 177#ifdef TEST_BUFFER_OVERRITE 178 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) { 179 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN); 180 } 181#endif 182 sproc(state, buffer, n, dstC); 183 184 if ((count -= n) == 0) { 185 break; 186 } 187 SkASSERT(count > 0); 188 x += n; 189 dstC += n; 190 } 191} 192 193void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { 194 const SkBitmapProcState& state = fState; 195 if (state.fShaderProc16) { 196 state.fShaderProc16(state, x, y, dstC, count); 197 return; 198 } 199 200 uint32_t buffer[BUF_MAX]; 201 SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; 202 SkBitmapProcState::SampleProc16 sproc = state.fSampleProc16; 203 int max = fState.maxCountForBufferSize(sizeof(buffer)); 204 205 SkASSERT(state.fBitmap->getPixels()); 206 SkASSERT(state.fBitmap->pixelRef() == NULL || 207 state.fBitmap->pixelRef()->getLockCount()); 208 209 for (;;) { 210 int n = count; 211 if (n > max) { 212 n = max; 213 } 214 mproc(state, buffer, n, x, y); 215 sproc(state, buffer, n, dstC); 216 217 if ((count -= n) == 0) { 218 break; 219 } 220 x += n; 221 dstC += n; 222 } 223} 224 225/////////////////////////////////////////////////////////////////////////////// 226 227#include "SkUnPreMultiply.h" 228#include "SkColorShader.h" 229 230// returns true and set color if the bitmap can be drawn as a single color 231// (for efficiency) 232static bool canUseColorShader(const SkBitmap& bm, SkColor* color) { 233 if (1 != bm.width() || 1 != bm.height()) { 234 return false; 235 } 236 237 SkAutoLockPixels alp(bm); 238 if (!bm.readyToDraw()) { 239 return false; 240 } 241 242 switch (bm.config()) { 243 case SkBitmap::kARGB_8888_Config: 244 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0)); 245 return true; 246 case SkBitmap::kRGB_565_Config: 247 *color = SkPixel16ToColor(*bm.getAddr16(0, 0)); 248 return true; 249 case SkBitmap::kIndex8_Config: 250 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0)); 251 return true; 252 default: // just skip the other configs for now 253 break; 254 } 255 return false; 256} 257 258#include "SkTemplatesPriv.h" 259 260SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, 261 TileMode tmx, TileMode tmy, 262 void* storage, size_t storageSize) { 263 SkShader* shader; 264 SkColor color; 265 if (canUseColorShader(src, &color)) { 266 SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize, 267 (color)); 268 } else { 269 SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage, 270 storageSize, (src, tmx, tmy)); 271 } 272 return shader; 273} 274 275static SkFlattenable::Registrar gBitmapProcShaderReg("SkBitmapProcShader", 276 SkBitmapProcShader::CreateProc); 277 278/////////////////////////////////////////////////////////////////////////////// 279 280static const char* gTileModeName[] = { 281 "clamp", "repeat", "mirror" 282}; 283 284bool SkBitmapProcShader::toDumpString(SkString* str) const { 285 str->printf("BitmapShader: [%d %d %d", 286 fRawBitmap.width(), fRawBitmap.height(), 287 fRawBitmap.bytesPerPixel()); 288 289 // add the pixelref 290 SkPixelRef* pr = fRawBitmap.pixelRef(); 291 if (pr) { 292 const char* uri = pr->getURI(); 293 if (uri) { 294 str->appendf(" \"%s\"", uri); 295 } 296 } 297 298 // add the (optional) matrix 299 { 300 SkMatrix m; 301 if (this->getLocalMatrix(&m)) { 302 SkString info; 303 m.toDumpString(&info); 304 str->appendf(" %s", info.c_str()); 305 } 306 } 307 308 str->appendf(" [%s %s]]", 309 gTileModeName[fState.fTileModeX], 310 gTileModeName[fState.fTileModeY]); 311 return true; 312} 313 314