fast case for translate-only repeat bitmapshader, so Tom can be happy
Review URL: https://codereview.appspot.com/6721045

git-svn-id: http://skia.googlecode.com/svn/trunk@5971 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp
index 283a1ec..85c0c0c 100644
--- a/src/core/SkBitmapProcState.cpp
+++ b/src/core/SkBitmapProcState.cpp
@@ -244,7 +244,7 @@
     SkASSERT(s.fInvKy == 0);
     SkASSERT(count > 0 && colors != NULL);
     SkASSERT(!s.fDoFilter);
-
+    
     const int maxX = s.fBitmap->width() - 1;
     const int maxY = s.fBitmap->height() - 1;
     int ix = s.fFilterOneX + x;
@@ -256,13 +256,13 @@
                    SkIntToScalar(y) + SK_ScalarHalf, &pt);
         int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
         int ix2 = SkScalarFloorToInt(pt.fX);
-
+        
         SkASSERT(iy == iy2);
         SkASSERT(ix == ix2);
     }
 #endif
     const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
-
+    
     // clamp to the left
     if (ix < 0) {
         int n = SkMin32(-ix, count);
@@ -290,6 +290,68 @@
     sk_memset32(colors, row[maxX], count);
 }
 
+static inline int sk_int_mod(int x, int n) {
+    SkASSERT(n > 0);
+    if ((unsigned)x >= (unsigned)n) {
+        if (x < 0) {
+            x = n + ~(~x % n);
+        } else {
+            x = x % n;
+        }
+    }
+    return x;
+}
+
+static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
+                                                     int x, int y,
+                                                     SkPMColor* SK_RESTRICT colors,
+                                                     int count) {
+    SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
+    SkASSERT(s.fInvKy == 0);
+    SkASSERT(count > 0 && colors != NULL);
+    SkASSERT(!s.fDoFilter);
+    
+    const int stopX = s.fBitmap->width();
+    const int stopY = s.fBitmap->height();
+    int ix = s.fFilterOneX + x;
+    int iy = sk_int_mod(s.fFilterOneY + y, stopY);
+#ifdef SK_DEBUG
+    {
+        SkPoint pt;
+        s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
+                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
+        int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
+        int ix2 = SkScalarFloorToInt(pt.fX);
+        
+        SkASSERT(iy == iy2);
+        SkASSERT(ix == ix2);
+    }
+#endif
+    const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
+
+    ix = sk_int_mod(ix, stopX);
+    for (;;) {
+        int n = SkMin32(stopX - ix, count);
+        memcpy(colors, row + ix, n * sizeof(SkPMColor));
+        count -= n;
+        if (0 == count) {
+            return;
+        }
+        colors += n;
+        ix = 0;
+    }
+}
+
+void SkBitmapProcState::setupForTranslate() {
+    SkPoint pt;
+    fInvProc(*fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
+    // Since we know we're not filtered, we re-purpose these fields allow
+    // us to go from device -> src coordinates w/ just an integer add,
+    // rather than running through the inverse-matrix
+    fFilterOneX = SkScalarFloorToInt(pt.fX);
+    fFilterOneY = SkScalarFloorToInt(pt.fY);
+}
+
 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
     if (fAlphaScale < 256) {
         return NULL;
@@ -304,16 +366,17 @@
         return NULL;
     }
 
-    if (SkShader::kClamp_TileMode == fTileModeX && SkShader::kClamp_TileMode == fTileModeY) {
-        SkPoint pt;
-        fInvProc(*fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
-        // Since we know we're not filtered, we re-purpose these fields allow
-        // us to go from device -> src coordinates w/ just an integer add,
-        // rather than running through the inverse-matrix
-        fFilterOneX = SkScalarFloorToInt(pt.fX);
-        fFilterOneY = SkScalarFloorToInt(pt.fY);
+    SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
+    SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
+
+    if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
+        this->setupForTranslate();
         return Clamp_S32_D32_nofilter_trans_shaderproc;
     }
+    if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
+        this->setupForTranslate();
+        return Repeat_S32_D32_nofilter_trans_shaderproc;
+    }
     return NULL;
 }