reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame^] | 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 | } |
| 25 | |
| 26 | SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer) |
| 27 | : INHERITED(buffer) { |
| 28 | fRawBitmap.unflatten(buffer); |
| 29 | fState.fTileModeX = buffer.readU8(); |
| 30 | fState.fTileModeY = buffer.readU8(); |
| 31 | } |
| 32 | |
| 33 | void SkBitmapProcShader::beginSession() { |
| 34 | this->INHERITED::beginSession(); |
| 35 | |
| 36 | fRawBitmap.lockPixels(); |
| 37 | } |
| 38 | |
| 39 | void SkBitmapProcShader::endSession() { |
| 40 | fRawBitmap.unlockPixels(); |
| 41 | |
| 42 | this->INHERITED::endSession(); |
| 43 | } |
| 44 | |
| 45 | bool SkBitmapProcShader::asABitmap(SkBitmap* texture, SkMatrix* texM, |
| 46 | TileMode xy[]) { |
| 47 | if (texture) { |
| 48 | *texture = fRawBitmap; |
| 49 | } |
| 50 | if (texM) { |
| 51 | texM->reset(); |
| 52 | } |
| 53 | if (xy) { |
| 54 | xy[0] = (TileMode)fState.fTileModeX; |
| 55 | xy[1] = (TileMode)fState.fTileModeY; |
| 56 | } |
| 57 | return true; |
| 58 | } |
| 59 | |
| 60 | void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) { |
| 61 | this->INHERITED::flatten(buffer); |
| 62 | |
| 63 | fRawBitmap.flatten(buffer); |
| 64 | buffer.write8(fState.fTileModeX); |
| 65 | buffer.write8(fState.fTileModeY); |
| 66 | } |
| 67 | |
| 68 | bool SkBitmapProcShader::setContext(const SkBitmap& device, |
| 69 | const SkPaint& paint, |
| 70 | const SkMatrix& matrix) { |
| 71 | // do this first, so we have a correct inverse matrix |
| 72 | if (!this->INHERITED::setContext(device, paint, matrix)) { |
| 73 | return false; |
| 74 | } |
| 75 | |
| 76 | fState.fOrigBitmap = fRawBitmap; |
| 77 | fState.fOrigBitmap.lockPixels(); |
| 78 | if (fState.fOrigBitmap.getPixels() == NULL) { |
| 79 | fState.fOrigBitmap.unlockPixels(); |
| 80 | return false; |
| 81 | } |
| 82 | |
| 83 | if (!fState.chooseProcs(this->getTotalInverse(), paint)) { |
| 84 | return false; |
| 85 | } |
| 86 | |
| 87 | bool bitmapIsOpaque = fState.fBitmap->isOpaque(); |
| 88 | |
| 89 | // filtering doesn't guarantee that opaque stays opaque (finite precision) |
| 90 | // so pretend we're not opaque if we're being asked to filter. If we had |
| 91 | // more blit-procs, we could specialize on opaque src, and just OR in 0xFF |
| 92 | // after the filter to be sure... |
| 93 | if (paint.isFilterBitmap()) { |
| 94 | bitmapIsOpaque = false; |
| 95 | } |
| 96 | |
| 97 | // update fFlags |
| 98 | fFlags = 0; // this should happen in SkShader.cpp |
| 99 | |
| 100 | if (bitmapIsOpaque && (255 == this->getPaintAlpha())) { |
| 101 | fFlags |= kOpaqueAlpha_Flag; |
| 102 | } |
| 103 | |
| 104 | switch (fState.fBitmap->config()) { |
| 105 | case SkBitmap::kRGB_565_Config: |
| 106 | fFlags |= (kHasSpan16_Flag | kIntrinsicly16_Flag); |
| 107 | break; |
| 108 | case SkBitmap::kIndex8_Config: |
| 109 | case SkBitmap::kARGB_8888_Config: |
| 110 | if (bitmapIsOpaque) { |
| 111 | fFlags |= kHasSpan16_Flag; |
| 112 | } |
| 113 | break; |
| 114 | case SkBitmap::kA8_Config: |
| 115 | break; // never set kHasSpan16_Flag |
| 116 | default: |
| 117 | break; |
| 118 | } |
| 119 | return true; |
| 120 | } |
| 121 | |
| 122 | #define BUF_MAX 128 |
| 123 | |
| 124 | void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { |
| 125 | uint32_t buffer[BUF_MAX]; |
| 126 | |
| 127 | const SkBitmapProcState& state = fState; |
| 128 | SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; |
| 129 | SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32; |
| 130 | int max = fState.fDoFilter ? (BUF_MAX >> 1) : BUF_MAX; |
| 131 | |
| 132 | SkASSERT(state.fBitmap->getPixels()); |
| 133 | SkASSERT(state.fBitmap->pixelRef() == NULL || |
| 134 | state.fBitmap->pixelRef()->getLockCount()); |
| 135 | |
| 136 | for (;;) { |
| 137 | int n = count; |
| 138 | if (n > max) { |
| 139 | n = max; |
| 140 | } |
| 141 | mproc(state, buffer, n, x, y); |
| 142 | sproc(state, buffer, n, dstC); |
| 143 | |
| 144 | if ((count -= n) == 0) { |
| 145 | break; |
| 146 | } |
| 147 | x += n; |
| 148 | dstC += n; |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { |
| 153 | uint32_t buffer[BUF_MAX]; |
| 154 | |
| 155 | const SkBitmapProcState& state = fState; |
| 156 | SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; |
| 157 | SkBitmapProcState::SampleProc16 sproc = state.fSampleProc16; |
| 158 | int max = fState.fDoFilter ? (BUF_MAX >> 1) : BUF_MAX; |
| 159 | |
| 160 | SkASSERT(state.fBitmap->getPixels()); |
| 161 | SkASSERT(state.fBitmap->pixelRef() == NULL || |
| 162 | state.fBitmap->pixelRef()->getLockCount()); |
| 163 | |
| 164 | for (;;) { |
| 165 | int n = count; |
| 166 | if (n > max) { |
| 167 | n = max; |
| 168 | } |
| 169 | mproc(state, buffer, n, x, y); |
| 170 | sproc(state, buffer, n, dstC); |
| 171 | |
| 172 | if ((count -= n) == 0) { |
| 173 | break; |
| 174 | } |
| 175 | x += n; |
| 176 | dstC += n; |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | /////////////////////////////////////////////////////////////////////////////// |
| 181 | |
| 182 | #include "SkTemplatesPriv.h" |
| 183 | |
| 184 | SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, |
| 185 | TileMode tmx, TileMode tmy, |
| 186 | void* storage, size_t storageSize) { |
| 187 | SkShader* shader; |
| 188 | SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage, |
| 189 | storageSize, (src, tmx, tmy)); |
| 190 | return shader; |
| 191 | } |
| 192 | |
| 193 | static SkFlattenable::Registrar gBitmapProcShaderReg("SkBitmapProcShader", |
| 194 | SkBitmapProcShader::CreateProc); |
| 195 | |
| 196 | /////////////////////////////////////////////////////////////////////////////// |
| 197 | |
| 198 | static const char* gTileModeName[] = { |
| 199 | "clamp", "repeat", "mirror" |
| 200 | }; |
| 201 | |
| 202 | bool SkBitmapProcShader::toDumpString(SkString* str) const { |
| 203 | str->printf("BitmapShader: [%d %d %d", |
| 204 | fRawBitmap.width(), fRawBitmap.height(), |
| 205 | fRawBitmap.bytesPerPixel()); |
| 206 | |
| 207 | // add the pixelref |
| 208 | SkPixelRef* pr = fRawBitmap.pixelRef(); |
| 209 | if (pr) { |
| 210 | const char* uri = pr->getURI(); |
| 211 | if (uri) { |
| 212 | str->appendf(" \"%s\"", uri); |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | // add the (optional) matrix |
| 217 | { |
| 218 | SkMatrix m; |
| 219 | if (this->getLocalMatrix(&m)) { |
| 220 | SkString info; |
| 221 | m.toDumpString(&info); |
| 222 | str->appendf(" %s", info.c_str()); |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | str->appendf(" [%s %s]]", |
| 227 | gTileModeName[fState.fTileModeX], |
| 228 | gTileModeName[fState.fTileModeY]); |
| 229 | return true; |
| 230 | } |
| 231 | |