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 12static 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 27SkBitmapSampler::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 40void SkBitmapSampler::setPaint(const SkPaint& paint) 41{ 42} 43 44class SkNullBitmapSampler : public SkBitmapSampler { 45public: 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 76class ARGB32_Bilinear_Sampler : public SkBitmapSampler { 77public: 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 120private: 121 const SkFilterPtrProc* fPtrProcTable; 122}; 123 124class RGB16_Bilinear_Sampler : public SkBitmapSampler { 125public: 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 171private: 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 178class Index8_Bilinear_Sampler : public SkBitmapSampler { 179public: 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 229private: 230 const SkFilterPtrProc* fPtrProcTable; 231}; 232 233class A8_Bilinear_Sampler : public SkBitmapSampler { 234public: 235 A8_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) 236 : SkBitmapSampler(bm, true, tmx, tmy) 237 { 238 fProcTable = SkGetBilinearFilterProcTable(); 239 } 240 241 virtual void setPaint(const SkPaint& paint) 242 { 243 fColor = SkPreMultiplyColor(paint.getColor()); 244 } 245 246 virtual SkPMColor sample(SkFixed x, SkFixed y) const 247 { 248 const uint8_t *p00, *p01, *p10, *p11; 249 250 // turn pixel centers into the top-left of our filter-box 251 x -= SK_FixedHalf; 252 y -= SK_FixedHalf; 253 254 // compute our pointers 255 { 256 const SkBitmap* bitmap = &fBitmap; 257 int ix = x >> 16; 258 int iy = y >> 16; 259 260 int maxX = fMaxX; 261 SkTileModeProc procX = fTileProcX; 262 int maxY = fMaxY; 263 SkTileModeProc procY = fTileProcY; 264 265 int tmpx = procX(ix, maxX); 266 int tmpy = procY(iy, maxY); 267 p00 = bitmap->getAddr8(tmpx, tmpy); 268 269 int tmpx1 = procX(ix + 1, maxX); 270 p01 = bitmap->getAddr8(tmpx1, tmpy); 271 272 int tmpy1 = procY(iy + 1, maxY); 273 p10 = bitmap->getAddr8(tmpx, tmpy1); 274 275 p11 = bitmap->getAddr8(tmpx1, tmpy1); 276 } 277 278 SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y); 279 int alpha = proc(*p00, *p01, *p10, *p11); 280 return SkAlphaMulQ(fColor, SkAlpha255To256(alpha)); 281 } 282 283private: 284 const SkFilterProc* fProcTable; 285 SkPMColor fColor; 286}; 287 288class A8_NoFilter_Sampler : public SkBitmapSampler { 289public: 290 A8_NoFilter_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) 291 : SkBitmapSampler(bm, false, tmx, tmy) 292 { 293 } 294 295 virtual void setPaint(const SkPaint& paint) 296 { 297 fColor = SkPreMultiplyColor(paint.getColor()); 298 } 299 300 virtual SkPMColor sample(SkFixed x, SkFixed y) const 301 { 302 int ix = SkFixedFloor(x); 303 int iy = SkFixedFloor(y); 304 305 int alpha = *fBitmap.getAddr8(fTileProcX(ix, fMaxX), fTileProcY(iy, fMaxY)); 306 return SkAlphaMulQ(fColor, SkAlpha255To256(alpha)); 307 } 308 309private: 310 const SkFilterProc* fProcTable; 311 SkPMColor fColor; 312}; 313 314/////////////////////////////////////////////////////////////////////////////// 315/////////////////////////////////////////////////////////////////////////////// 316 317SkBitmapSampler* SkBitmapSampler::Create(const SkBitmap& bm, bool doFilter, 318 SkShader::TileMode tmx, 319 SkShader::TileMode tmy) 320{ 321 switch (bm.getConfig()) { 322 case SkBitmap::kARGB_8888_Config: 323 if (doFilter) 324 return SkNEW_ARGS(ARGB32_Bilinear_Sampler, (bm, tmx, tmy)); 325 326 if (tmx == tmy) { 327 switch (tmx) { 328 case SkShader::kClamp_TileMode: 329 return SkNEW_ARGS(ARGB32_Point_Clamp_Sampler, (bm)); 330 case SkShader::kRepeat_TileMode: 331 if (is_pow2(bm.width()) && is_pow2(bm.height())) 332 return SkNEW_ARGS(ARGB32_Point_Repeat_Pow2_Sampler, (bm)); 333 else 334 return SkNEW_ARGS(ARGB32_Point_Repeat_Mod_Sampler, (bm)); 335 case SkShader::kMirror_TileMode: 336 if (is_pow2(bm.width()) && is_pow2(bm.height())) 337 return SkNEW_ARGS(ARGB32_Point_Mirror_Pow2_Sampler, (bm)); 338 else 339 return SkNEW_ARGS(ARGB32_Point_Mirror_Mod_Sampler, (bm)); 340 default: 341 SkDEBUGFAIL("unknown mode"); 342 } 343 } 344 else { // tmx != tmy 345 return SkNEW_ARGS(ARGB32_Point_Sampler, (bm, tmx, tmy)); 346 } 347 break; 348 349 case SkBitmap::kRGB_565_Config: 350 if (doFilter) 351 return SkNEW_ARGS(RGB16_Bilinear_Sampler, (bm, tmx, tmy)); 352 353 if (tmx == tmy) { 354 switch (tmx) { 355 case SkShader::kClamp_TileMode: 356 return SkNEW_ARGS(RGB16_Point_Clamp_Sampler, (bm)); 357 case SkShader::kRepeat_TileMode: 358 if (is_pow2(bm.width()) && is_pow2(bm.height())) 359 return SkNEW_ARGS(RGB16_Point_Repeat_Pow2_Sampler, (bm)); 360 else 361 return SkNEW_ARGS(RGB16_Point_Repeat_Mod_Sampler, (bm)); 362 case SkShader::kMirror_TileMode: 363 if (is_pow2(bm.width()) && is_pow2(bm.height())) 364 return SkNEW_ARGS(RGB16_Point_Mirror_Pow2_Sampler, (bm)); 365 else 366 return SkNEW_ARGS(RGB16_Point_Mirror_Mod_Sampler, (bm)); 367 default: 368 SkDEBUGFAIL("unknown mode"); 369 } 370 } 371 else { // tmx != tmy 372 return SkNEW_ARGS(RGB16_Point_Sampler, (bm, tmx, tmy)); 373 } 374 break; 375 376 case SkBitmap::kIndex8_Config: 377 if (doFilter) 378 return SkNEW_ARGS(Index8_Bilinear_Sampler, (bm, tmx, tmy)); 379 380 if (tmx == tmy) { 381 switch (tmx) { 382 case SkShader::kClamp_TileMode: 383 return SkNEW_ARGS(Index8_Point_Clamp_Sampler, (bm)); 384 case SkShader::kRepeat_TileMode: 385 if (is_pow2(bm.width()) && is_pow2(bm.height())) 386 return SkNEW_ARGS(Index8_Point_Repeat_Pow2_Sampler, (bm)); 387 else 388 return SkNEW_ARGS(Index8_Point_Repeat_Mod_Sampler, (bm)); 389 case SkShader::kMirror_TileMode: 390 if (is_pow2(bm.width()) && is_pow2(bm.height())) 391 return SkNEW_ARGS(Index8_Point_Mirror_Pow2_Sampler, (bm)); 392 else 393 return SkNEW_ARGS(Index8_Point_Mirror_Mod_Sampler, (bm)); 394 default: 395 SkDEBUGFAIL("unknown mode"); 396 } 397 } 398 else { // tmx != tmy 399 return SkNEW_ARGS(Index8_Point_Sampler, (bm, tmx, tmy)); 400 } 401 break; 402 403 case SkBitmap::kA8_Config: 404 if (doFilter) 405 return SkNEW_ARGS(A8_Bilinear_Sampler, (bm, tmx, tmy)); 406 else 407 return SkNEW_ARGS(A8_NoFilter_Sampler, (bm, tmx, tmy)); 408 break; 409 410 default: 411 SkDEBUGFAIL("unknown device"); 412 } 413 return SkNEW_ARGS(SkNullBitmapSampler, (bm, doFilter, tmx, tmy)); 414} 415 416