1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "SkBitmapProcShader.h" 9 #include "SkColorPriv.h" 10 #include "SkPixelRef.h" 11 12 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) { 13 switch (bm.config()) { 14 case SkBitmap::kA8_Config: 15 case SkBitmap::kRGB_565_Config: 16 case SkBitmap::kIndex8_Config: 17 case SkBitmap::kARGB_8888_Config: 18 // if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx)) 19 return true; 20 default: 21 break; 22 } 23 return false; 24 } 25 26 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, 27 TileMode tmx, TileMode tmy) { 28 fRawBitmap = src; 29 fState.fTileModeX = (uint8_t)tmx; 30 fState.fTileModeY = (uint8_t)tmy; 31 fFlags = 0; // computed in setContext 32 } 33 34 SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer) 35 : INHERITED(buffer) { 36 fRawBitmap.unflatten(buffer); 37 fState.fTileModeX = buffer.readU8(); 38 fState.fTileModeY = buffer.readU8(); 39 fFlags = 0; // computed in setContext 40 } 41 42 void SkBitmapProcShader::beginSession() { 43 this->INHERITED::beginSession(); 44 45 fRawBitmap.lockPixels(); 46 } 47 48 void SkBitmapProcShader::endSession() { 49 fRawBitmap.unlockPixels(); 50 51 this->INHERITED::endSession(); 52 } 53 54 SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture, 55 SkMatrix* texM, 56 TileMode xy[], 57 SkScalar* twoPointRadialParams) const { 58 if (texture) { 59 *texture = fRawBitmap; 60 } 61 if (texM) { 62 texM->reset(); 63 } 64 if (xy) { 65 xy[0] = (TileMode)fState.fTileModeX; 66 xy[1] = (TileMode)fState.fTileModeY; 67 } 68 return kDefault_BitmapType; 69 } 70 71 void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) { 72 this->INHERITED::flatten(buffer); 73 74 fRawBitmap.flatten(buffer); 75 buffer.write8(fState.fTileModeX); 76 buffer.write8(fState.fTileModeY); 77 } 78 79 static bool only_scale_and_translate(const SkMatrix& matrix) { 80 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 81 return (matrix.getType() & ~mask) == 0; 82 } 83 84 bool SkBitmapProcShader::isOpaque() const { 85 return fRawBitmap.isOpaque(); 86 } 87 88 bool SkBitmapProcShader::setContext(const SkBitmap& device, 89 const SkPaint& paint, 90 const SkMatrix& matrix) { 91 // do this first, so we have a correct inverse matrix 92 if (!this->INHERITED::setContext(device, paint, matrix)) { 93 return false; 94 } 95 96 fState.fOrigBitmap = fRawBitmap; 97 fState.fOrigBitmap.lockPixels(); 98 if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) { 99 fState.fOrigBitmap.unlockPixels(); 100 return false; 101 } 102 103 if (!fState.chooseProcs(this->getTotalInverse(), paint)) { 104 return false; 105 } 106 107 const SkBitmap& bitmap = *fState.fBitmap; 108 bool bitmapIsOpaque = bitmap.isOpaque(); 109 110 // update fFlags 111 uint32_t flags = 0; 112 if (bitmapIsOpaque && (255 == this->getPaintAlpha())) { 113 flags |= kOpaqueAlpha_Flag; 114 } 115 116 switch (bitmap.config()) { 117 case SkBitmap::kRGB_565_Config: 118 flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag); 119 break; 120 case SkBitmap::kIndex8_Config: 121 case SkBitmap::kARGB_8888_Config: 122 if (bitmapIsOpaque) { 123 flags |= kHasSpan16_Flag; 124 } 125 break; 126 case SkBitmap::kA8_Config: 127 break; // never set kHasSpan16_Flag 128 default: 129 break; 130 } 131 132 if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) { 133 // gradients can auto-dither in their 16bit sampler, but we don't so 134 // we clear the flag here. 135 flags &= ~kHasSpan16_Flag; 136 } 137 138 // if we're only 1-pixel heigh, and we don't rotate, then we can claim this 139 if (1 == bitmap.height() && 140 only_scale_and_translate(this->getTotalInverse())) { 141 flags |= kConstInY32_Flag; 142 if (flags & kHasSpan16_Flag) { 143 flags |= kConstInY16_Flag; 144 } 145 } 146 147 fFlags = flags; 148 return true; 149 } 150 151 #define BUF_MAX 128 152 153 #define TEST_BUFFER_OVERRITEx 154 155 #ifdef TEST_BUFFER_OVERRITE 156 #define TEST_BUFFER_EXTRA 32 157 #define TEST_PATTERN 0x88888888 158 #else 159 #define TEST_BUFFER_EXTRA 0 160 #endif 161 162 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 163 const SkBitmapProcState& state = fState; 164 if (state.fShaderProc32) { 165 state.fShaderProc32(state, x, y, dstC, count); 166 return; 167 } 168 169 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; 170 SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; 171 SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32; 172 int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); 173 174 SkASSERT(state.fBitmap->getPixels()); 175 SkASSERT(state.fBitmap->pixelRef() == NULL || 176 state.fBitmap->pixelRef()->isLocked()); 177 178 for (;;) { 179 int n = count; 180 if (n > max) { 181 n = max; 182 } 183 SkASSERT(n > 0 && n < BUF_MAX*2); 184 #ifdef TEST_BUFFER_OVERRITE 185 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) { 186 buffer[BUF_MAX + i] = TEST_PATTERN; 187 } 188 #endif 189 mproc(state, buffer, n, x, y); 190 #ifdef TEST_BUFFER_OVERRITE 191 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) { 192 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN); 193 } 194 #endif 195 sproc(state, buffer, n, dstC); 196 197 if ((count -= n) == 0) { 198 break; 199 } 200 SkASSERT(count > 0); 201 x += n; 202 dstC += n; 203 } 204 } 205 206 void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { 207 const SkBitmapProcState& state = fState; 208 if (state.fShaderProc16) { 209 state.fShaderProc16(state, x, y, dstC, count); 210 return; 211 } 212 213 uint32_t buffer[BUF_MAX]; 214 SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; 215 SkBitmapProcState::SampleProc16 sproc = state.fSampleProc16; 216 int max = fState.maxCountForBufferSize(sizeof(buffer)); 217 218 SkASSERT(state.fBitmap->getPixels()); 219 SkASSERT(state.fBitmap->pixelRef() == NULL || 220 state.fBitmap->pixelRef()->isLocked()); 221 222 for (;;) { 223 int n = count; 224 if (n > max) { 225 n = max; 226 } 227 mproc(state, buffer, n, x, y); 228 sproc(state, buffer, n, dstC); 229 230 if ((count -= n) == 0) { 231 break; 232 } 233 x += n; 234 dstC += n; 235 } 236 } 237 238 /////////////////////////////////////////////////////////////////////////////// 239 240 #include "SkUnPreMultiply.h" 241 #include "SkColorShader.h" 242 #include "SkEmptyShader.h" 243 244 // returns true and set color if the bitmap can be drawn as a single color 245 // (for efficiency) 246 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) { 247 if (1 != bm.width() || 1 != bm.height()) { 248 return false; 249 } 250 251 SkAutoLockPixels alp(bm); 252 if (!bm.readyToDraw()) { 253 return false; 254 } 255 256 switch (bm.config()) { 257 case SkBitmap::kARGB_8888_Config: 258 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0)); 259 return true; 260 case SkBitmap::kRGB_565_Config: 261 *color = SkPixel16ToColor(*bm.getAddr16(0, 0)); 262 return true; 263 case SkBitmap::kIndex8_Config: 264 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0)); 265 return true; 266 default: // just skip the other configs for now 267 break; 268 } 269 return false; 270 } 271 272 #include "SkTemplatesPriv.h" 273 274 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, 275 TileMode tmx, TileMode tmy, 276 void* storage, size_t storageSize) { 277 SkShader* shader; 278 SkColor color; 279 if (src.isNull()) { 280 SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize); 281 } 282 else if (canUseColorShader(src, &color)) { 283 SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize, 284 (color)); 285 } else { 286 SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage, 287 storageSize, (src, tmx, tmy)); 288 } 289 return shader; 290 } 291 292 SK_DEFINE_FLATTENABLE_REGISTRAR(SkBitmapProcShader) 293 294 /////////////////////////////////////////////////////////////////////////////// 295 296 static const char* gTileModeName[] = { 297 "clamp", "repeat", "mirror" 298 }; 299 300 bool SkBitmapProcShader::toDumpString(SkString* str) const { 301 str->printf("BitmapShader: [%d %d %d", 302 fRawBitmap.width(), fRawBitmap.height(), 303 fRawBitmap.bytesPerPixel()); 304 305 // add the pixelref 306 SkPixelRef* pr = fRawBitmap.pixelRef(); 307 if (pr) { 308 const char* uri = pr->getURI(); 309 if (uri) { 310 str->appendf(" \"%s\"", uri); 311 } 312 } 313 314 // add the (optional) matrix 315 { 316 SkMatrix m; 317 if (this->getLocalMatrix(&m)) { 318 SkString info; 319 m.toDumpString(&info); 320 str->appendf(" %s", info.c_str()); 321 } 322 } 323 324 str->appendf(" [%s %s]]", 325 gTileModeName[fState.fTileModeX], 326 gTileModeName[fState.fTileModeY]); 327 return true; 328 } 329 330