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 140void 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 172void 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) 211static 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 239SkShader* 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 254static SkFlattenable::Registrar gBitmapProcShaderReg("SkBitmapProcShader", 255 SkBitmapProcShader::CreateProc); 256 257/////////////////////////////////////////////////////////////////////////////// 258 259static const char* gTileModeName[] = { 260 "clamp", "repeat", "mirror" 261}; 262 263bool 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