1 2 /* 3 * Copyright 2006 The Android Open Source Project 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 9 10 #include "SkBitmapSampler.h" 11 12 static SkTileModeProc get_tilemode_proc(SkShader::TileMode mode) 13 { 14 switch (mode) { 15 case SkShader::kClamp_TileMode: 16 return do_clamp; 17 case SkShader::kRepeat_TileMode: 18 return do_repeat_mod; 19 case SkShader::kMirror_TileMode: 20 return do_mirror_mod; 21 default: 22 SkDEBUGFAIL("unknown mode"); 23 return NULL; 24 } 25 } 26 27 SkBitmapSampler::SkBitmapSampler(const SkBitmap& bm, bool filter, 28 SkShader::TileMode tmx, SkShader::TileMode tmy) 29 : fBitmap(bm), fFilterBitmap(filter), fTileModeX(tmx), fTileModeY(tmy) 30 { 31 SkASSERT(bm.width() > 0 && bm.height() > 0); 32 33 fMaxX = SkToU16(bm.width() - 1); 34 fMaxY = SkToU16(bm.height() - 1); 35 36 fTileProcX = get_tilemode_proc(tmx); 37 fTileProcY = get_tilemode_proc(tmy); 38 } 39 40 void SkBitmapSampler::setPaint(const SkPaint& paint) 41 { 42 } 43 44 class SkNullBitmapSampler : public SkBitmapSampler { 45 public: 46 SkNullBitmapSampler(const SkBitmap& bm, bool filter, 47 SkShader::TileMode tmx, SkShader::TileMode tmy) 48 : SkBitmapSampler(bm, filter, tmx, tmy) {} 49 50 virtual SkPMColor sample(SkFixed x, SkFixed y) const { return 0; } 51 }; 52 53 ///////////////////////////////////////////////////////////////////////////////// 54 ///////////////////////////////////////////////////////////////////////////////// 55 56 #define BITMAP_CLASSNAME_PREFIX(name) ARGB32##name 57 #define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) *bitmap.getAddr32(x, y) 58 #include "SkBitmapSamplerTemplate.h" 59 60 #include "SkColorPriv.h" 61 62 #define BITMAP_CLASSNAME_PREFIX(name) RGB16##name 63 #define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) SkPixel16ToPixel32(*bitmap.getAddr16(x, y)) 64 #include "SkBitmapSamplerTemplate.h" 65 66 #define BITMAP_CLASSNAME_PREFIX(name) Index8##name 67 #define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) bitmap.getIndex8Color(x, y) 68 #include "SkBitmapSamplerTemplate.h" 69 70 ///////////////////////////////////////////////////////////////////////////////// 71 ///////////////////////////////////////////////////////////////////////////////// 72 ///////////////// The Bilinear versions 73 74 #include "SkFilterProc.h" 75 76 class ARGB32_Bilinear_Sampler : public SkBitmapSampler { 77 public: 78 ARGB32_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) 79 : SkBitmapSampler(bm, true, tmx, tmy) 80 { 81 fPtrProcTable = SkGetBilinearFilterPtrProcTable(); 82 } 83 84 virtual SkPMColor sample(SkFixed x, SkFixed y) const 85 { 86 const uint32_t *p00, *p01, *p10, *p11; 87 88 // turn pixel centers into the top-left of our filter-box 89 x -= SK_FixedHalf; 90 y -= SK_FixedHalf; 91 92 // compute our pointers 93 { 94 const SkBitmap* bitmap = &fBitmap; 95 int ix = x >> 16; 96 int iy = y >> 16; 97 98 int maxX = fMaxX; 99 SkTileModeProc procX = fTileProcX; 100 int maxY = fMaxY; 101 SkTileModeProc procY = fTileProcY; 102 103 int tmpx = procX(ix, maxX); 104 int tmpy = procY(iy, maxY); 105 p00 = bitmap->getAddr32(tmpx, tmpy); 106 107 int tmpx1 = procX(ix + 1, maxX); 108 p01 = bitmap->getAddr32(tmpx1, tmpy); 109 110 int tmpy1 = procY(iy + 1, maxY); 111 p10 = bitmap->getAddr32(tmpx, tmpy1); 112 113 p11 = bitmap->getAddr32(tmpx1, tmpy1); 114 } 115 116 SkFilterPtrProc proc = SkGetBilinearFilterPtrProc(fPtrProcTable, x, y); 117 return proc(p00, p01, p10, p11); 118 } 119 120 private: 121 const SkFilterPtrProc* fPtrProcTable; 122 }; 123 124 class RGB16_Bilinear_Sampler : public SkBitmapSampler { 125 public: 126 RGB16_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) 127 : SkBitmapSampler(bm, true, tmx, tmy) 128 { 129 fProcTable = SkGetBilinearFilterProcTable(); 130 } 131 132 virtual SkPMColor sample(SkFixed x, SkFixed y) const 133 { 134 const uint16_t *p00, *p01, *p10, *p11; 135 136 // turn pixel centers into the top-left of our filter-box 137 x -= SK_FixedHalf; 138 y -= SK_FixedHalf; 139 140 // compute our pointers 141 { 142 const SkBitmap* bitmap = &fBitmap; 143 int ix = x >> 16; 144 int iy = y >> 16; 145 146 int maxX = fMaxX; 147 SkTileModeProc procX = fTileProcX; 148 int maxY = fMaxY; 149 SkTileModeProc procY = fTileProcY; 150 151 int tmpx = procX(ix, maxX); 152 int tmpy = procY(iy, maxY); 153 p00 = bitmap->getAddr16(tmpx, tmpy); 154 155 int tmpx1 = procX(ix + 1, maxX); 156 p01 = bitmap->getAddr16(tmpx1, tmpy); 157 158 int tmpy1 = procY(iy + 1, maxY); 159 p10 = bitmap->getAddr16(tmpx, tmpy1); 160 161 p11 = bitmap->getAddr16(tmpx1, tmpy1); 162 } 163 164 SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y); 165 uint32_t c = proc(SkExpand_rgb_16(*p00), SkExpand_rgb_16(*p01), 166 SkExpand_rgb_16(*p10), SkExpand_rgb_16(*p11)); 167 168 return SkPixel16ToPixel32((uint16_t)SkCompact_rgb_16(c)); 169 } 170 171 private: 172 const SkFilterProc* fProcTable; 173 }; 174 175 // If we had a init/term method on sampler, we could avoid the per-pixel 176 // call to lockColors/unlockColors 177 178 class Index8_Bilinear_Sampler : public SkBitmapSampler { 179 public: 180 Index8_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) 181 : SkBitmapSampler(bm, true, tmx, tmy) 182 { 183 fPtrProcTable = SkGetBilinearFilterPtrProcTable(); 184 } 185 186 virtual SkPMColor sample(SkFixed x, SkFixed y) const 187 { 188 const SkBitmap* bitmap = &fBitmap; 189 190 const uint8_t *p00, *p01, *p10, *p11; 191 192 // turn pixel centers into the top-left of our filter-box 193 x -= SK_FixedHalf; 194 y -= SK_FixedHalf; 195 196 // compute our pointers 197 { 198 int ix = x >> 16; 199 int iy = y >> 16; 200 201 int maxX = fMaxX; 202 SkTileModeProc procX = fTileProcX; 203 int maxY = fMaxY; 204 SkTileModeProc procY = fTileProcY; 205 206 int tmpx = procX(ix, maxX); 207 int tmpy = procY(iy, maxY); 208 p00 = bitmap->getAddr8(tmpx, tmpy); 209 210 int tmpx1 = procX(ix + 1, maxX); 211 p01 = bitmap->getAddr8(tmpx1, tmpy); 212 213 int tmpy1 = procY(iy + 1, maxY); 214 p10 = bitmap->getAddr8(tmpx, tmpy1); 215 216 p11 = bitmap->getAddr8(tmpx1, tmpy1); 217 } 218 219 const SkPMColor* colors = bitmap->getColorTable()->lockColors(); 220 221 SkFilterPtrProc proc = SkGetBilinearFilterPtrProc(fPtrProcTable, x, y); 222 uint32_t c = proc(&colors[*p00], &colors[*p01], &colors[*p10], &colors[*p11]); 223 224 bitmap->getColorTable()->unlockColors(false); 225 226 return c; 227 } 228 229 private: 230 const SkFilterPtrProc* fPtrProcTable; 231 }; 232 233 class A8_Bilinear_Sampler : public SkBitmapSampler { 234 public: 235 A8_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) 236 : SkBitmapSampler(bm, true, tmx, tmy) 237 , fColor(0) 238 { 239 fProcTable = SkGetBilinearFilterProcTable(); 240 } 241 242 virtual void setPaint(const SkPaint& paint) 243 { 244 fColor = SkPreMultiplyColor(paint.getColor()); 245 } 246 247 virtual SkPMColor sample(SkFixed x, SkFixed y) const 248 { 249 const uint8_t *p00, *p01, *p10, *p11; 250 251 // turn pixel centers into the top-left of our filter-box 252 x -= SK_FixedHalf; 253 y -= SK_FixedHalf; 254 255 // compute our pointers 256 { 257 const SkBitmap* bitmap = &fBitmap; 258 int ix = x >> 16; 259 int iy = y >> 16; 260 261 int maxX = fMaxX; 262 SkTileModeProc procX = fTileProcX; 263 int maxY = fMaxY; 264 SkTileModeProc procY = fTileProcY; 265 266 int tmpx = procX(ix, maxX); 267 int tmpy = procY(iy, maxY); 268 p00 = bitmap->getAddr8(tmpx, tmpy); 269 270 int tmpx1 = procX(ix + 1, maxX); 271 p01 = bitmap->getAddr8(tmpx1, tmpy); 272 273 int tmpy1 = procY(iy + 1, maxY); 274 p10 = bitmap->getAddr8(tmpx, tmpy1); 275 276 p11 = bitmap->getAddr8(tmpx1, tmpy1); 277 } 278 279 SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y); 280 int alpha = proc(*p00, *p01, *p10, *p11); 281 return SkAlphaMulQ(fColor, SkAlpha255To256(alpha)); 282 } 283 284 private: 285 const SkFilterProc* fProcTable; 286 SkPMColor fColor; 287 }; 288 289 class A8_NoFilter_Sampler : public SkBitmapSampler { 290 public: 291 A8_NoFilter_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) 292 : SkBitmapSampler(bm, false, tmx, tmy) 293 , fProcTable(NULL) 294 { 295 } 296 297 virtual void setPaint(const SkPaint& paint) 298 { 299 fColor = SkPreMultiplyColor(paint.getColor()); 300 } 301 302 virtual SkPMColor sample(SkFixed x, SkFixed y) const 303 { 304 int ix = SkFixedFloor(x); 305 int iy = SkFixedFloor(y); 306 307 int alpha = *fBitmap.getAddr8(fTileProcX(ix, fMaxX), fTileProcY(iy, fMaxY)); 308 return SkAlphaMulQ(fColor, SkAlpha255To256(alpha)); 309 } 310 311 private: 312 const SkFilterProc* fProcTable; 313 SkPMColor fColor; 314 }; 315 316 /////////////////////////////////////////////////////////////////////////////// 317 /////////////////////////////////////////////////////////////////////////////// 318 319 SkBitmapSampler* SkBitmapSampler::Create(const SkBitmap& bm, bool doFilter, 320 SkShader::TileMode tmx, 321 SkShader::TileMode tmy) 322 { 323 switch (bm.getConfig()) { 324 case SkBitmap::kARGB_8888_Config: 325 if (doFilter) 326 return SkNEW_ARGS(ARGB32_Bilinear_Sampler, (bm, tmx, tmy)); 327 328 if (tmx == tmy) { 329 switch (tmx) { 330 case SkShader::kClamp_TileMode: 331 return SkNEW_ARGS(ARGB32_Point_Clamp_Sampler, (bm)); 332 case SkShader::kRepeat_TileMode: 333 if (is_pow2(bm.width()) && is_pow2(bm.height())) 334 return SkNEW_ARGS(ARGB32_Point_Repeat_Pow2_Sampler, (bm)); 335 else 336 return SkNEW_ARGS(ARGB32_Point_Repeat_Mod_Sampler, (bm)); 337 case SkShader::kMirror_TileMode: 338 if (is_pow2(bm.width()) && is_pow2(bm.height())) 339 return SkNEW_ARGS(ARGB32_Point_Mirror_Pow2_Sampler, (bm)); 340 else 341 return SkNEW_ARGS(ARGB32_Point_Mirror_Mod_Sampler, (bm)); 342 default: 343 SkDEBUGFAIL("unknown mode"); 344 } 345 } 346 else { // tmx != tmy 347 return SkNEW_ARGS(ARGB32_Point_Sampler, (bm, tmx, tmy)); 348 } 349 break; 350 351 case SkBitmap::kRGB_565_Config: 352 if (doFilter) 353 return SkNEW_ARGS(RGB16_Bilinear_Sampler, (bm, tmx, tmy)); 354 355 if (tmx == tmy) { 356 switch (tmx) { 357 case SkShader::kClamp_TileMode: 358 return SkNEW_ARGS(RGB16_Point_Clamp_Sampler, (bm)); 359 case SkShader::kRepeat_TileMode: 360 if (is_pow2(bm.width()) && is_pow2(bm.height())) 361 return SkNEW_ARGS(RGB16_Point_Repeat_Pow2_Sampler, (bm)); 362 else 363 return SkNEW_ARGS(RGB16_Point_Repeat_Mod_Sampler, (bm)); 364 case SkShader::kMirror_TileMode: 365 if (is_pow2(bm.width()) && is_pow2(bm.height())) 366 return SkNEW_ARGS(RGB16_Point_Mirror_Pow2_Sampler, (bm)); 367 else 368 return SkNEW_ARGS(RGB16_Point_Mirror_Mod_Sampler, (bm)); 369 default: 370 SkDEBUGFAIL("unknown mode"); 371 } 372 } 373 else { // tmx != tmy 374 return SkNEW_ARGS(RGB16_Point_Sampler, (bm, tmx, tmy)); 375 } 376 break; 377 378 case SkBitmap::kIndex8_Config: 379 if (doFilter) 380 return SkNEW_ARGS(Index8_Bilinear_Sampler, (bm, tmx, tmy)); 381 382 if (tmx == tmy) { 383 switch (tmx) { 384 case SkShader::kClamp_TileMode: 385 return SkNEW_ARGS(Index8_Point_Clamp_Sampler, (bm)); 386 case SkShader::kRepeat_TileMode: 387 if (is_pow2(bm.width()) && is_pow2(bm.height())) 388 return SkNEW_ARGS(Index8_Point_Repeat_Pow2_Sampler, (bm)); 389 else 390 return SkNEW_ARGS(Index8_Point_Repeat_Mod_Sampler, (bm)); 391 case SkShader::kMirror_TileMode: 392 if (is_pow2(bm.width()) && is_pow2(bm.height())) 393 return SkNEW_ARGS(Index8_Point_Mirror_Pow2_Sampler, (bm)); 394 else 395 return SkNEW_ARGS(Index8_Point_Mirror_Mod_Sampler, (bm)); 396 default: 397 SkDEBUGFAIL("unknown mode"); 398 } 399 } 400 else { // tmx != tmy 401 return SkNEW_ARGS(Index8_Point_Sampler, (bm, tmx, tmy)); 402 } 403 break; 404 405 case SkBitmap::kA8_Config: 406 if (doFilter) 407 return SkNEW_ARGS(A8_Bilinear_Sampler, (bm, tmx, tmy)); 408 else 409 return SkNEW_ARGS(A8_NoFilter_Sampler, (bm, tmx, tmy)); 410 break; 411 412 default: 413 SkDEBUGFAIL("unknown device"); 414 } 415 return SkNEW_ARGS(SkNullBitmapSampler, (bm, doFilter, tmx, tmy)); 416 } 417