SkBitmapProcShader.cpp revision 7f6e1e9caa4ced154c23701768e6c618dfe6ad48
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 75// return true if the config can possibly have per-pixel alpha, ignoring the 76// current setting of isOpaque. 77static bool canSupportPerPixelAlpha(const SkBitmap& bm) { 78 // return true unless we're guaranteed to be opaque 79 return bm.config() != SkBitmap::kRGB_565_Config; 80} 81 82bool SkBitmapProcShader::setContext(const SkBitmap& device, 83 const SkPaint& paint, 84 const SkMatrix& matrix) { 85 // do this first, so we have a correct inverse matrix 86 if (!this->INHERITED::setContext(device, paint, matrix)) { 87 return false; 88 } 89 90 fState.fOrigBitmap = fRawBitmap; 91 fState.fOrigBitmap.lockPixels(); 92 if (fState.fOrigBitmap.getPixels() == NULL) { 93 fState.fOrigBitmap.unlockPixels(); 94 return false; 95 } 96 97 if (!fState.chooseProcs(this->getTotalInverse(), paint)) { 98 return false; 99 } 100 101 const SkBitmap& bitmap = *fState.fBitmap; 102 bool bitmapIsOpaque = bitmap.isOpaque(); 103 104 // filtering doesn't guarantee that opaque stays opaque (finite precision) 105 // so pretend we're not opaque if we're being asked to filter. If we had 106 // more blit-procs, we could specialize on opaque src, and just OR in 0xFF 107 // after the filter to be sure... 108 /* 109 (some time later) 110 Adding check for canSupportPerPixelAlpha, since bitmaps that are 565 111 (for example) will *always* be opaque, even after filtering. 112 113 Would be really nice to never do this, if we could ensure that 114 filtering didn't introduct non-opaqueness accidentally. 115 */ 116 if (paint.isFilterBitmap() && canSupportPerPixelAlpha(bitmap)) { 117 bitmapIsOpaque = false; 118 } 119 120 // update fFlags 121 uint32_t flags = 0; 122 if (bitmapIsOpaque && (255 == this->getPaintAlpha())) { 123 flags |= kOpaqueAlpha_Flag; 124 } 125 126 switch (bitmap.config()) { 127 case SkBitmap::kRGB_565_Config: 128 flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag); 129 break; 130 case SkBitmap::kIndex8_Config: 131 case SkBitmap::kARGB_8888_Config: 132 if (bitmapIsOpaque) { 133 flags |= kHasSpan16_Flag; 134 } 135 break; 136 case SkBitmap::kA8_Config: 137 break; // never set kHasSpan16_Flag 138 default: 139 break; 140 } 141 142 if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) { 143 // gradients can auto-dither in their 16bit sampler, but we don't so 144 // we clear the flag here. 145 flags &= ~kHasSpan16_Flag; 146 } 147 148 // if we're only 1-pixel heigh, and we don't rotate, then we can claim this 149 if (1 == bitmap.height() && 150 only_scale_and_translate(this->getTotalInverse())) { 151 flags |= kConstInY32_Flag; 152 if (flags & kHasSpan16_Flag) { 153 flags |= kConstInY16_Flag; 154 } 155 } 156 157 fFlags = flags; 158 return true; 159} 160 161#define BUF_MAX 128 162 163void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 164 const SkBitmapProcState& state = fState; 165 if (state.fShaderProc32) { 166 state.fShaderProc32(state, x, y, dstC, count); 167 return; 168 } 169 170 uint32_t buffer[BUF_MAX]; 171 SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; 172 SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32; 173 int max = fState.maxCountForBufferSize(sizeof(buffer)); 174 175 SkASSERT(state.fBitmap->getPixels()); 176 SkASSERT(state.fBitmap->pixelRef() == NULL || 177 state.fBitmap->pixelRef()->getLockCount()); 178 179 for (;;) { 180 int n = count; 181 if (n > max) { 182 n = max; 183 } 184 mproc(state, buffer, n, x, y); 185 sproc(state, buffer, n, dstC); 186 187 if ((count -= n) == 0) { 188 break; 189 } 190 x += n; 191 dstC += n; 192 } 193} 194 195void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { 196 const SkBitmapProcState& state = fState; 197 if (state.fShaderProc16) { 198 state.fShaderProc16(state, x, y, dstC, count); 199 return; 200 } 201 202 uint32_t buffer[BUF_MAX]; 203 SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; 204 SkBitmapProcState::SampleProc16 sproc = state.fSampleProc16; 205 int max = fState.maxCountForBufferSize(sizeof(buffer)); 206 207 SkASSERT(state.fBitmap->getPixels()); 208 SkASSERT(state.fBitmap->pixelRef() == NULL || 209 state.fBitmap->pixelRef()->getLockCount()); 210 211 for (;;) { 212 int n = count; 213 if (n > max) { 214 n = max; 215 } 216 mproc(state, buffer, n, x, y); 217 sproc(state, buffer, n, dstC); 218 219 if ((count -= n) == 0) { 220 break; 221 } 222 x += n; 223 dstC += n; 224 } 225} 226 227/////////////////////////////////////////////////////////////////////////////// 228 229#include "SkUnPreMultiply.h" 230#include "SkColorShader.h" 231 232// returns true and set color if the bitmap can be drawn as a single color 233// (for efficiency) 234static bool canUseColorShader(const SkBitmap& bm, SkColor* color) { 235 if (1 != bm.width() || 1 != bm.height()) { 236 return false; 237 } 238 239 SkAutoLockPixels alp(bm); 240 if (!bm.readyToDraw()) { 241 return false; 242 } 243 244 switch (bm.config()) { 245 case SkBitmap::kARGB_8888_Config: 246 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0)); 247 return true; 248 case SkBitmap::kRGB_565_Config: 249 *color = SkPixel16ToColor(*bm.getAddr16(0, 0)); 250 return true; 251 case SkBitmap::kIndex8_Config: 252 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0)); 253 return true; 254 default: // just skip the other configs for now 255 break; 256 } 257 return false; 258} 259 260#include "SkTemplatesPriv.h" 261 262SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, 263 TileMode tmx, TileMode tmy, 264 void* storage, size_t storageSize) { 265 SkShader* shader; 266 SkColor color; 267 if (canUseColorShader(src, &color)) { 268 SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize, 269 (color)); 270 } else { 271 SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage, 272 storageSize, (src, tmx, tmy)); 273 } 274 return shader; 275} 276 277static SkFlattenable::Registrar gBitmapProcShaderReg("SkBitmapProcShader", 278 SkBitmapProcShader::CreateProc); 279 280/////////////////////////////////////////////////////////////////////////////// 281 282static const char* gTileModeName[] = { 283 "clamp", "repeat", "mirror" 284}; 285 286bool SkBitmapProcShader::toDumpString(SkString* str) const { 287 str->printf("BitmapShader: [%d %d %d", 288 fRawBitmap.width(), fRawBitmap.height(), 289 fRawBitmap.bytesPerPixel()); 290 291 // add the pixelref 292 SkPixelRef* pr = fRawBitmap.pixelRef(); 293 if (pr) { 294 const char* uri = pr->getURI(); 295 if (uri) { 296 str->appendf(" \"%s\"", uri); 297 } 298 } 299 300 // add the (optional) matrix 301 { 302 SkMatrix m; 303 if (this->getLocalMatrix(&m)) { 304 SkString info; 305 m.toDumpString(&info); 306 str->appendf(" %s", info.c_str()); 307 } 308 } 309 310 str->appendf(" [%s %s]]", 311 gTileModeName[fState.fTileModeX], 312 gTileModeName[fState.fTileModeY]); 313 return true; 314} 315 316