detect nearly translate-only matrices when drawing bitmaps (for speed)
rename setXfermode(Mode) to setXfermodeMode(Mode) for sanity
fix memory leak in setXfermode(Mode)



git-svn-id: http://skia.googlecode.com/svn/trunk@239 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index a721479..5a01cd6 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -460,7 +460,7 @@
         paint, returning the mode that was set. If the Mode is SrcOver, then
         the paint's xfermode is set to null.
      */
-    SkXfermode* setXfermode(SkXfermode::Mode);
+    SkXfermode* setXfermodeMode(SkXfermode::Mode);
 
     /** Get the paint's patheffect object.
         <p />
diff --git a/samplecode/SampleAll.cpp b/samplecode/SampleAll.cpp
index c80ee43..7e83dec 100644
--- a/samplecode/SampleAll.cpp
+++ b/samplecode/SampleAll.cpp
@@ -84,7 +84,7 @@
 
     p.setAlpha(0x11);
     p.setStyle(SkPaint::kFill_Style);
-    p.setXfermode(SkXfermode::kSrc_Mode);
+    p.setXfermodeMode(SkXfermode::kSrc_Mode);
     rast->addLayer(p);
 }
 
@@ -93,7 +93,7 @@
     rast->addLayer(p);
 
     p.setAlpha(0x40);
-    p.setXfermode(SkXfermode::kSrc_Mode);
+    p.setXfermodeMode(SkXfermode::kSrc_Mode);
     p.setStyle(SkPaint::kStroke_Style);
     p.setStrokeWidth(SK_Scalar1*2);
     rast->addLayer(p);
@@ -107,7 +107,7 @@
 
     p.setStyle(SkPaint::kStroke_Style);
     p.setStrokeWidth(SK_Scalar1*3/2);
-    p.setXfermode(SkXfermode::kClear_Mode);
+    p.setXfermodeMode(SkXfermode::kClear_Mode);
     rast->addLayer(p);
 }
 
@@ -119,7 +119,7 @@
 
     p.setAlpha(0x20);
     p.setStyle(SkPaint::kFill_Style);
-    p.setXfermode(SkXfermode::kSrc_Mode);
+    p.setXfermodeMode(SkXfermode::kSrc_Mode);
     rast->addLayer(p);
 }
 
@@ -129,7 +129,7 @@
     rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
 
     p.setAlpha(0xFF);
-    p.setXfermode(SkXfermode::kClear_Mode);
+    p.setXfermodeMode(SkXfermode::kClear_Mode);
     rast->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
 
     p.setXfermode(NULL);
@@ -141,7 +141,7 @@
     rast->addLayer(p);
 
     p.setPathEffect(new SkDiscretePathEffect(SK_Scalar1*4, SK_Scalar1*3))->unref();
-    p.setXfermode(SkXfermode::kSrcOut_Mode);
+    p.setXfermodeMode(SkXfermode::kSrcOut_Mode);
     rast->addLayer(p);
 }
 
@@ -153,7 +153,7 @@
     SkLayerRasterizer* rast2 = new SkLayerRasterizer;
     r5(rast2, p);
     p.setRasterizer(rast2)->unref();
-    p.setXfermode(SkXfermode::kClear_Mode);
+    p.setXfermodeMode(SkXfermode::kClear_Mode);
     rast->addLayer(p);
 }
 
@@ -208,7 +208,7 @@
     lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
     lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
     p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
-    p.setXfermode(SkXfermode::kClear_Mode);
+    p.setXfermodeMode(SkXfermode::kClear_Mode);
     rast->addLayer(p);
 
     p.setPathEffect(NULL);
@@ -278,7 +278,7 @@
     lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
     lattice.postRotate(SkIntToScalar(30), 0, 0);
     p.setPathEffect(new Line2DPathEffect(SK_Scalar1*2, lattice))->unref();
-    p.setXfermode(SkXfermode::kClear_Mode);
+    p.setXfermodeMode(SkXfermode::kClear_Mode);
     rast->addLayer(p);
 
     p.setPathEffect(NULL);
diff --git a/samplecode/SampleLayerMask.cpp b/samplecode/SampleLayerMask.cpp
index 819eb5c..51a021b 100644
--- a/samplecode/SampleLayerMask.cpp
+++ b/samplecode/SampleLayerMask.cpp
@@ -35,13 +35,13 @@
             bounds.offset(-bounds.fLeft, -bounds.fTop);
             c.drawOval(bounds, paint);
             
-            paint.setXfermode(SkXfermode::kDstIn_Mode);
+            paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
             canvas->drawBitmap(mask, r.fLeft, r.fTop, &paint);
         } else {
             SkPath p;
             p.addOval(r);
             p.setFillType(SkPath::kInverseWinding_FillType);
-            paint.setXfermode(SkXfermode::kDstOut_Mode);
+            paint.setXfermodeMode(SkXfermode::kDstOut_Mode);
             canvas->drawPath(p, paint);
         }
     }
diff --git a/samplecode/SampleLayers.cpp b/samplecode/SampleLayers.cpp
index 5a52d0e..ae8bd33 100644
--- a/samplecode/SampleLayers.cpp
+++ b/samplecode/SampleLayers.cpp
@@ -26,7 +26,7 @@
     SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
     
     paint->setShader(s)->unref();
-    paint->setXfermode(SkXfermode::kDstIn_Mode);
+    paint->setXfermodeMode(SkXfermode::kDstIn_Mode);
 }
 
 static void dump_layers(const char label[], SkCanvas* canvas) {
@@ -162,7 +162,7 @@
             canvas->saveLayer(&r, &p);
             canvas->drawColor(0xFFFF0000);
             p.setAlpha(1);  // or 0
-            p.setXfermode(SkXfermode::kSrc_Mode);
+            p.setXfermodeMode(SkXfermode::kSrc_Mode);
             canvas->drawOval(r, p);
             canvas->restore();
             return;
@@ -239,7 +239,7 @@
         canvas->drawOval(r, p);
         
         p.setAlpha(0x80);
-        p.setXfermode(SkXfermode::kDstIn_Mode);
+        p.setXfermodeMode(SkXfermode::kDstIn_Mode);
         canvas->drawRect(bounds, p);
 
         canvas->restore();
diff --git a/samplecode/SampleMipMap.cpp b/samplecode/SampleMipMap.cpp
index 025cb07..21bf0f0 100644
--- a/samplecode/SampleMipMap.cpp
+++ b/samplecode/SampleMipMap.cpp
@@ -65,7 +65,7 @@
         bg.allocPixels();
         
         SkAutoCanvasRestore acr(canvas, true);
-        for (int i = 0; i < N-2; i++) {
+        for (int i = 0; i < 6; i++) {
             bg.eraseColor(0);
             SkCanvas c(bg);
             c.scale(SK_Scalar1 / (1 << i), SK_Scalar1 / (1 << i));
@@ -87,6 +87,8 @@
         this->drawBG(canvas);
         
         canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+        
+        canvas->scale(1.00000001, 0.9999999);
 
         drawN2(canvas, fBitmap);
 
diff --git a/samplecode/SampleStrokeText.cpp b/samplecode/SampleStrokeText.cpp
index e144511..a527bd2 100644
--- a/samplecode/SampleStrokeText.cpp
+++ b/samplecode/SampleStrokeText.cpp
@@ -55,7 +55,7 @@
     dst->eraseColor(SK_ColorWHITE);
     {
         SkCanvas canvas(*dst);
-        paint.setXfermode(SkXfermode::kDstATop_Mode);
+        paint.setXfermodeMode(SkXfermode::kDstATop_Mode);
         canvas.drawBitmap(src, 0, 0, &paint);
         paint.setColor(original.getColor());
         paint.setStyle(SkPaint::kStroke_Style);
@@ -86,7 +86,7 @@
     SkPaint paint(original);
 
     paint.setAntiAlias(true);
-    paint.setXfermode(SkXfermode::kDstATop_Mode);
+    paint.setXfermodeMode(SkXfermode::kDstATop_Mode);
     paint.setColor(original.getColor());
     paint.setStyle(SkPaint::kStroke_Style);
     
diff --git a/samplecode/SampleTextEffects.cpp b/samplecode/SampleTextEffects.cpp
index 5f7be1d..0dbde5e 100644
--- a/samplecode/SampleTextEffects.cpp
+++ b/samplecode/SampleTextEffects.cpp
@@ -68,7 +68,7 @@
 
     p.setAlpha(0x11);
     p.setStyle(SkPaint::kFill_Style);
-    p.setXfermode(SkXfermode::kSrc_Mode);
+    p.setXfermodeMode(SkXfermode::kSrc_Mode);
     rast->addLayer(p);
 }
 
@@ -77,7 +77,7 @@
     rast->addLayer(p);
 
     p.setAlpha(0x40);
-    p.setXfermode(SkXfermode::kSrc_Mode);
+    p.setXfermodeMode(SkXfermode::kSrc_Mode);
     p.setStyle(SkPaint::kStroke_Style);
     p.setStrokeWidth(SK_Scalar1*2);
     rast->addLayer(p);
@@ -91,7 +91,7 @@
 
     p.setStyle(SkPaint::kStroke_Style);
     p.setStrokeWidth(SK_Scalar1*3/2);
-    p.setXfermode(SkXfermode::kClear_Mode);
+    p.setXfermodeMode(SkXfermode::kClear_Mode);
     rast->addLayer(p);
 }
 
@@ -103,7 +103,7 @@
 
     p.setAlpha(0x20);
     p.setStyle(SkPaint::kFill_Style);
-    p.setXfermode(SkXfermode::kSrc_Mode);
+    p.setXfermodeMode(SkXfermode::kSrc_Mode);
     rast->addLayer(p);
 }
 
@@ -113,7 +113,7 @@
     rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
 
     p.setAlpha(0xFF);
-    p.setXfermode(SkXfermode::kClear_Mode);
+    p.setXfermodeMode(SkXfermode::kClear_Mode);
     rast->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
 
     p.setXfermode(NULL);
@@ -127,7 +127,7 @@
     rast->addLayer(p);
 
     p.setPathEffect(new SkDiscretePathEffect(SK_Scalar1*4, SK_Scalar1*3))->unref();
-    p.setXfermode(SkXfermode::kSrcOut_Mode);
+    p.setXfermodeMode(SkXfermode::kSrcOut_Mode);
     rast->addLayer(p);
 }
 
@@ -139,7 +139,7 @@
     SkLayerRasterizer* rast2 = new SkLayerRasterizer;
     r5(rast2, p);
     p.setRasterizer(rast2)->unref();
-    p.setXfermode(SkXfermode::kClear_Mode);
+    p.setXfermodeMode(SkXfermode::kClear_Mode);
     rast->addLayer(p);
 }
 
@@ -196,7 +196,7 @@
     lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
     lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
     p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
-    p.setXfermode(SkXfermode::kClear_Mode);
+    p.setXfermodeMode(SkXfermode::kClear_Mode);
     rast->addLayer(p);
 
     p.setPathEffect(NULL);
@@ -269,7 +269,7 @@
     lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
     lattice.postRotate(SkIntToScalar(30), 0, 0);
     p.setPathEffect(new Line2DPathEffect(SK_Scalar1*2, lattice))->unref();
-    p.setXfermode(SkXfermode::kClear_Mode);
+    p.setXfermodeMode(SkXfermode::kClear_Mode);
     rast->addLayer(p);
 
     p.setPathEffect(NULL);
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 28772b0..2413168 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1234,7 +1234,7 @@
 
     paint.setARGB(a, r, g, b);
     if (SkXfermode::kSrcOver_Mode != mode) {
-        paint.setXfermode(mode);
+        paint.setXfermodeMode(mode);
     }
     this->drawPaint(paint);
 }
@@ -1244,7 +1244,7 @@
 
     paint.setColor(c);
     if (SkXfermode::kSrcOver_Mode != mode) {
-        paint.setXfermode(mode);
+        paint.setXfermodeMode(mode);
     }
     this->drawPaint(paint);
 }
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 8146ff8..fa3eb55 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -873,15 +873,33 @@
     }
 }
 
-static inline bool just_translate(const SkMatrix& m) {
-    return (m.getType() & ~SkMatrix::kTranslate_Mask) == 0;
+/** For the purposes of drawing bitmaps, if a matrix is "almost" translate
+    go ahead and treat it as if it were, so that subsequent code can go fast.
+ */
+static bool just_translate(const SkMatrix& matrix, const SkBitmap& bitmap) {
+    SkMatrix::TypeMask mask = matrix.getType();
+
+    if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
+        return false;
+    }
+    if (mask & SkMatrix::kScale_Mask) {
+        SkScalar sx = matrix[SkMatrix::kMScaleX];
+        SkScalar sy = matrix[SkMatrix::kMScaleY];
+        int w = bitmap.width();
+        int h = bitmap.height();
+        int sw = SkScalarRound(SkScalarMul(sx, SkIntToScalar(w)));
+        int sh = SkScalarRound(SkScalarMul(sy, SkIntToScalar(h)));
+        return sw == w && sh == h;
+    }
+    // if we got here, we're either kTranslate_Mask or identity
+    return true;
 }
 
 void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap,
                               const SkPaint& paint) const {
     SkASSERT(bitmap.getConfig() == SkBitmap::kA8_Config);
 
-    if (just_translate(*fMatrix)) {        
+    if (just_translate(*fMatrix, bitmap)) {        
         int ix = SkScalarRound(fMatrix->getTranslateX());
         int iy = SkScalarRound(fMatrix->getTranslateY());
 
@@ -1005,7 +1023,8 @@
         return;
     }
 
-    if (bitmap.getConfig() != SkBitmap::kA8_Config && just_translate(matrix)) {
+    if (bitmap.getConfig() != SkBitmap::kA8_Config &&
+            just_translate(matrix, bitmap)) {
         int         ix = SkScalarRound(matrix.getTranslateX());
         int         iy = SkScalarRound(matrix.getTranslateY());
         uint32_t    storage[kBlitterStorageLongCount];
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 0495903..8b2a21b 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -1437,7 +1437,7 @@
     return mode;
 }
 
-SkXfermode* SkPaint::setXfermode(SkXfermode::Mode mode) {
+SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) {
     SkSafeUnref(fXfermode);
     fXfermode = SkXfermode::Create(mode);
     return fXfermode;
diff --git a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
index a7f70e6..19f3614 100644
--- a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
+++ b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
@@ -47,6 +47,7 @@
 		0041CE470F00A12400695E8C /* SampleNinePatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE310F00A12400695E8C /* SampleNinePatch.cpp */; };
 		0041CE480F00A12400695E8C /* SampleOverflow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE320F00A12400695E8C /* SampleOverflow.cpp */; };
 		0041CE4A0F00A12400695E8C /* SamplePatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE340F00A12400695E8C /* SamplePatch.cpp */; };
+		0057785F0FF17CCC00582CD9 /* SampleMipMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2794C04E0FE72903009AD112 /* SampleMipMap.cpp */; };
 		005E92DC0FF08507008965B9 /* SampleFilter2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE290F00A12400695E8C /* SampleFilter2.cpp */; };
 		005E92DE0FF0850E008965B9 /* SampleFillType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE270F00A12400695E8C /* SampleFillType.cpp */; };
 		005E92E00FF08512008965B9 /* SampleFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE280F00A12400695E8C /* SampleFilter.cpp */; };
@@ -79,7 +80,6 @@
 		2762F66D0FCCCABE002BD8B4 /* SkFlipPixelRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2762F66B0FCCCABE002BD8B4 /* SkFlipPixelRef.cpp */; };
 		2762F66E0FCCCABE002BD8B4 /* SkPageFlipper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2762F66C0FCCCABE002BD8B4 /* SkPageFlipper.cpp */; };
 		2762F67D0FCCCB01002BD8B4 /* SamplePageFlip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2762F6770FCCCB01002BD8B4 /* SamplePageFlip.cpp */; };
-		2794C04F0FE72903009AD112 /* SampleMipMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2794C04E0FE72903009AD112 /* SampleMipMap.cpp */; };
 		8D0C4E8D0486CD37000505A6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */; };
 		8D0C4E8E0486CD37000505A6 /* main.nib in Resources */ = {isa = PBXBuildFile; fileRef = 02345980000FD03B11CA0E72 /* main.nib */; };
 		8D0C4E920486CD37000505A6 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20286C33FDCF999611CA2CEA /* Carbon.framework */; };
@@ -569,12 +569,12 @@
 				00A7295D0FD8397600D5051F /* SampleAll.cpp in Sources */,
 				000A99820FD97526007E45BD /* SampleArc.cpp in Sources */,
 				00AF77B00FE2EA2D007F9650 /* SampleTestGL.cpp in Sources */,
-				2794C04F0FE72903009AD112 /* SampleMipMap.cpp in Sources */,
 				00AF787E0FE94433007F9650 /* SamplePath.cpp in Sources */,
 				0088C1160FEC311C00CE52F5 /* SampleXfermodes.cpp in Sources */,
 				005E92DC0FF08507008965B9 /* SampleFilter2.cpp in Sources */,
 				005E92DE0FF0850E008965B9 /* SampleFillType.cpp in Sources */,
 				005E92E00FF08512008965B9 /* SampleFilter.cpp in Sources */,
+				0057785F0FF17CCC00582CD9 /* SampleMipMap.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};