grab from latest android



git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkBitmapSampler.cpp b/src/core/SkBitmapSampler.cpp
new file mode 100644
index 0000000..045efd1
--- /dev/null
+++ b/src/core/SkBitmapSampler.cpp
@@ -0,0 +1,423 @@
+/* libs/graphics/sgl/SkBitmapSampler.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** 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));
+}
+