Added shaderproc for 1xN repeatX/repeatY BitmapProcShader

https://codereview.appspot.com/7063054/



git-svn-id: http://skia.googlecode.com/svn/trunk@7273 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp
index ea09c5d..79dcc9a1 100644
--- a/src/core/SkBitmapProcState.cpp
+++ b/src/core/SkBitmapProcState.cpp
@@ -91,7 +91,7 @@
     const SkMatrix* m;
     bool trivial_matrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0;
     bool clamp_clamp = SkShader::kClamp_TileMode == fTileModeX &&
-    SkShader::kClamp_TileMode == fTileModeY;
+                       SkShader::kClamp_TileMode == fTileModeY;
 
     if (clamp_clamp || trivial_matrix) {
         m = &inv;
@@ -255,7 +255,7 @@
         S4444_opaque_D32_filter_DX,
         S4444_alpha_D32_filter_DX,
 
-        // A8 treats alpha/opauqe the same (equally efficient)
+        // A8 treats alpha/opaque the same (equally efficient)
         SA8_alpha_D32_nofilter_DXDY,
         SA8_alpha_D32_nofilter_DXDY,
         SA8_alpha_D32_nofilter_DX,
@@ -380,6 +380,14 @@
     return x;
 }
 
+static inline int sk_int_mirror(int x, int n) {
+    x = sk_int_mod(x, 2 * n);
+    if (x >= n) {
+        x = n + ~(x - n);
+    }
+    return x;
+}
+
 static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
                                                      int x, int y,
                                                      SkPMColor* SK_RESTRICT colors,
@@ -420,6 +428,103 @@
     }
 }
 
+static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
+                                      int x, int y,
+                                      SkPMColor* SK_RESTRICT colors,
+                                      int count) {
+    SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
+    SkASSERT(s.fInvKy == 0);
+    SkASSERT(count > 0 && colors != NULL);
+    SkASSERT(1 == s.fBitmap->width());
+
+    int iY0, iY1, iSubY;
+
+    if (s.fDoFilter) {
+        SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
+        uint32_t xy[2];
+
+        mproc(s, xy, 1, x, y);
+
+        iY0 = xy[0] >> 18;
+        iY1 = xy[0] & 0x3FFF;
+        iSubY = (xy[0] >> 14) & 0xF;
+    } else {
+        int yTemp;
+
+        if (s.fInvType > SkMatrix::kTranslate_Mask) {
+            SkPoint pt;
+            s.fInvProc(*s.fInvMatrix, 
+                       SkIntToScalar(x) + SK_ScalarHalf,
+                       SkIntToScalar(y) + SK_ScalarHalf, 
+                       &pt);
+            yTemp = SkScalarFloorToInt(pt.fY);
+        } else {
+            yTemp = s.fFilterOneY + y;
+        }
+
+        const int stopY = s.fBitmap->height();
+        switch (s.fTileModeY) {
+            case SkShader::kClamp_TileMode:
+                iY0 = SkClampMax(yTemp, stopY-1);
+                break;
+            case SkShader::kRepeat_TileMode:
+                iY0 = sk_int_mod(yTemp, stopY);
+                break;
+            case SkShader::kMirror_TileMode:
+            default:
+                iY0 = sk_int_mirror(yTemp, stopY);
+                break;
+        }
+
+#ifdef SK_DEBUG
+        {
+            SkPoint pt;
+            s.fInvProc(*s.fInvMatrix, 
+                       SkIntToScalar(x) + SK_ScalarHalf,
+                       SkIntToScalar(y) + SK_ScalarHalf, 
+                       &pt);
+            int iY2;
+
+            switch (s.fTileModeY) {
+            case SkShader::kClamp_TileMode:
+                iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1);
+                break;
+            case SkShader::kRepeat_TileMode:
+                iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
+                break;
+            case SkShader::kMirror_TileMode:
+            default:
+                iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY);
+                break;
+            }
+
+            SkASSERT(iY0 == iY2);
+        }
+#endif
+    }
+
+    const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
+    SkPMColor color;
+
+    if (s.fDoFilter) {
+        const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
+
+        if (s.fAlphaScale < 256) {
+            Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
+        } else {
+            Filter_32_opaque(iSubY, *row0, *row1, &color);
+        }
+    } else {
+        if (s.fAlphaScale < 256) {
+            color = SkAlphaMulQ(*row0, s.fAlphaScale);
+        } else {
+            color = *row0;
+        }
+    }
+
+    sk_memset32(colors, color, count);
+}
+
 static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y,
                                  SkPMColor* SK_RESTRICT colors, int count) {
     // if we get called, the matrix is too tricky, so we just draw nothing
@@ -449,6 +554,20 @@
 }
 
 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
+
+    if (SkBitmap::kARGB_8888_Config != fBitmap->config()) {
+        return NULL;
+    }
+
+    static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
+
+    if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
+        if (!fDoFilter && fInvType <= SkMatrix::kTranslate_Mask && !this->setupForTranslate()) {
+            return DoNothing_shaderproc;
+        }
+        return S32_D32_constX_shaderproc;
+    }
+
     if (fAlphaScale < 256) {
         return NULL;
     }
@@ -458,9 +577,6 @@
     if (fDoFilter) {
         return NULL;
     }
-    if (SkBitmap::kARGB_8888_Config != fBitmap->config()) {
-        return NULL;
-    }
 
     SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
     SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
diff --git a/src/core/SkBitmapProcState_filter.h b/src/core/SkBitmapProcState_filter.h
index f7848f7..1260665 100644
--- a/src/core/SkBitmapProcState_filter.h
+++ b/src/core/SkBitmapProcState_filter.h
@@ -79,3 +79,47 @@
     *dstColor = ((lo >> 8) & mask) | (hi & ~mask);
 }
 
+// Two color version, where we filter only along 1 axis
+static inline void Filter_32_opaque(unsigned t,
+                                    SkPMColor color0,
+                                    SkPMColor color1,
+                                    SkPMColor* dstColor) {
+    SkASSERT((unsigned)t <= 0xF);
+
+    static const uint32_t mask = gMask_00FF00FF; //0x00FF00FF;
+
+    int scale = 256 - 16*t;
+    uint32_t lo = (color0 & mask) * scale;
+    uint32_t hi = ((color0 >> 8) & mask) * scale;
+
+    scale = 16*t;
+    lo += (color1 & mask) * scale;
+    hi += ((color1 >> 8) & mask) * scale;
+
+    *dstColor = ((lo >> 8) & mask) | (hi & ~mask);
+}
+
+// Two color version, where we filter only along 1 axis
+static inline void Filter_32_alpha(unsigned t,
+                                   SkPMColor color0,
+                                   SkPMColor color1,
+                                   SkPMColor* dstColor,
+                                   unsigned alphaScale) {
+    SkASSERT((unsigned)t <= 0xF);
+    SkASSERT(alphaScale <= 256);
+
+    static const uint32_t mask = gMask_00FF00FF; //0x00FF00FF;
+
+    int scale = 256 - 16*t;
+    uint32_t lo = (color0 & mask) * scale;
+    uint32_t hi = ((color0 >> 8) & mask) * scale;
+
+    scale = 16*t;
+    lo += (color1 & mask) * scale;
+    hi += ((color1 >> 8) & mask) * scale;
+
+    lo = ((lo >> 8) & mask) * alphaScale;
+    hi = ((hi >> 8) & mask) * alphaScale;
+
+    *dstColor = ((lo >> 8) & mask) | (hi & ~mask);
+}