| |
| /* |
| * Copyright 2006 The Android Open Source Project |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| |
| #include "SkBitmapSampler.h" |
| |
| static SkTileModeProc get_tilemode_proc(SkShader::TileMode mode) |
| { |
| switch (mode) { |
| case SkShader::kClamp_TileMode: |
| return do_clamp; |
| case SkShader::kRepeat_TileMode: |
| return do_repeat_mod; |
| case SkShader::kMirror_TileMode: |
| return do_mirror_mod; |
| default: |
| SkASSERT(!"unknown mode"); |
| return NULL; |
| } |
| } |
| |
| SkBitmapSampler::SkBitmapSampler(const SkBitmap& bm, bool filter, |
| SkShader::TileMode tmx, SkShader::TileMode tmy) |
| : fBitmap(bm), fFilterBitmap(filter), fTileModeX(tmx), fTileModeY(tmy) |
| { |
| SkASSERT(bm.width() > 0 && bm.height() > 0); |
| |
| fMaxX = SkToU16(bm.width() - 1); |
| fMaxY = SkToU16(bm.height() - 1); |
| |
| fTileProcX = get_tilemode_proc(tmx); |
| fTileProcY = get_tilemode_proc(tmy); |
| } |
| |
| void SkBitmapSampler::setPaint(const SkPaint& paint) |
| { |
| } |
| |
| class SkNullBitmapSampler : public SkBitmapSampler { |
| public: |
| SkNullBitmapSampler(const SkBitmap& bm, bool filter, |
| SkShader::TileMode tmx, SkShader::TileMode tmy) |
| : SkBitmapSampler(bm, filter, tmx, tmy) {} |
| |
| virtual SkPMColor sample(SkFixed x, SkFixed y) const { return 0; } |
| }; |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| #define BITMAP_CLASSNAME_PREFIX(name) ARGB32##name |
| #define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) *bitmap.getAddr32(x, y) |
| #include "SkBitmapSamplerTemplate.h" |
| |
| #include "SkColorPriv.h" |
| |
| #define BITMAP_CLASSNAME_PREFIX(name) RGB16##name |
| #define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) SkPixel16ToPixel32(*bitmap.getAddr16(x, y)) |
| #include "SkBitmapSamplerTemplate.h" |
| |
| #define BITMAP_CLASSNAME_PREFIX(name) Index8##name |
| #define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) bitmap.getIndex8Color(x, y) |
| #include "SkBitmapSamplerTemplate.h" |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| ///////////////////////////////////////////////////////////////////////////////// |
| ///////////////// The Bilinear versions |
| |
| #include "SkFilterProc.h" |
| |
| class ARGB32_Bilinear_Sampler : public SkBitmapSampler { |
| public: |
| ARGB32_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) |
| : SkBitmapSampler(bm, true, tmx, tmy) |
| { |
| fPtrProcTable = SkGetBilinearFilterPtrProcTable(); |
| } |
| |
| virtual SkPMColor sample(SkFixed x, SkFixed y) const |
| { |
| const uint32_t *p00, *p01, *p10, *p11; |
| |
| // turn pixel centers into the top-left of our filter-box |
| x -= SK_FixedHalf; |
| y -= SK_FixedHalf; |
| |
| // compute our pointers |
| { |
| const SkBitmap* bitmap = &fBitmap; |
| int ix = x >> 16; |
| int iy = y >> 16; |
| |
| int maxX = fMaxX; |
| SkTileModeProc procX = fTileProcX; |
| int maxY = fMaxY; |
| SkTileModeProc procY = fTileProcY; |
| |
| int tmpx = procX(ix, maxX); |
| int tmpy = procY(iy, maxY); |
| p00 = bitmap->getAddr32(tmpx, tmpy); |
| |
| int tmpx1 = procX(ix + 1, maxX); |
| p01 = bitmap->getAddr32(tmpx1, tmpy); |
| |
| int tmpy1 = procY(iy + 1, maxY); |
| p10 = bitmap->getAddr32(tmpx, tmpy1); |
| |
| p11 = bitmap->getAddr32(tmpx1, tmpy1); |
| } |
| |
| SkFilterPtrProc proc = SkGetBilinearFilterPtrProc(fPtrProcTable, x, y); |
| return proc(p00, p01, p10, p11); |
| } |
| |
| private: |
| const SkFilterPtrProc* fPtrProcTable; |
| }; |
| |
| class RGB16_Bilinear_Sampler : public SkBitmapSampler { |
| public: |
| RGB16_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) |
| : SkBitmapSampler(bm, true, tmx, tmy) |
| { |
| fProcTable = SkGetBilinearFilterProcTable(); |
| } |
| |
| virtual SkPMColor sample(SkFixed x, SkFixed y) const |
| { |
| const uint16_t *p00, *p01, *p10, *p11; |
| |
| // turn pixel centers into the top-left of our filter-box |
| x -= SK_FixedHalf; |
| y -= SK_FixedHalf; |
| |
| // compute our pointers |
| { |
| const SkBitmap* bitmap = &fBitmap; |
| int ix = x >> 16; |
| int iy = y >> 16; |
| |
| int maxX = fMaxX; |
| SkTileModeProc procX = fTileProcX; |
| int maxY = fMaxY; |
| SkTileModeProc procY = fTileProcY; |
| |
| int tmpx = procX(ix, maxX); |
| int tmpy = procY(iy, maxY); |
| p00 = bitmap->getAddr16(tmpx, tmpy); |
| |
| int tmpx1 = procX(ix + 1, maxX); |
| p01 = bitmap->getAddr16(tmpx1, tmpy); |
| |
| int tmpy1 = procY(iy + 1, maxY); |
| p10 = bitmap->getAddr16(tmpx, tmpy1); |
| |
| p11 = bitmap->getAddr16(tmpx1, tmpy1); |
| } |
| |
| SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y); |
| uint32_t c = proc(SkExpand_rgb_16(*p00), SkExpand_rgb_16(*p01), |
| SkExpand_rgb_16(*p10), SkExpand_rgb_16(*p11)); |
| |
| return SkPixel16ToPixel32((uint16_t)SkCompact_rgb_16(c)); |
| } |
| |
| private: |
| const SkFilterProc* fProcTable; |
| }; |
| |
| // If we had a init/term method on sampler, we could avoid the per-pixel |
| // call to lockColors/unlockColors |
| |
| class Index8_Bilinear_Sampler : public SkBitmapSampler { |
| public: |
| Index8_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) |
| : SkBitmapSampler(bm, true, tmx, tmy) |
| { |
| fPtrProcTable = SkGetBilinearFilterPtrProcTable(); |
| } |
| |
| virtual SkPMColor sample(SkFixed x, SkFixed y) const |
| { |
| const SkBitmap* bitmap = &fBitmap; |
| |
| const uint8_t *p00, *p01, *p10, *p11; |
| |
| // turn pixel centers into the top-left of our filter-box |
| x -= SK_FixedHalf; |
| y -= SK_FixedHalf; |
| |
| // compute our pointers |
| { |
| int ix = x >> 16; |
| int iy = y >> 16; |
| |
| int maxX = fMaxX; |
| SkTileModeProc procX = fTileProcX; |
| int maxY = fMaxY; |
| SkTileModeProc procY = fTileProcY; |
| |
| int tmpx = procX(ix, maxX); |
| int tmpy = procY(iy, maxY); |
| p00 = bitmap->getAddr8(tmpx, tmpy); |
| |
| int tmpx1 = procX(ix + 1, maxX); |
| p01 = bitmap->getAddr8(tmpx1, tmpy); |
| |
| int tmpy1 = procY(iy + 1, maxY); |
| p10 = bitmap->getAddr8(tmpx, tmpy1); |
| |
| p11 = bitmap->getAddr8(tmpx1, tmpy1); |
| } |
| |
| const SkPMColor* colors = bitmap->getColorTable()->lockColors(); |
| |
| SkFilterPtrProc proc = SkGetBilinearFilterPtrProc(fPtrProcTable, x, y); |
| uint32_t c = proc(&colors[*p00], &colors[*p01], &colors[*p10], &colors[*p11]); |
| |
| bitmap->getColorTable()->unlockColors(false); |
| |
| return c; |
| } |
| |
| private: |
| const SkFilterPtrProc* fPtrProcTable; |
| }; |
| |
| class A8_Bilinear_Sampler : public SkBitmapSampler { |
| public: |
| A8_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) |
| : SkBitmapSampler(bm, true, tmx, tmy) |
| { |
| fProcTable = SkGetBilinearFilterProcTable(); |
| } |
| |
| virtual void setPaint(const SkPaint& paint) |
| { |
| fColor = SkPreMultiplyColor(paint.getColor()); |
| } |
| |
| virtual SkPMColor sample(SkFixed x, SkFixed y) const |
| { |
| const uint8_t *p00, *p01, *p10, *p11; |
| |
| // turn pixel centers into the top-left of our filter-box |
| x -= SK_FixedHalf; |
| y -= SK_FixedHalf; |
| |
| // compute our pointers |
| { |
| const SkBitmap* bitmap = &fBitmap; |
| int ix = x >> 16; |
| int iy = y >> 16; |
| |
| int maxX = fMaxX; |
| SkTileModeProc procX = fTileProcX; |
| int maxY = fMaxY; |
| SkTileModeProc procY = fTileProcY; |
| |
| int tmpx = procX(ix, maxX); |
| int tmpy = procY(iy, maxY); |
| p00 = bitmap->getAddr8(tmpx, tmpy); |
| |
| int tmpx1 = procX(ix + 1, maxX); |
| p01 = bitmap->getAddr8(tmpx1, tmpy); |
| |
| int tmpy1 = procY(iy + 1, maxY); |
| p10 = bitmap->getAddr8(tmpx, tmpy1); |
| |
| p11 = bitmap->getAddr8(tmpx1, tmpy1); |
| } |
| |
| SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y); |
| int alpha = proc(*p00, *p01, *p10, *p11); |
| return SkAlphaMulQ(fColor, SkAlpha255To256(alpha)); |
| } |
| |
| private: |
| const SkFilterProc* fProcTable; |
| SkPMColor fColor; |
| }; |
| |
| class A8_NoFilter_Sampler : public SkBitmapSampler { |
| public: |
| A8_NoFilter_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy) |
| : SkBitmapSampler(bm, false, tmx, tmy) |
| { |
| } |
| |
| virtual void setPaint(const SkPaint& paint) |
| { |
| fColor = SkPreMultiplyColor(paint.getColor()); |
| } |
| |
| virtual SkPMColor sample(SkFixed x, SkFixed y) const |
| { |
| int ix = SkFixedFloor(x); |
| int iy = SkFixedFloor(y); |
| |
| int alpha = *fBitmap.getAddr8(fTileProcX(ix, fMaxX), fTileProcY(iy, fMaxY)); |
| return SkAlphaMulQ(fColor, SkAlpha255To256(alpha)); |
| } |
| |
| private: |
| const SkFilterProc* fProcTable; |
| SkPMColor fColor; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| SkBitmapSampler* SkBitmapSampler::Create(const SkBitmap& bm, bool doFilter, |
| SkShader::TileMode tmx, |
| SkShader::TileMode tmy) |
| { |
| switch (bm.getConfig()) { |
| case SkBitmap::kARGB_8888_Config: |
| if (doFilter) |
| return SkNEW_ARGS(ARGB32_Bilinear_Sampler, (bm, tmx, tmy)); |
| |
| if (tmx == tmy) { |
| switch (tmx) { |
| case SkShader::kClamp_TileMode: |
| return SkNEW_ARGS(ARGB32_Point_Clamp_Sampler, (bm)); |
| case SkShader::kRepeat_TileMode: |
| if (is_pow2(bm.width()) && is_pow2(bm.height())) |
| return SkNEW_ARGS(ARGB32_Point_Repeat_Pow2_Sampler, (bm)); |
| else |
| return SkNEW_ARGS(ARGB32_Point_Repeat_Mod_Sampler, (bm)); |
| case SkShader::kMirror_TileMode: |
| if (is_pow2(bm.width()) && is_pow2(bm.height())) |
| return SkNEW_ARGS(ARGB32_Point_Mirror_Pow2_Sampler, (bm)); |
| else |
| return SkNEW_ARGS(ARGB32_Point_Mirror_Mod_Sampler, (bm)); |
| default: |
| SkASSERT(!"unknown mode"); |
| } |
| } |
| else { // tmx != tmy |
| return SkNEW_ARGS(ARGB32_Point_Sampler, (bm, tmx, tmy)); |
| } |
| break; |
| |
| case SkBitmap::kRGB_565_Config: |
| if (doFilter) |
| return SkNEW_ARGS(RGB16_Bilinear_Sampler, (bm, tmx, tmy)); |
| |
| if (tmx == tmy) { |
| switch (tmx) { |
| case SkShader::kClamp_TileMode: |
| return SkNEW_ARGS(RGB16_Point_Clamp_Sampler, (bm)); |
| case SkShader::kRepeat_TileMode: |
| if (is_pow2(bm.width()) && is_pow2(bm.height())) |
| return SkNEW_ARGS(RGB16_Point_Repeat_Pow2_Sampler, (bm)); |
| else |
| return SkNEW_ARGS(RGB16_Point_Repeat_Mod_Sampler, (bm)); |
| case SkShader::kMirror_TileMode: |
| if (is_pow2(bm.width()) && is_pow2(bm.height())) |
| return SkNEW_ARGS(RGB16_Point_Mirror_Pow2_Sampler, (bm)); |
| else |
| return SkNEW_ARGS(RGB16_Point_Mirror_Mod_Sampler, (bm)); |
| default: |
| SkASSERT(!"unknown mode"); |
| } |
| } |
| else { // tmx != tmy |
| return SkNEW_ARGS(RGB16_Point_Sampler, (bm, tmx, tmy)); |
| } |
| break; |
| |
| case SkBitmap::kIndex8_Config: |
| if (doFilter) |
| return SkNEW_ARGS(Index8_Bilinear_Sampler, (bm, tmx, tmy)); |
| |
| if (tmx == tmy) { |
| switch (tmx) { |
| case SkShader::kClamp_TileMode: |
| return SkNEW_ARGS(Index8_Point_Clamp_Sampler, (bm)); |
| case SkShader::kRepeat_TileMode: |
| if (is_pow2(bm.width()) && is_pow2(bm.height())) |
| return SkNEW_ARGS(Index8_Point_Repeat_Pow2_Sampler, (bm)); |
| else |
| return SkNEW_ARGS(Index8_Point_Repeat_Mod_Sampler, (bm)); |
| case SkShader::kMirror_TileMode: |
| if (is_pow2(bm.width()) && is_pow2(bm.height())) |
| return SkNEW_ARGS(Index8_Point_Mirror_Pow2_Sampler, (bm)); |
| else |
| return SkNEW_ARGS(Index8_Point_Mirror_Mod_Sampler, (bm)); |
| default: |
| SkASSERT(!"unknown mode"); |
| } |
| } |
| else { // tmx != tmy |
| return SkNEW_ARGS(Index8_Point_Sampler, (bm, tmx, tmy)); |
| } |
| break; |
| |
| case SkBitmap::kA8_Config: |
| if (doFilter) |
| return SkNEW_ARGS(A8_Bilinear_Sampler, (bm, tmx, tmy)); |
| else |
| return SkNEW_ARGS(A8_NoFilter_Sampler, (bm, tmx, tmy)); |
| break; |
| |
| default: |
| SkASSERT(!"unknown device"); |
| } |
| return SkNEW_ARGS(SkNullBitmapSampler, (bm, doFilter, tmx, tmy)); |
| } |
| |