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/bench/BitmapBench.cpp b/bench/BitmapBench.cpp
index d8363fc..a472d24 100644
--- a/bench/BitmapBench.cpp
+++ b/bench/BitmapBench.cpp
@@ -149,7 +149,7 @@
         int count = N;
 #ifdef SK_RELEASE
         // in DEBUG, N is always 1
-        if (paint.getFlags() & SkPaint::kHighQualityFilterBitmap_Flag) {
+        if (SkPaint::kHigh_FilterLevel == paint.getFilterLevel()) {
             count /= BICUBIC_DUR_SCALE;
         }
 #endif
@@ -170,7 +170,7 @@
 #ifdef SK_DEBUG
         return 1;
 #else
-        return (paint.getFlags() & SkPaint::kHighQualityFilterBitmap_Flag) ?
+        return SkPaint::kHigh_FilterLevel == paint.getFilterLevel() ?
                 (float)BICUBIC_DUR_SCALE : 1;
 #endif
     }
@@ -264,20 +264,28 @@
             canvas->rotate(SkIntToScalar(35));
             canvas->translate(-x, -y);
         }
-
-        uint32_t orMask = 0;
-        uint32_t clearMask = SkPaint::kFilterBitmap_Flag | SkPaint::kHighQualityFilterBitmap_Flag;
-        if (fFlags & kBilerp_Flag) {
-            orMask |= SkPaint::kFilterBitmap_Flag;
-        }
-        if (fFlags & kBicubic_Flag) {
-            orMask |= SkPaint::kHighQualityFilterBitmap_Flag;
-        }
-        this->setPaintMasks(orMask, clearMask);
-
         INHERITED::onDraw(canvas);
     }
 
+    virtual void setupPaint(SkPaint* paint) SK_OVERRIDE {
+        this->INHERITED::setupPaint(paint);
+
+        int index = 0;
+        if (fFlags & kBilerp_Flag) {
+            index |= 1;
+        }
+        if (fFlags & kBicubic_Flag) {
+            index |= 2;
+        }
+        static const SkPaint::FilterLevel gLevels[] = {
+            SkPaint::kNone_FilterLevel,
+            SkPaint::kLow_FilterLevel,
+            SkPaint::kMedium_FilterLevel,
+            SkPaint::kHigh_FilterLevel
+        };
+        paint->setFilterLevel(gLevels[index]);
+}
+
 private:
     typedef BitmapBench INHERITED;
 };
diff --git a/bench/BitmapScaleBench.cpp b/bench/BitmapScaleBench.cpp
index 561e096..2187346 100644
--- a/bench/BitmapScaleBench.cpp
+++ b/bench/BitmapScaleBench.cpp
@@ -96,8 +96,7 @@
         SkCanvas canvas( fOutputBitmap );
         SkPaint paint;
 
-        paint.setFlags( SkPaint::kHighQualityFilterBitmap_Flag | SkPaint::kFilterBitmap_Flag );
-
+        paint.setFilterLevel(SkPaint::kHigh_FilterLevel);
         canvas.drawBitmapMatrix( fInputBitmap, fMatrix, &paint );
     }
 private:
diff --git a/gm/downsamplebitmap.cpp b/gm/downsamplebitmap.cpp
index e34effa..5cb971d 100644
--- a/gm/downsamplebitmap.cpp
+++ b/gm/downsamplebitmap.cpp
@@ -64,8 +64,7 @@
             matrix.setScale( curScale, curScale );
 
             SkPaint paint;
-            paint.setFilterBitmap(true);
-            paint.setFlags( paint.getFlags() | SkPaint::kHighQualityFilterBitmap_Flag );
+            paint.setFilterLevel(SkPaint::kHigh_FilterLevel);
 
             canvas->save();
             canvas->translate( (SkScalar) curX, 0.f );
diff --git a/gm/filterbitmap.cpp b/gm/filterbitmap.cpp
index 0afcb95..4a1b89e 100644
--- a/gm/filterbitmap.cpp
+++ b/gm/filterbitmap.cpp
@@ -31,11 +31,11 @@
 
     canvas->drawBitmapMatrix(bm, mat, &paint);
 
-    paint.setFilterBitmap(true);
+    paint.setFilterLevel(SkPaint::kLow_FilterLevel);
     canvas->translate(dx, 0);
     canvas->drawBitmapMatrix(bm, mat, &paint);
 
-    paint.setFlags(paint.getFlags() | SkPaint::kHighQualityFilterBitmap_Flag);
+    paint.setFilterLevel(SkPaint::kHigh_FilterLevel);
     canvas->translate(dx, 0);
     canvas->drawBitmapMatrix(bm, mat, &paint);
 }
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index 421a35b..fa0c61e 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -52,6 +52,14 @@
 */
 
 class SK_API SkPaint {
+    enum {
+        // DEPRECATED -- use setFilterLevel instead
+        kFilterBitmap_Flag    = 0x02, // temporary flag
+        // DEPRECATED -- use setFilterLevel instead
+        kHighQualityFilterBitmap_Flag = 0x4000, // temporary flag
+        // DEPRECATED -- use setFilterLevel instead
+        kHighQualityDownsampleBitmap_Flag = 0x8000, // temporary flag
+    };
 public:
     SkPaint();
     SkPaint(const SkPaint& paint);
@@ -98,10 +106,6 @@
     */
     enum Flags {
         kAntiAlias_Flag       = 0x01,   //!< mask to enable antialiasing
-
-        // DEPRECATED -- use setFilterLevel instead
-        kFilterBitmap_Flag    = 0x02, // temporary flag
-
         kDither_Flag          = 0x04,   //!< mask to enable dithering
         kUnderlineText_Flag   = 0x08,   //!< mask to enable underline text
         kStrikeThruText_Flag  = 0x10,   //!< mask to enable strike-thru text
@@ -114,12 +118,6 @@
         kAutoHinting_Flag     = 0x800,  //!< mask to force Freetype's autohinter
         kVerticalText_Flag    = 0x1000,
         kGenA8FromLCD_Flag    = 0x2000, // hack for GDI -- do not use if you can help it
-
-        // DEPRECATED -- use setFilterLevel instead
-        kHighQualityFilterBitmap_Flag = 0x4000, // temporary flag
-        // DEPRECATED -- use setFilterLevel instead
-        kHighQualityDownsampleBitmap_Flag = 0x8000, // temporary flag
-
         // when adding extra flags, note that the fFlags member is specified
         // with a bit-width and you'll have to expand it.
 
diff --git a/samplecode/SampleAll.cpp b/samplecode/SampleAll.cpp
index ff8249f..01fbe0f 100644
--- a/samplecode/SampleAll.cpp
+++ b/samplecode/SampleAll.cpp
@@ -392,7 +392,8 @@
 
         canvas->save();
         canvas->translate(SkIntToScalar(0), SkIntToScalar(5));
-        paint.setFlags(SkPaint::kAntiAlias_Flag | SkPaint::kFilterBitmap_Flag);
+        paint.setAntiAlias(true);
+        paint.setFilterLevel(SkPaint::kLow_FilterLevel);
         // !!! draw through a clip
         paint.setColor(SK_ColorLTGRAY);
         paint.setStyle(SkPaint::kFill_Style);
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);
diff --git a/tests/PaintTest.cpp b/tests/PaintTest.cpp
index 5631632..dc131f2 100644
--- a/tests/PaintTest.cpp
+++ b/tests/PaintTest.cpp
@@ -109,17 +109,28 @@
 }
 
 // temparary api for bicubic, just be sure we can set/clear it
-static void test_bicubic(skiatest::Reporter* reporter) {
-    SkPaint p0;
-    REPORTER_ASSERT(reporter, 0 == (p0.getFlags() & SkPaint::kBicubicFilterBitmap_Flag));
-    p0.setFlags(p0.getFlags() | SkPaint::kBicubicFilterBitmap_Flag);
-    REPORTER_ASSERT(reporter, 0 != (p0.getFlags() & SkPaint::kBicubicFilterBitmap_Flag));
-    SkPaint p1(p0);
-    REPORTER_ASSERT(reporter, 0 != (p1.getFlags() & SkPaint::kBicubicFilterBitmap_Flag));
-    p0.reset();
-    REPORTER_ASSERT(reporter, 0 == (p0.getFlags() & SkPaint::kBicubicFilterBitmap_Flag));
-    p0 = p1;
-    p0.setFlags(p0.getFlags() | SkPaint::kBicubicFilterBitmap_Flag);
+static void test_filterlevel(skiatest::Reporter* reporter) {
+    SkPaint p0, p1;
+    
+    REPORTER_ASSERT(reporter,
+                    SkPaint::kNone_FilterLevel == p0.getFilterLevel());
+    
+    static const SkPaint::FilterLevel gLevels[] = {
+        SkPaint::kNone_FilterLevel,
+        SkPaint::kLow_FilterLevel,
+        SkPaint::kMedium_FilterLevel,
+        SkPaint::kHigh_FilterLevel
+    };
+    for (size_t i = 0; i < SK_ARRAY_COUNT(gLevels); ++i) {
+        p0.setFilterLevel(gLevels[i]);
+        REPORTER_ASSERT(reporter, gLevels[i] == p0.getFilterLevel());
+        p1 = p0;
+        REPORTER_ASSERT(reporter, gLevels[i] == p1.getFilterLevel());
+
+        p0.reset();
+        REPORTER_ASSERT(reporter,
+                        SkPaint::kNone_FilterLevel == p0.getFilterLevel());
+    }
 }
 
 static void test_copy(skiatest::Reporter* reporter) {
@@ -230,7 +241,7 @@
     regression_cubic(reporter);
     regression_measureText(reporter);
 
-    test_bicubic(reporter);
+    test_filterlevel(reporter);
 
     // need to implement charsToGlyphs on other backends (e.g. linux, win)
     // before we can run this tests everywhere