summaryrefslogtreecommitdiffstats
path: root/skia/sgl/SkBitmapSampler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'skia/sgl/SkBitmapSampler.cpp')
-rw-r--r--skia/sgl/SkBitmapSampler.cpp423
1 files changed, 423 insertions, 0 deletions
diff --git a/skia/sgl/SkBitmapSampler.cpp b/skia/sgl/SkBitmapSampler.cpp
new file mode 100644
index 0000000..924aeaa
--- /dev/null
+++ b/skia/sgl/SkBitmapSampler.cpp
@@ -0,0 +1,423 @@
+/* libs/graphics/sgl/SkBitmapSampler.cpp
+**
+** Copyright 2006, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#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));
+}
+