fix copyTo to only copy the minimum pixels per row, and to lock the src before
trying to access its colorTable. Update unittest for copyTo. Add sample for
using a mask to clip a layer.



git-svn-id: http://skia.googlecode.com/svn/trunk@168 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/samplecode/SampleLayerMask.cpp b/samplecode/SampleLayerMask.cpp
new file mode 100644
index 0000000..8cbe76d
--- /dev/null
+++ b/samplecode/SampleLayerMask.cpp
@@ -0,0 +1,73 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkPorterDuff.h"
+#include "SkView.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+class LayerMaskView : public SkView {
+public:
+	LayerMaskView() {}
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "LayerMask");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawMask(SkCanvas* canvas, const SkRect& r) {
+        SkPaint paint;
+        paint.setAntiAlias(true);
+
+        if (true) {
+            SkBitmap mask;
+            int w = SkScalarRound(r.width());
+            int h = SkScalarRound(r.height());
+            mask.setConfig(SkBitmap::kARGB_8888_Config, w, h);
+            mask.allocPixels();
+            mask.eraseColor(0);
+            SkCanvas c(mask);
+            SkRect bounds = r;
+            bounds.offset(-bounds.fLeft, -bounds.fTop);
+            c.drawOval(bounds, paint);
+            
+            paint.setPorterDuffXfermode(SkPorterDuff::kDstIn_Mode);
+            canvas->drawBitmap(mask, r.fLeft, r.fTop, &paint);
+        } else {
+            SkPath p;
+            p.addOval(r);
+            p.setFillType(SkPath::kInverseWinding_FillType);
+            paint.setPorterDuffXfermode(SkPorterDuff::kDstOut_Mode);
+            canvas->drawPath(p, paint);
+        }
+    }
+
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFFDDDDDD);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        SkRect  r;
+        r.set(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(120), SkIntToScalar(120));
+        canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
+        canvas->drawColor(SK_ColorRED);
+        drawMask(canvas, r);
+        canvas->restore();
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new LayerMaskView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 3debd81..2765fab 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -710,6 +710,9 @@
         return false;
     }
 
+    // we lock this now, since we may need its colortable
+    SkAutoLockPixels srclock(*this);
+
     SkBitmap tmp;
     tmp.setConfig(dstConfig, this->width(), this->height());
 
@@ -721,7 +724,6 @@
         return false;
     }
 
-    SkAutoLockPixels srclock(*this);
     SkAutoLockPixels dstlock(tmp);
 
     if (!this->readyToDraw() || !tmp.readyToDraw()) {
@@ -733,7 +735,19 @@
        re-draw for the !sameConfigs cases
     */
     if (sameConfigs) {
-       memcpy(tmp.getPixels(), this->getPixels(), this->getSize());
+        if (tmp.getSize() == this->getSize()) {
+            memcpy(tmp.getPixels(), this->getPixels(), this->getSize());
+        } else {
+            const char* srcP = reinterpret_cast<const char*>(this->getPixels());
+            char* dstP = reinterpret_cast<char*>(tmp.getPixels());
+            // to be sure we don't read too much, only copy our logical pixels
+            size_t bytesToCopy = tmp.width() * tmp.bytesPerPixel();
+            for (int y = 0; y < tmp.height(); y++) {
+                memcpy(dstP, srcP, bytesToCopy);
+                srcP += this->rowBytes();
+                dstP += tmp.rowBytes();
+            }
+        }
     } else {
         // if the src has alpha, we have to clear the dst first
         if (!this->isOpaque()) {
diff --git a/tests/BitmapCopyTest.cpp b/tests/BitmapCopyTest.cpp
index f904859..95b49ce 100644
--- a/tests/BitmapCopyTest.cpp
+++ b/tests/BitmapCopyTest.cpp
@@ -1,5 +1,6 @@
 #include "Test.h"
 #include "SkBitmap.h"
+#include "SkRect.h"
 
 static const char* boolStr(bool value) {
     return value ? "true" : "false";
@@ -82,6 +83,30 @@
                     REPORTER_ASSERT(reporter, !memcmp(srcP, dstP,
                                                       src.getSize()));
                 }
+                // test extractSubset
+                {
+                    SkBitmap subset;
+                    SkIRect r;
+                    r.set(1, 1, 2, 2);
+                    if (src.extractSubset(&subset, r)) {
+                        REPORTER_ASSERT(reporter, subset.width() == 1);
+                        REPORTER_ASSERT(reporter, subset.height() == 1);
+
+                        SkBitmap copy;
+                        REPORTER_ASSERT(reporter,
+                                        subset.copyTo(&copy, subset.config()));
+                        REPORTER_ASSERT(reporter, copy.width() == 1);
+                        REPORTER_ASSERT(reporter, copy.height() == 1);
+                        REPORTER_ASSERT(reporter, copy.rowBytes() <= 4);
+                        
+                        SkAutoLockPixels alp0(subset);
+                        SkAutoLockPixels alp1(copy);
+                        // they should both have, or both not-have, a colortable
+                        bool hasCT = subset.getColorTable() != NULL;
+                        REPORTER_ASSERT(reporter,
+                                    (copy.getColorTable() != NULL) == hasCT);
+                    }
+                }
             } else {
                 // dst should be unchanged from its initial state
                 REPORTER_ASSERT(reporter, dst.config() == SkBitmap::kNo_Config);
diff --git a/xcode/core/core.xcodeproj/project.pbxproj b/xcode/core/core.xcodeproj/project.pbxproj
index e4d0ca9..c4c1630 100644
--- a/xcode/core/core.xcodeproj/project.pbxproj
+++ b/xcode/core/core.xcodeproj/project.pbxproj
@@ -262,9 +262,17 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+		009490660FB0AC280063C792 /* opengl */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			name = opengl;
+			sourceTree = "<group>";
+		};
 		08FB7794FE84155DC02AAC07 /* core */ = {
 			isa = PBXGroup;
 			children = (
+				009490660FB0AC280063C792 /* opengl */,
 				08FB7795FE84155DC02AAC07 /* src */,
 				C6A0FF2B0290797F04C91782 /* Documentation */,
 				1AB674ADFE9D54B511CA2CBB /* Products */,
diff --git a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
index 3a3a581..bd18517 100644
--- a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
+++ b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
@@ -66,6 +66,7 @@
 		007A7CC10F01658C00A2D6EE /* SampleXfermodes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007A7CB20F01658C00A2D6EE /* SampleXfermodes.cpp */; };
 		007C785E0F3B4C230004B142 /* SamplePathClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007C785D0F3B4C230004B142 /* SamplePathClip.cpp */; };
 		008C4D980F77DAEE0056981C /* SampleHairline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 008C4D970F77DAEE0056981C /* SampleHairline.cpp */; };
+		009490320FB0A5B90063C792 /* SampleLayerMask.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 009490310FB0A5B90063C792 /* SampleLayerMask.cpp */; };
 		009CC9190F65918A002185BE /* SampleFontScalerTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 009CC9180F65918A002185BE /* SampleFontScalerTest.cpp */; };
 		00A41E4B0EFC312F00C9CBEB /* SampleArc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A41E4A0EFC312F00C9CBEB /* SampleArc.cpp */; };
 		00C55DA10F8552DC000CAC09 /* SampleGradients.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */; };
@@ -183,6 +184,7 @@
 		007A7CB20F01658C00A2D6EE /* SampleXfermodes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleXfermodes.cpp; path = ../../samplecode/SampleXfermodes.cpp; sourceTree = SOURCE_ROOT; };
 		007C785D0F3B4C230004B142 /* SamplePathClip.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SamplePathClip.cpp; path = ../../samplecode/SamplePathClip.cpp; sourceTree = SOURCE_ROOT; };
 		008C4D970F77DAEE0056981C /* SampleHairline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleHairline.cpp; path = ../../samplecode/SampleHairline.cpp; sourceTree = SOURCE_ROOT; };
+		009490310FB0A5B90063C792 /* SampleLayerMask.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleLayerMask.cpp; path = ../../samplecode/SampleLayerMask.cpp; sourceTree = SOURCE_ROOT; };
 		009CC9180F65918A002185BE /* SampleFontScalerTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFontScalerTest.cpp; path = ../../samplecode/SampleFontScalerTest.cpp; sourceTree = SOURCE_ROOT; };
 		00A41E4A0EFC312F00C9CBEB /* SampleArc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleArc.cpp; path = ../../samplecode/SampleArc.cpp; sourceTree = SOURCE_ROOT; };
 		00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleGradients.cpp; path = ../../samplecode/SampleGradients.cpp; sourceTree = SOURCE_ROOT; };
@@ -222,6 +224,7 @@
 				007A7CA40F01658C00A2D6EE /* SamplePicture.cpp */,
 				00D6B5CB0F72DC4300C466B9 /* SampleFuzz.cpp */,
 				00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */,
+				009490310FB0A5B90063C792 /* SampleLayerMask.cpp */,
 				009CC9180F65918A002185BE /* SampleFontScalerTest.cpp */,
 				007A7CA50F01658C00A2D6EE /* SamplePoints.cpp */,
 				007A7CA70F01658C00A2D6EE /* SampleRegion.cpp */,
@@ -525,6 +528,7 @@
 				0041CE440F00A12400695E8C /* SampleLines.cpp in Sources */,
 				008C4D980F77DAEE0056981C /* SampleHairline.cpp in Sources */,
 				00C55DA10F8552DC000CAC09 /* SampleGradients.cpp in Sources */,
+				009490320FB0A5B90063C792 /* SampleLayerMask.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};