1 #include "SkBitmapProcShader.h" 2 #include "SkColorPriv.h" 3 #include "SkPixelRef.h" 4 5 bool 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 19 SkBitmapProcShader::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 27 SkBitmapProcShader::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 35 void SkBitmapProcShader::beginSession() { 36 this->INHERITED::beginSession(); 37 38 fRawBitmap.lockPixels(); 39 } 40 41 void SkBitmapProcShader::endSession() { 42 fRawBitmap.unlockPixels(); 43 44 this->INHERITED::endSession(); 45 } 46 47 SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture, 48 SkMatrix* texM, 49 TileMode xy[], 50 SkScalar* twoPointRadialParams) const { 51 if (texture) { 52 *texture = fRawBitmap; 53 } 54 if (texM) { 55 texM->reset(); 56 } 57 if (xy) { 58 xy[0] = (TileMode)fState.fTileModeX; 59 xy[1] = (TileMode)fState.fTileModeY; 60 } 61 return kDefault_BitmapType; 62 } 63 64 void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) { 65 this->INHERITED::flatten(buffer); 66 67 fRawBitmap.flatten(buffer); 68 buffer.write8(fState.fTileModeX); 69 buffer.write8(fState.fTileModeY); 70 } 71 72 static bool only_scale_and_translate(const SkMatrix& matrix) { 73 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 74 return (matrix.getType() & ~mask) == 0; 75 } 76 77 bool SkBitmapProcShader::setContext(const SkBitmap& device, 78 const SkPaint& paint, 79 const SkMatrix& matrix) { 80 // do this first, so we have a correct inverse matrix 81 if (!this->INHERITED::setContext(device, paint, matrix)) { 82 return false; 83 } 84 85 fState.fOrigBitmap = fRawBitmap; 86 fState.fOrigBitmap.lockPixels(); 87 if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) { 88 fState.fOrigBitmap.unlockPixels(); 89 return false; 90 } 91 92 if (!fState.chooseProcs(this->getTotalInverse(), paint)) { 93 return false; 94 } 95 96 const SkBitmap& bitmap = *fState.fBitmap; 97 bool bitmapIsOpaque = bitmap.isOpaque(); 98 99 // update fFlags 100 uint32_t flags = 0; 101 if (bitmapIsOpaque && (255 == this->getPaintAlpha())) { 102 flags |= kOpaqueAlpha_Flag; 103 } 104 105 switch (bitmap.config()) { 106 case SkBitmap::kRGB_565_Config: 107 flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag); 108 break; 109 case SkBitmap::kIndex8_Config: 110 case SkBitmap::kARGB_8888_Config: 111 if (bitmapIsOpaque) { 112 flags |= kHasSpan16_Flag; 113 } 114 break; 115 case SkBitmap::kA8_Config: 116 break; // never set kHasSpan16_Flag 117 default: 118 break; 119 } 120 121 if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) { 122 // gradients can auto-dither in their 16bit sampler, but we don't so 123 // we clear the flag here. 124 flags &= ~kHasSpan16_Flag; 125 } 126 127 // if we're only 1-pixel heigh, and we don't rotate, then we can claim this 128 if (1 == bitmap.height() && 129 only_scale_and_translate(this->getTotalInverse())) { 130 flags |= kConstInY32_Flag; 131 if (flags & kHasSpan16_Flag) { 132 flags |= kConstInY16_Flag; 133 } 134 } 135 136 fFlags = flags; 137 return true; 138 } 139 140 #define BUF_MAX 128 141 142 #define TEST_BUFFER_OVERRITEx 143 144 #ifdef TEST_BUFFER_OVERRITE 145 #define TEST_BUFFER_EXTRA 32 146 #define TEST_PATTERN 0x88888888 147 #else 148 #define TEST_BUFFER_EXTRA 0 149 #endif 150 151 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 152 const SkBitmapProcState& state = fState; 153 if (state.fShaderProc32) { 154 state.fShaderProc32(state, x, y, dstC, count); 155 return; 156 } 157 158 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; 159 SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; 160 SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32; 161 int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); 162 163 SkASSERT(state.fBitmap->getPixels()); 164 SkASSERT(state.fBitmap->pixelRef() == NULL || 165 state.fBitmap->pixelRef()->getLockCount()); 166 167 for (;;) { 168 int n = count; 169 if (n > max) { 170 n = max; 171 } 172 SkASSERT(n > 0 && n < BUF_MAX*2); 173 #ifdef TEST_BUFFER_OVERRITE 174 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) { 175 buffer[BUF_MAX + i] = TEST_PATTERN; 176 } 177 #endif 178 mproc(state, buffer, n, x, y); 179 #ifdef TEST_BUFFER_OVERRITE 180 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) { 181 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN); 182 } 183 #endif 184 sproc(state, buffer, n, dstC); 185 186 if ((count -= n) == 0) { 187 break; 188 } 189 SkASSERT(count > 0); 190 x += n; 191 dstC += n; 192 } 193 } 194 195 void 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) 234 static 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 262 SkShader* 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 277 static SkFlattenable::Registrar gBitmapProcShaderReg("SkBitmapProcShader", 278 SkBitmapProcShader::CreateProc); 279 280 /////////////////////////////////////////////////////////////////////////////// 281 282 static const char* gTileModeName[] = { 283 "clamp", "repeat", "mirror" 284 }; 285 286 bool 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