SkBitmapProcShader.cpp revision 3bafe74a29c37761082980ed4ee9b831256bd27e
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 "SkFlattenableBuffers.h" 11#include "SkPixelRef.h" 12 13bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) { 14 switch (bm.config()) { 15 case SkBitmap::kA8_Config: 16 case SkBitmap::kRGB_565_Config: 17 case SkBitmap::kIndex8_Config: 18 case SkBitmap::kARGB_8888_Config: 19 // if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx)) 20 return true; 21 default: 22 break; 23 } 24 return false; 25} 26 27SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, 28 TileMode tmx, TileMode tmy) { 29 fRawBitmap = src; 30 fState.fTileModeX = (uint8_t)tmx; 31 fState.fTileModeY = (uint8_t)tmy; 32 fFlags = 0; // computed in setContext 33} 34 35SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer) 36 : INHERITED(buffer) { 37 buffer.readBitmap(&fRawBitmap); 38 fState.fTileModeX = buffer.readUInt(); 39 fState.fTileModeY = buffer.readUInt(); 40 fFlags = 0; // computed in setContext 41} 42 43void SkBitmapProcShader::beginSession() { 44 this->INHERITED::beginSession(); 45 46 fRawBitmap.lockPixels(); 47} 48 49void SkBitmapProcShader::endSession() { 50 fRawBitmap.unlockPixels(); 51 52 this->INHERITED::endSession(); 53} 54 55SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture, 56 SkMatrix* texM, 57 TileMode xy[]) 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 71void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const { 72 this->INHERITED::flatten(buffer); 73 74 buffer.writeBitmap(fRawBitmap); 75 buffer.writeUInt(fState.fTileModeX); 76 buffer.writeUInt(fState.fTileModeY); 77} 78 79static 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 84bool SkBitmapProcShader::isOpaque() const { 85 return fRawBitmap.isOpaque(); 86} 87 88bool 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 162void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 163 const SkBitmapProcState& state = fState; 164 if (state.getShaderProc32()) { 165 state.getShaderProc32()(state, x, y, dstC, count); 166 return; 167 } 168 169 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; 170 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 171 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32(); 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 206SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) { 207 if (fState.getShaderProc32()) { 208 *ctx = &fState; 209 return (ShadeProc)fState.getShaderProc32(); 210 } 211 return NULL; 212} 213 214void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { 215 const SkBitmapProcState& state = fState; 216 if (state.getShaderProc16()) { 217 state.getShaderProc16()(state, x, y, dstC, count); 218 return; 219 } 220 221 uint32_t buffer[BUF_MAX]; 222 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); 223 SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16(); 224 int max = fState.maxCountForBufferSize(sizeof(buffer)); 225 226 SkASSERT(state.fBitmap->getPixels()); 227 SkASSERT(state.fBitmap->pixelRef() == NULL || 228 state.fBitmap->pixelRef()->isLocked()); 229 230 for (;;) { 231 int n = count; 232 if (n > max) { 233 n = max; 234 } 235 mproc(state, buffer, n, x, y); 236 sproc(state, buffer, n, dstC); 237 238 if ((count -= n) == 0) { 239 break; 240 } 241 x += n; 242 dstC += n; 243 } 244} 245 246/////////////////////////////////////////////////////////////////////////////// 247 248#include "SkUnPreMultiply.h" 249#include "SkColorShader.h" 250#include "SkEmptyShader.h" 251 252// returns true and set color if the bitmap can be drawn as a single color 253// (for efficiency) 254static bool canUseColorShader(const SkBitmap& bm, SkColor* color) { 255 if (1 != bm.width() || 1 != bm.height()) { 256 return false; 257 } 258 259 SkAutoLockPixels alp(bm); 260 if (!bm.readyToDraw()) { 261 return false; 262 } 263 264 switch (bm.config()) { 265 case SkBitmap::kARGB_8888_Config: 266 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0)); 267 return true; 268 case SkBitmap::kRGB_565_Config: 269 *color = SkPixel16ToColor(*bm.getAddr16(0, 0)); 270 return true; 271 case SkBitmap::kIndex8_Config: 272 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0)); 273 return true; 274 default: // just skip the other configs for now 275 break; 276 } 277 return false; 278} 279 280#include "SkTemplatesPriv.h" 281 282static bool bitmapIsTooBig(const SkBitmap& bm) { 283 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it 284 // communicates between its matrix-proc and its sampler-proc. Until we can 285 // widen that, we have to reject bitmaps that are larger. 286 // 287 const int maxSize = 65535; 288 289 return bm.width() > maxSize || bm.height() > maxSize; 290} 291 292SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, 293 TileMode tmx, TileMode tmy, 294 void* storage, size_t storageSize) { 295 SkShader* shader; 296 SkColor color; 297 if (src.isNull() || bitmapIsTooBig(src)) { 298 SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize); 299 } 300 else if (canUseColorShader(src, &color)) { 301 SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize, 302 (color)); 303 } else { 304 SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage, 305 storageSize, (src, tmx, tmy)); 306 } 307 return shader; 308} 309 310/////////////////////////////////////////////////////////////////////////////// 311 312static const char* gTileModeName[] = { 313 "clamp", "repeat", "mirror" 314}; 315 316bool SkBitmapProcShader::toDumpString(SkString* str) const { 317 str->printf("BitmapShader: [%d %d %d", 318 fRawBitmap.width(), fRawBitmap.height(), 319 fRawBitmap.bytesPerPixel()); 320 321 // add the pixelref 322 SkPixelRef* pr = fRawBitmap.pixelRef(); 323 if (pr) { 324 const char* uri = pr->getURI(); 325 if (uri) { 326 str->appendf(" \"%s\"", uri); 327 } 328 } 329 330 // add the (optional) matrix 331 { 332 SkMatrix m; 333 if (this->getLocalMatrix(&m)) { 334 SkString info; 335 m.toDumpString(&info); 336 str->appendf(" %s", info.c_str()); 337 } 338 } 339 340 str->appendf(" [%s %s]]", 341 gTileModeName[fState.fTileModeX], 342 gTileModeName[fState.fTileModeY]); 343 return true; 344} 345 346