stop using bitmap-filter flags outside of paint itself, as a step towards really changing them into an enum

BUG=

Review URL: https://codereview.chromium.org/19825002

git-svn-id: http://skia.googlecode.com/svn/trunk@10240 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkBitmapFilter.cpp b/src/core/SkBitmapFilter.cpp
index 0604009..c2f68d4 100644
--- a/src/core/SkBitmapFilter.cpp
+++ b/src/core/SkBitmapFilter.cpp
@@ -101,7 +101,7 @@
 SkBitmapProcState::ShaderProc32
 SkBitmapProcState::chooseBitmapFilterProc() {
 
-    if (fFilterQuality != kHQ_BitmapFilter) {
+    if (fFilterLevel != SkPaint::kHigh_FilterLevel) {
         return NULL;
     }
 
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp
index ebb010f..2298398 100644
--- a/src/core/SkBitmapProcState.cpp
+++ b/src/core/SkBitmapProcState.cpp
@@ -91,13 +91,26 @@
     return (dimension & ~0x3FFF) == 0;
 }
 
+static bool effective_matrix_scale_sqrd(const SkMatrix& mat) {
+    SkPoint v1, v2;
+    
+    v1.fX = mat.getScaleX();
+    v1.fY = mat.getSkewY();
+    
+    v2.fX = mat.getSkewX();
+    v2.fY = mat.getScaleY();
+    
+    return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd());
+}
+
 // TODO -- we may want to pass the clip into this function so we only scale
 // the portion of the image that we're going to need.  This will complicate
 // the interface to the cache, but might be well worth it.
 
 void SkBitmapProcState::possiblyScaleImage() {
 
-    if (fFilterQuality != kHQ_BitmapFilter) {
+    if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
+        // none or low (bilerp) does not need to look any further
         return;
     }
 
@@ -125,7 +138,7 @@
     // doing high quality scaling.  If so, do the bitmap scale here and
     // remove the scaling component from the matrix.
 
-    if (fFilterQuality == kHQ_BitmapFilter &&
+    if (SkPaint::kHigh_FilterLevel == fFilterLevel &&
         fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) &&
         fOrigBitmap.config() == SkBitmap::kARGB_8888_Config) {
 
@@ -148,55 +161,73 @@
 
         // no need for any further filtering; we just did it!
 
-        fFilterQuality = kNone_BitmapFilter;
+        fFilterLevel = SkPaint::kNone_FilterLevel;
 
         return;
     }
 
-    if (!fOrigBitmap.hasMipMap() && fFilterQuality != kNone_BitmapFilter) {
+    /*
+     *  If we get here, the caller has requested either Med or High filter-level
+     *
+     *  If High, then our special-case for scale-only did not take, and so we
+     *  have to make a choice:
+     *      1. fall back on mipmaps + bilerp
+     *      2. fall back on scanline bicubic filter
+     *  For now, we compute the "scale" value from the matrix, and have a
+     *  threshold to decide when bicubic is better, and when mips are better.
+     *  No doubt a fancier decision tree could be used uere.
+     *
+     *  If Medium, then we just try to build a mipmap and select a level,
+     *  setting the filter-level to kLow to signal that we just need bilerp
+     *  to process the selected level.
+     */
 
-        // STEP 2: MIPMAP DOWNSAMPLE?
+    SkScalar scaleSqd = effective_matrix_scale_sqrd(fInvMatrix);
 
-        // Check to see if the transformation matrix is scaling *down*.
-        // If so, automatically build mipmaps.
+    if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
+        // Set the limit at 0.25 for the CTM... if the CTM is scaling smaller
+        // than this, then the mipmaps quality may be greater (certainly faster)
+        // so we only keep High quality if the scale is greater than this.
+        //
+        // Since we're dealing with the inverse, we compare against its inverse.
+        const SkScalar bicubicLimit = SkFloatToScalar(4.0f);
+        const SkScalar bicubicLimitSqd = bicubicLimit * bicubicLimit;
+        if (scaleSqd < bicubicLimitSqd) {  // use bicubic scanline
+            return;
+        }
 
-        SkPoint v1, v2;
+        // else set the filter-level to Medium, since we're scaling down and
+        // want to reqeust mipmaps
+        fFilterLevel = SkPaint::kMedium_FilterLevel;
+    }
+    
+    SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel);
 
-        // conservatively estimate if the matrix is scaling down by seeing
-        // what its upper left 2x2 portion does to two unit vectors.
-
-        v1.fX = fInvMatrix.getScaleX();
-        v1.fY = fInvMatrix.getSkewY();
-
-        v2.fX = fInvMatrix.getSkewX();
-        v2.fY = fInvMatrix.getScaleY();
-
-        if (v1.fX * v1.fX + v1.fY * v1.fY > 1 ||
-            v2.fX * v2.fX + v2.fY * v2.fY > 1) {
+    /**
+     *  Medium quality means use a mipmap for down-scaling, and just bilper
+     *  for upscaling. Since we're examining the inverse matrix, we look for
+     *  a scale > 1 to indicate down scaling by the CTM.
+     */
+    if (scaleSqd > SK_Scalar1) {
+        if (!fOrigBitmap.hasMipMap()) {
             fOrigBitmap.buildMipMap();
-
-            // Now that we've built the mipmaps and we know we're downsampling,
-            // downgrade to bilinear interpolation for the mip level.
-
-            fFilterQuality = kBilerp_BitmapFilter;
+            // build may fail, so we need to check again
+        }
+        if (fOrigBitmap.hasMipMap()) {
+            int shift = fOrigBitmap.extractMipLevel(&fScaledBitmap,
+                                        SkScalarToFixed(fInvMatrix.getScaleX()),
+                                        SkScalarToFixed(fInvMatrix.getSkewY()));
+            if (shift > 0) {
+                SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
+                fInvMatrix.postScale(scale, scale);
+                fBitmap = &fScaledBitmap;
+            }
         }
     }
 
-    if (fOrigBitmap.hasMipMap()) {
-
-        // STEP 3: We've got mipmaps, let's choose the closest level as our render
-        // source and adjust the matrix accordingly.
-
-        int shift = fOrigBitmap.extractMipLevel(&fScaledBitmap,
-                                                SkScalarToFixed(fInvMatrix.getScaleX()),
-                                                SkScalarToFixed(fInvMatrix.getSkewY()));
-
-        if (shift > 0) {
-            SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
-            fInvMatrix.postScale(scale, scale);
-            fBitmap = &fScaledBitmap;
-        }
-    }
+    // Now that we've built the mipmaps (if applicable), we set the filter-level
+    // bilinear interpolation.
+    fFilterLevel = SkPaint::kLow_FilterLevel;
 }
 
 void SkBitmapProcState::endContext() {
@@ -225,14 +256,7 @@
     // We may downgrade it later if we determine that we either don't need
     // or can't provide as high a quality filtering as the user requested.
 
-    fFilterQuality = kNone_BitmapFilter;
-    if (paint.isFilterBitmap()) {
-        if (paint.getFlags() & SkPaint::kHighQualityFilterBitmap_Flag) {
-            fFilterQuality = kHQ_BitmapFilter;
-        } else {
-            fFilterQuality = kBilerp_BitmapFilter;
-        }
-    }
+    fFilterLevel = paint.getFilterLevel();
 
 #ifndef SK_IGNORE_IMAGE_PRESCALE
     // possiblyScaleImage will look to see if it can rescale the image as a
@@ -284,7 +308,7 @@
 
     trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
 
-    if (kHQ_BitmapFilter == fFilterQuality) {
+    if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
         // If this is still set, that means we wanted HQ sampling
         // but couldn't do it as a preprocess.  Let's try to install
         // the scanline version of the HQ sampler.  If that process fails,
@@ -300,17 +324,17 @@
 
         fShaderProc32 = this->chooseBitmapFilterProc();
         if (!fShaderProc32) {
-            fFilterQuality = kBilerp_BitmapFilter;
+            fFilterLevel = SkPaint::kLow_FilterLevel;
         }
     }
 
-    if (kBilerp_BitmapFilter == fFilterQuality) {
+    if (SkPaint::kLow_FilterLevel == fFilterLevel) {
         // Only try bilerp if the matrix is "interesting" and
         // the image has a suitable size.
 
         if (fInvType <= SkMatrix::kTranslate_Mask ||
-            !valid_for_filtering(fBitmap->width() | fBitmap->height())) {
-                 fFilterQuality = kNone_BitmapFilter;
+                !valid_for_filtering(fBitmap->width() | fBitmap->height())) {
+            fFilterLevel = SkPaint::kNone_FilterLevel;
         }
     }
 
@@ -328,7 +352,7 @@
     // still set to HQ by the time we get here, then we must have installed
     // the shader proc above and can skip all this.
 
-    if (fFilterQuality < kHQ_BitmapFilter) {
+    if (fFilterLevel < SkPaint::kHigh_FilterLevel) {
 
         int index = 0;
         if (fAlphaScale < 256) {  // note: this distinction is not used for D16
@@ -337,7 +361,7 @@
         if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
             index |= 2;
         }
-        if (fFilterQuality != kNone_BitmapFilter) {
+        if (fFilterLevel > SkPaint::kNone_FilterLevel) {
             index |= 4;
         }
         // bits 3,4,5 encoding the source bitmap format
@@ -468,7 +492,7 @@
     SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
     SkASSERT(s.fInvKy == 0);
     SkASSERT(count > 0 && colors != NULL);
-    SkASSERT(SkBitmapProcState::kNone_BitmapFilter == s.fFilterQuality);
+    SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
 
     const int maxX = s.fBitmap->width() - 1;
     const int maxY = s.fBitmap->height() - 1;
@@ -542,7 +566,7 @@
     SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
     SkASSERT(s.fInvKy == 0);
     SkASSERT(count > 0 && colors != NULL);
-    SkASSERT(SkBitmapProcState::kNone_BitmapFilter == s.fFilterQuality);
+    SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
 
     const int stopX = s.fBitmap->width();
     const int stopY = s.fBitmap->height();
@@ -588,7 +612,7 @@
     int iY1   SK_INIT_TO_AVOID_WARNING;
     int iSubY SK_INIT_TO_AVOID_WARNING;
 
-    if (s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter) {
+    if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
         SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
         uint32_t xy[2];
 
@@ -669,7 +693,7 @@
     const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
     SkPMColor color;
 
-    if (s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter) {
+    if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
         const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
 
         if (s.fAlphaScale < 256) {
@@ -725,7 +749,7 @@
     static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
 
     if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
-        if (kNone_BitmapFilter == fFilterQuality &&
+        if (SkPaint::kNone_FilterLevel == fFilterLevel &&
             fInvType <= SkMatrix::kTranslate_Mask &&
             !this->setupForTranslate()) {
             return DoNothing_shaderproc;
@@ -739,7 +763,7 @@
     if (fInvType > SkMatrix::kTranslate_Mask) {
         return NULL;
     }
-    if (fFilterQuality != kNone_BitmapFilter) {
+    if (SkPaint::kNone_FilterLevel != fFilterLevel) {
         return NULL;
     }
 
@@ -835,9 +859,9 @@
     //  scale -vs- affine
     //  filter -vs- nofilter
     if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
-        proc = state.fFilterQuality != kNone_BitmapFilter ? check_scale_filter : check_scale_nofilter;
+        proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_scale_filter : check_scale_nofilter;
     } else {
-        proc = state.fFilterQuality != kNone_BitmapFilter ? check_affine_filter : check_affine_nofilter;
+        proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_affine_filter : check_affine_nofilter;
     }
     proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
 }
@@ -872,7 +896,7 @@
         size >>= 2;
     }
 
-    if (fFilterQuality != kNone_BitmapFilter) {
+    if (fFilterLevel != SkPaint::kNone_FilterLevel) {
         size >>= 1;
     }
 
diff --git a/src/core/SkBitmapProcState.h b/src/core/SkBitmapProcState.h
index b4fae04..349194f 100644
--- a/src/core/SkBitmapProcState.h
+++ b/src/core/SkBitmapProcState.h
@@ -89,12 +89,7 @@
     uint8_t             fInvType;           // chooseProcs
     uint8_t             fTileModeX;         // CONSTRUCTOR
     uint8_t             fTileModeY;         // CONSTRUCTOR
-
-    enum {
-        kNone_BitmapFilter,
-        kBilerp_BitmapFilter,
-        kHQ_BitmapFilter
-    } fFilterQuality;          // chooseProcs
+    uint8_t             fFilterLevel;       // chooseProcs
 
     /** The shader will let us know when we can release some of our resources
       * like scaled bitmaps.
diff --git a/src/core/SkBitmapProcState_matrixProcs.cpp b/src/core/SkBitmapProcState_matrixProcs.cpp
index d3cd550..a3d2b08 100644
--- a/src/core/SkBitmapProcState_matrixProcs.cpp
+++ b/src/core/SkBitmapProcState_matrixProcs.cpp
@@ -472,7 +472,7 @@
 //    test_int_tileprocs();
     // check for our special case when there is no scale/affine/perspective
     if (trivial_matrix) {
-        SkASSERT(kNone_BitmapFilter == fFilterQuality);
+        SkASSERT(SkPaint::kNone_FilterLevel == fFilterLevel);
         fIntTileProcY = choose_int_tile_proc(fTileModeY);
         switch (fTileModeX) {
             case SkShader::kClamp_TileMode:
@@ -485,7 +485,7 @@
     }
 
     int index = 0;
-    if (fFilterQuality != kNone_BitmapFilter) {
+    if (fFilterLevel != SkPaint::kNone_FilterLevel) {
         index = 1;
     }
     if (fInvType & SkMatrix::kPerspective_Mask) {
diff --git a/src/core/SkBitmapProcState_sample.h b/src/core/SkBitmapProcState_sample.h
index ac14b96..5c5f199 100644
--- a/src/core/SkBitmapProcState_sample.h
+++ b/src/core/SkBitmapProcState_sample.h
@@ -42,7 +42,7 @@
                               const uint32_t* SK_RESTRICT xy,
                               int count, DSTTYPE* SK_RESTRICT colors) {
     SkASSERT(count > 0 && colors != NULL);
-    SkASSERT(SkBitmapProcState::kNone_BitmapFilter == s.fFilterQuality);
+    SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
     SkDEBUGCODE(CHECKSTATE(s);)
 
 #ifdef PREAMBLE
@@ -85,7 +85,7 @@
                             int count, DSTTYPE* SK_RESTRICT colors) {
     SkASSERT(count > 0 && colors != NULL);
     SkASSERT(s.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask));
-    SkASSERT(SkBitmapProcState::kNone_BitmapFilter == s.fFilterQuality);
+    SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
     SkDEBUGCODE(CHECKSTATE(s);)
 
 #ifdef PREAMBLE
@@ -139,7 +139,7 @@
                           const uint32_t* SK_RESTRICT xy,
                            int count, DSTTYPE* SK_RESTRICT colors) {
     SkASSERT(count > 0 && colors != NULL);
-    SkASSERT(s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter);
+    SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);
     SkDEBUGCODE(CHECKSTATE(s);)
 
 #ifdef PREAMBLE
@@ -185,7 +185,7 @@
                             const uint32_t* SK_RESTRICT xy,
                             int count, DSTTYPE* SK_RESTRICT colors) {
     SkASSERT(count > 0 && colors != NULL);
-    SkASSERT(s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter);
+    SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);
     SkDEBUGCODE(CHECKSTATE(s);)
 
 #ifdef PREAMBLE
diff --git a/src/core/SkBitmapProcState_shaderproc.h b/src/core/SkBitmapProcState_shaderproc.h
index d765b8e..0014b4a 100644
--- a/src/core/SkBitmapProcState_shaderproc.h
+++ b/src/core/SkBitmapProcState_shaderproc.h
@@ -21,7 +21,7 @@
                              SkMatrix::kScale_Mask)) == 0);
     SkASSERT(s.fInvKy == 0);
     SkASSERT(count > 0 && colors != NULL);
-    SkASSERT(s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter);
+    SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);
     SkDEBUGCODE(CHECKSTATE(s);)
 
     const unsigned maxX = s.fBitmap->width() - 1;
diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp
index 401bea4..998c4bc 100644
--- a/src/effects/SkLayerDrawLooper.cpp
+++ b/src/effects/SkLayerDrawLooper.cpp
@@ -269,8 +269,7 @@
             bool needSeparator = false;
             SkAddFlagToString(str, SkToBool(SkPaint::kAntiAlias_Flag & rec->fInfo.fFlagsMask),
                               "AntiAlias", &needSeparator);
-            SkAddFlagToString(str, SkToBool(SkPaint::kFilterBitmap_Flag & rec->fInfo.fFlagsMask),
-                              "FilterBitmap", &needSeparator);
+//            SkAddFlagToString(str, SkToBool(SkPaint::kFilterBitmap_Flag & rec->fInfo.fFlagsMask), "FilterBitmap", &needSeparator);
             SkAddFlagToString(str, SkToBool(SkPaint::kDither_Flag & rec->fInfo.fFlagsMask),
                               "Dither", &needSeparator);
             SkAddFlagToString(str, SkToBool(SkPaint::kUnderlineText_Flag & rec->fInfo.fFlagsMask),
diff --git a/src/opts/SkBitmapProcState_opts_SSE2.cpp b/src/opts/SkBitmapProcState_opts_SSE2.cpp
index 0c84d00..0b07997 100644
--- a/src/opts/SkBitmapProcState_opts_SSE2.cpp
+++ b/src/opts/SkBitmapProcState_opts_SSE2.cpp
@@ -9,13 +9,14 @@
 
 #include <emmintrin.h>
 #include "SkBitmapProcState_opts_SSE2.h"
+#include "SkPaint.h"
 #include "SkUtils.h"
 
 void S32_opaque_D32_filter_DX_SSE2(const SkBitmapProcState& s,
                                    const uint32_t* xy,
                                    int count, uint32_t* colors) {
     SkASSERT(count > 0 && colors != NULL);
-    SkASSERT(s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter);
+    SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);
     SkASSERT(s.fBitmap->config() == SkBitmap::kARGB_8888_Config);
     SkASSERT(s.fAlphaScale == 256);
 
@@ -121,7 +122,7 @@
                                   const uint32_t* xy,
                                   int count, uint32_t* colors) {
     SkASSERT(count > 0 && colors != NULL);
-    SkASSERT(s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter);
+    SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);
     SkASSERT(s.fBitmap->config() == SkBitmap::kARGB_8888_Config);
     SkASSERT(s.fAlphaScale < 256);
 
@@ -641,7 +642,7 @@
                                    const uint32_t* xy,
                                    int count, uint16_t* colors) {
     SkASSERT(count > 0 && colors != NULL);
-    SkASSERT(s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter);
+    SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);
     SkASSERT(s.fBitmap->config() == SkBitmap::kARGB_8888_Config);
     SkASSERT(s.fBitmap->isOpaque());
 
diff --git a/src/opts/SkBitmapProcState_opts_SSSE3.cpp b/src/opts/SkBitmapProcState_opts_SSSE3.cpp
index f18b7e1..f8342ec 100644
--- a/src/opts/SkBitmapProcState_opts_SSSE3.cpp
+++ b/src/opts/SkBitmapProcState_opts_SSSE3.cpp
@@ -7,6 +7,7 @@
 
 #include <tmmintrin.h>  // SSSE3
 #include "SkBitmapProcState_opts_SSSE3.h"
+#include "SkPaint.h"
 #include "SkUtils.h"
 
 // adding anonymous namespace seemed to force gcc to inline directly the
@@ -385,7 +386,7 @@
                                      const uint32_t* xy,
                                      int count, uint32_t* colors) {
     SkASSERT(count > 0 && colors != NULL);
-    SkASSERT(s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter);
+    SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);
     SkASSERT(s.fBitmap->config() == SkBitmap::kARGB_8888_Config);
     if (has_alpha) {
         SkASSERT(s.fAlphaScale < 256);
@@ -576,7 +577,7 @@
                                        const uint32_t* xy,
                                        int count, uint32_t* colors) {
     SkASSERT(count > 0 && colors != NULL);
-    SkASSERT(s.fFilterQuality != SkBitmapProcState::kNone_BitmapFilter);
+    SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);
     SkASSERT(s.fBitmap->config() == SkBitmap::kARGB_8888_Config);
     if (has_alpha) {
         SkASSERT(s.fAlphaScale < 256);