Index: sgl/SkBitmapProcState.h
===================================================================
--- sgl/SkBitmapProcState.h	(revision 42716)
+++ sgl/SkBitmapProcState.h	(working copy)
@@ -39,8 +39,9 @@
                                  int count,
                                  uint16_t colors[]);
     
-    typedef U16CPU (*FixedTileProc)(SkFixed);   // returns 0..0xFFFF
-    
+    typedef SkFixed (*FixedTileProc)(SkFixed, int);
+    typedef int (*IntTileProc)(int, int);
+
     MatrixProc          fMatrixProc;        // chooseProcs
     SampleProc32        fSampleProc32;      // chooseProcs
     SampleProc16        fSampleProc16;      // chooseProcs
@@ -48,6 +49,8 @@
     SkMatrix            fUnitInvMatrix;     // chooseProcs
     FixedTileProc       fTileProcX;         // chooseProcs
     FixedTileProc       fTileProcY;         // chooseProcs
+    IntTileProc         iTileProcX;         // chooseProcs
+    IntTileProc         iTileProcY;         // chooseProcs
     SkFixed             fFilterOneX;
     SkFixed             fFilterOneY;
 
Index: sgl/SkBitmapProcState.cpp
===================================================================
--- sgl/SkBitmapProcState.cpp	(revision 42716)
+++ sgl/SkBitmapProcState.cpp	(working copy)
@@ -296,8 +296,9 @@
     }
     const SkMatrix* m;
     
-    if (SkShader::kClamp_TileMode == fTileModeX &&
-            SkShader::kClamp_TileMode == fTileModeY) {
+    if (inv.getType() <= SkMatrix::kTranslate_Mask ||
+        (SkShader::kClamp_TileMode == fTileModeX &&
+         SkShader::kClamp_TileMode == fTileModeY)) {
         m = &inv;
     } else {
         fUnitInvMatrix = inv;
@@ -330,6 +331,16 @@
     fInvMatrix      = m;
     fInvProc        = m->getMapXYProc();
     fInvType        = m->getType();
+    if (fInvType <= SkMatrix::kTranslate_Mask &&
+        inv.getType() > SkMatrix::kTranslate_Mask) {
+      SkASSERT(inv.getType() <=
+               (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask));
+      // It is possible that by the calculation of fUnitInvMatrix, we have
+      // eliminated the scale transformation of the matrix (e.g., if inv^(-1)
+      // scales fOrigBitmap into an 1X1 rect). We add the scale flag back so
+      // that we don't make wrong choice in chooseMatrixProc().
+      fInvType |= SkMatrix::kScale_Mask;
+    }
     fInvSx          = SkScalarToFixed(m->getScaleX());
     fInvSy          = SkScalarToFixed(m->getScaleY());
     fInvKy          = SkScalarToFixed(m->getSkewY());
Index: sgl/SkBitmapProcState_matrix.h
===================================================================
--- sgl/SkBitmapProcState_matrix.h	(revision 42716)
+++ sgl/SkBitmapProcState_matrix.h	(working copy)
@@ -1,4 +1,5 @@
 
+#define TRANSLATE_NOFILTER_NAME MAKENAME(_nofilter_translate)
 #define SCALE_NOFILTER_NAME     MAKENAME(_nofilter_scale)
 #define SCALE_FILTER_NAME       MAKENAME(_filter_scale)
 #define AFFINE_NOFILTER_NAME    MAKENAME(_nofilter_affine)
@@ -17,6 +18,38 @@
     #define PREAMBLE_ARG_Y
 #endif
 
+#ifndef PREAMBLE_TRANS
+    #define PREAMBLE_TRANS(state)
+#endif
+
+static void TRANSLATE_NOFILTER_NAME(const SkBitmapProcState& s,
+                                    uint32_t xy[], int count, int x, int y)
+{
+    SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
+
+    PREAMBLE_TRANS(s);
+
+    x += SkScalarFloor(s.fInvMatrix->getTranslateX());
+    y += SkScalarFloor(s.fInvMatrix->getTranslateY());
+
+    *xy++ = (uint32_t)TILEY_TRANS(y, (s.fBitmap->height() - 1));
+    
+    int maxX = s.fBitmap->width() - 1;
+    int i;
+    uint16_t* xx = (uint16_t*)xy;
+    for (i = (count >> 2); i > 0; --i)
+    {
+        *xx++ = (uint16_t)TILEX_TRANS(x, maxX); x++;
+        *xx++ = (uint16_t)TILEX_TRANS(x, maxX); x++;
+        *xx++ = (uint16_t)TILEX_TRANS(x, maxX); x++;
+        *xx++ = (uint16_t)TILEX_TRANS(x, maxX); x++;
+    }
+    for (i = (count & 3); i > 0; --i)
+    {
+        *xx++ = (uint16_t)TILEX_TRANS(x, maxX); x++;
+    }
+}
+
 static void SCALE_NOFILTER_NAME(const SkBitmapProcState& s,
                                 uint32_t xy[], int count, int x, int y) {
     SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
@@ -206,9 +239,9 @@
     unsigned maxY = s.fBitmap->height() - 1;
     
     do {
-        *xy++ = PACK_FILTER_Y_NAME(fy, maxY, oneX PREAMBLE_ARG_Y);
+        *xy++ = PACK_FILTER_Y_NAME(fy, maxY, oneY PREAMBLE_ARG_Y);
         fy += dy;
-        *xy++ = PACK_FILTER_X_NAME(fx, maxX, oneY PREAMBLE_ARG_X);
+        *xy++ = PACK_FILTER_X_NAME(fx, maxX, oneX PREAMBLE_ARG_X);
         fx += dx;
     } while (--count != 0);
 }
@@ -241,6 +274,9 @@
 }
 
 static SkBitmapProcState::MatrixProc MAKENAME(_Procs)[] = {
+    TRANSLATE_NOFILTER_NAME,
+    TRANSLATE_NOFILTER_NAME,    // No need to do filtering if the matrix is no
+                                // more complex than identity/translate.
     SCALE_NOFILTER_NAME,
     SCALE_FILTER_NAME,
     AFFINE_NOFILTER_NAME,
@@ -255,7 +291,10 @@
 #ifdef CHECK_FOR_DECAL
     #undef CHECK_FOR_DECAL
 #endif
-
+#undef TILEX_TRANS
+#undef TILEY_TRANS
+ 
+#undef TRANSLATE_NOFILTER_NAME
 #undef SCALE_NOFILTER_NAME
 #undef SCALE_FILTER_NAME
 #undef AFFINE_NOFILTER_NAME
@@ -268,6 +307,7 @@
 #undef PREAMBLE_PARAM_Y
 #undef PREAMBLE_ARG_X
 #undef PREAMBLE_ARG_Y
+#undef PREAMBLE_TRANS
 
 #undef TILEX_LOW_BITS
 #undef TILEY_LOW_BITS
Index: sgl/SkBitmapProcState_matrixProcs.cpp
===================================================================
--- sgl/SkBitmapProcState_matrixProcs.cpp	(revision 42716)
+++ sgl/SkBitmapProcState_matrixProcs.cpp	(working copy)
@@ -28,6 +28,8 @@
 #define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF)
 #define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF)
 #define CHECK_FOR_DECAL
+#define TILEX_TRANS(x, max)     SkClampMax(x, max)
+#define TILEY_TRANS(y, max)     SkClampMax(y, max)
 #include "SkBitmapProcState_matrix.h"
 
 #define MAKENAME(suffix)        RepeatX_RepeatY ## suffix
@@ -35,6 +37,9 @@
 #define TILEY_PROCF(fy, max)    (((fy) & 0xFFFF) * ((max) + 1) >> 16)
 #define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
 #define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
+#define REAL_MOD(val, modulus)  (((val)%(modulus)) + (modulus)*( (val)<0 ))
+#define TILEX_TRANS(x, max)     (REAL_MOD((x), ((max) + 1)))
+#define TILEY_TRANS(y, max)     (REAL_MOD((y), ((max) + 1)))
 #include "SkBitmapProcState_matrix.h"
 
 #define MAKENAME(suffix)        GeneralXY ## suffix
@@ -44,13 +49,17 @@
 #define PREAMBLE_PARAM_Y        , SkBitmapProcState::FixedTileProc tileProcY
 #define PREAMBLE_ARG_X          , tileProcX
 #define PREAMBLE_ARG_Y          , tileProcY
-#define TILEX_PROCF(fx, max)    (tileProcX(fx) * ((max) + 1) >> 16)
-#define TILEY_PROCF(fy, max)    (tileProcY(fy) * ((max) + 1) >> 16)
-#define TILEX_LOW_BITS(fx, max) ((tileProcX(fx) * ((max) + 1) >> 12) & 0xF)
-#define TILEY_LOW_BITS(fy, max) ((tileProcY(fy) * ((max) + 1) >> 12) & 0xF)
+#define TILEX_PROCF(fx, max)    (tileProcX(fx, max) >> 16)
+#define TILEY_PROCF(fy, max)    (tileProcY(fy, max) >> 16)
+#define TILEX_LOW_BITS(fx, max) ((tileProcX(fx, max) >> 14) & 0x3)
+#define TILEY_LOW_BITS(fy, max) ((tileProcY(fy, max) >> 14) & 0x3)
+#define PREAMBLE_TRANS(state)   SkBitmapProcState::IntTileProc tileProcX = (state).iTileProcX; \
+                                SkBitmapProcState::IntTileProc tileProcY = (state).iTileProcY
+#define TILEX_TRANS(x, max)     tileProcX(x, max)
+#define TILEY_TRANS(y, max)     tileProcY(y, max)
 #include "SkBitmapProcState_matrix.h"
 
-static inline U16CPU fixed_clamp(SkFixed x)
+static inline SkFixed fixed_clamp(SkFixed x, int max)
 {
 #ifdef SK_CPU_HAS_CONDITIONAL_INSTR
     if (x >> 16)
@@ -66,19 +75,20 @@
             x = 0xFFFF;
     }
 #endif
-    return x;
+    return x * (max + 1);
 }
 
-static inline U16CPU fixed_repeat(SkFixed x)
+static inline SkFixed fixed_repeat(SkFixed x, int max)
 {
-    return x & 0xFFFF;
+    return (x & 0xFFFF) * (max + 1);
 }
 
-static inline U16CPU fixed_mirror(SkFixed x)
+static inline SkFixed fixed_mirror(SkFixed x, int max)
 {
     SkFixed s = x << 15 >> 31;
     // s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
-    return (x ^ s) & 0xFFFF;
+    x = ((x ^ s) & 0xFFFF) * (max + 1);
+    return s ? (x ^ 0xFFFF) : x;
 }
 
 static SkBitmapProcState::FixedTileProc choose_tile_proc(unsigned m)
@@ -90,15 +100,52 @@
     SkASSERT(SkShader::kMirror_TileMode == m);
     return fixed_mirror;
 }
+ 
+static inline int int_clamp(int x, int max)
+{
+    SkASSERT(max >= 0);
+    
+    return SkClampMax(x, max);
+}
 
+static inline int int_repeat(int x, int max)
+{
+    SkASSERT(max >= 0);
+
+    return x % (max + 1);
+}
+
+static inline int int_mirror(int x, int max)
+{
+    SkASSERT(max >= 0);
+
+    int dx = x % (max + 1);
+    if (dx < 0)
+        dx = -dx - 1;
+    
+    return (x / (max + 1) % 2) ? max - dx : dx;
+}
+
+static SkBitmapProcState::IntTileProc choose_int_tile_proc(unsigned m)
+{
+    if (SkShader::kClamp_TileMode == m)
+        return int_clamp;
+    if (SkShader::kRepeat_TileMode == m)
+        return int_repeat;
+    SkASSERT(SkShader::kMirror_TileMode == m);
+    return int_mirror;
+}
+
 SkBitmapProcState::MatrixProc SkBitmapProcState::chooseMatrixProc()
 {
     int index = 0;
     if (fDoFilter)
         index = 1;
     if (fInvType & SkMatrix::kPerspective_Mask)
+        index |= 6;
+    else if (fInvType & SkMatrix::kAffine_Mask)
         index |= 4;
-    else if (fInvType & SkMatrix::kAffine_Mask)
+    else if (fInvType & SkMatrix::kScale_Mask)
         index |= 2;
 
     if (SkShader::kClamp_TileMode == fTileModeX &&
@@ -123,6 +170,8 @@
     // only general needs these procs
     fTileProcX = choose_tile_proc(fTileModeX);
     fTileProcY = choose_tile_proc(fTileModeY);
+    iTileProcX = choose_int_tile_proc(fTileModeX);
+    iTileProcY = choose_int_tile_proc(fTileModeY);
     return GeneralXY_Procs[index];
 }