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