[PDF] Honor srcRect in drawBitmap.

Review URL: http://codereview.appspot.com/4083045

git-svn-id: http://skia.googlecode.com/svn/trunk@745 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/pdf/SkPDFDevice.h b/include/pdf/SkPDFDevice.h
index 7395373..b6bc7be 100644
--- a/include/pdf/SkPDFDevice.h
+++ b/include/pdf/SkPDFDevice.h
@@ -178,7 +178,7 @@
     void popGS();
     void setTextTransform(SkScalar x, SkScalar y, SkScalar textSkewX);
     void internalDrawBitmap(const SkMatrix& matrix, const SkBitmap& bitmap,
-                            const SkPaint& paint);
+                            const SkIRect* srcRect, const SkPaint& paint);
 
     SkMatrix setTransform(const SkMatrix& matrix);
 };
diff --git a/include/pdf/SkPDFImage.h b/include/pdf/SkPDFImage.h
index 6e5ee37..48d6398 100644
--- a/include/pdf/SkPDFImage.h
+++ b/include/pdf/SkPDFImage.h
@@ -22,6 +22,7 @@
 #include "SkRefCnt.h"
 
 class SkBitmap;
+class SkIRect;
 class SkPaint;
 class SkPDFCatalog;
 
@@ -40,7 +41,8 @@
      *  @param bitmap  The image to use.
      *  @param paint   Used to calculate alpha, masks, etc.
      */
-    SkPDFImage(const SkBitmap& bitmap, const SkPaint& paint);
+    SkPDFImage(const SkBitmap& bitmap, const SkIRect& srcRect,
+               const SkPaint& paint);
     virtual ~SkPDFImage();
 
     // The SkPDFObject interface.
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 4cbdf9c..b98e4af 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -266,7 +266,7 @@
 void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& path,
                            const SkPaint& paint, const SkMatrix* prePathMatrix,
                            bool pathIsMutable) {
-    NOT_IMPLEMENTED("drawPath with prePathMatrix", (prePathMatrix != NULL));
+    NOT_IMPLEMENTED(prePathMatrix != NULL, true);
 
     if (paint.getPathEffect()) {
         // Apply the path effect to path and draw it that way.
@@ -287,18 +287,16 @@
 void SkPDFDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap,
                              const SkIRect* srcRect,
                              const SkMatrix& matrix, const SkPaint& paint) {
-    // TODO: respect srcRect if present
-
     SkMatrix transform = matrix;
     transform.postConcat(fGraphicStack[fGraphicStackIndex].fTransform);
-    internalDrawBitmap(transform, bitmap, paint);
+    internalDrawBitmap(transform, bitmap, srcRect, paint);
 }
 
 void SkPDFDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap,
                              int x, int y, const SkPaint& paint) {
     SkMatrix matrix;
     matrix.setTranslate(x, y);
-    internalDrawBitmap(matrix, bitmap, paint);
+    internalDrawBitmap(matrix, bitmap, NULL, paint);
 }
 
 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
@@ -813,17 +811,22 @@
 
 void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
                                      const SkBitmap& bitmap,
+                                     const SkIRect* srcRect,
                                      const SkPaint& paint) {
+    SkIRect subset = SkIRect::MakeWH(bitmap.width(), bitmap.height());
+    if (srcRect && !subset.intersect(*srcRect))
+        return;
+
     SkMatrix scaled;
     // Adjust for origin flip.
     scaled.setScale(1, -1);
     scaled.postTranslate(0, 1);
     // Scale the image up from 1x1 to WxH.
-    scaled.postScale(bitmap.width(), bitmap.height());
+    scaled.postScale(subset.width(), subset.height());
     scaled.postConcat(matrix);
     SkMatrix curTransform = setTransform(scaled);
 
-    SkPDFImage* image = new SkPDFImage(bitmap, paint);
+    SkPDFImage* image = new SkPDFImage(bitmap, subset, paint);
     fXObjectResources.push(image);  // Transfer reference.
     fContent.append("/X");
     fContent.appendS32(fXObjectResources.count() - 1);
diff --git a/src/pdf/SkPDFImage.cpp b/src/pdf/SkPDFImage.cpp
index 2162eae..51bf8ae 100644
--- a/src/pdf/SkPDFImage.cpp
+++ b/src/pdf/SkPDFImage.cpp
@@ -22,87 +22,91 @@
 #include "SkPaint.h"
 #include "SkPackBits.h"
 #include "SkPDFCatalog.h"
+#include "SkRect.h"
 #include "SkStream.h"
 #include "SkString.h"
 #include "SkUnPreMultiply.h"
 
 namespace {
 
-SkMemoryStream* extractImageData(const SkBitmap& bitmap) {
+SkMemoryStream* extractImageData(const SkBitmap& bitmap,
+                                 const SkIRect& srcRect) {
     SkMemoryStream* result = NULL;
 
     bitmap.lockPixels();
     switch (bitmap.getConfig()) {
-        case SkBitmap::kIndex8_Config:
-            result = new SkMemoryStream(bitmap.getPixels(), bitmap.getSize(),
-                                        true);
+        case SkBitmap::kIndex8_Config: {
+            const int rowBytes = srcRect.width();
+            result = new SkMemoryStream(rowBytes * srcRect.height());
+            uint8_t* dst = (uint8_t*)result->getMemoryBase();
+            for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
+                memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes);
+                dst += rowBytes;
+            }
             break;
+        }
         case SkBitmap::kRLE_Index8_Config: {
-            result = new SkMemoryStream(bitmap.getSize());
+            const int rowBytes = srcRect.width();
+            result = new SkMemoryStream(rowBytes * srcRect.height());
+            uint8_t* dst = (uint8_t*)result->getMemoryBase();
             const SkBitmap::RLEPixels* rle =
                 (const SkBitmap::RLEPixels*)bitmap.getPixels();
-            uint8_t* dst = (uint8_t*)result->getMemoryBase();
-            const int width = bitmap.width();
-            for (int y = 0; y < bitmap.height(); y++) {
-                SkPackBits::Unpack8(rle->packedAtY(y), width, dst);
-                dst += width;
+            for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
+                SkPackBits::Unpack8(dst, srcRect.fLeft, rowBytes,
+                                    rle->packedAtY(y));
+                dst += rowBytes;
             }
             break;
         }
         case SkBitmap::kARGB_4444_Config: {
-            const int width = bitmap.width();
-            const int rowBytes = (width * 3 + 1) / 2;
-            result = new SkMemoryStream(rowBytes * bitmap.height());
+            const int rowBytes = (srcRect.width() * 3 + 1) / 2;
+            result = new SkMemoryStream(rowBytes * srcRect.height());
             uint8_t* dst = (uint8_t*)result->getMemoryBase();
-            for (int y = 0; y < bitmap.height(); y++) {
+            for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
                 uint16_t* src = bitmap.getAddr16(0, y);
-                for (int x = 0; x < width; x += 2) {
-                    dst[0] = (SkGetPackedR4444(src[0]) << 4) |
-                        SkGetPackedG4444(src[0]);
-                    dst[1] = (SkGetPackedB4444(src[0]) << 4) |
-                        SkGetPackedR4444(src[1]);
-                    dst[2] = (SkGetPackedG4444(src[1]) << 4) |
-                        SkGetPackedB4444(src[1]);
-                    src += 2;
+                int x;
+                for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
+                    dst[0] = (SkGetPackedR4444(src[x]) << 4) |
+                        SkGetPackedG4444(src[x]);
+                    dst[1] = (SkGetPackedB4444(src[x]) << 4) |
+                        SkGetPackedR4444(src[x + 1]);
+                    dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) |
+                        SkGetPackedB4444(src[x + 1]);
                     dst += 3;
                 }
-                if (width & 1) {
-                    dst[0] = (SkGetPackedR4444(src[0]) << 4) |
-                        SkGetPackedG4444(src[0]);
-                    dst[1] = (SkGetPackedB4444(src[0]) << 4);
+                if (srcRect.width() & 1) {
+                    dst[0] = (SkGetPackedR4444(src[x]) << 4) |
+                        SkGetPackedG4444(src[x]);
+                    dst[1] = (SkGetPackedB4444(src[x]) << 4);
                 }
             }
             break;
         }
         case SkBitmap::kRGB_565_Config: {
-            const int width = bitmap.width();
-            const int rowBytes = width * 3;
-            result = new SkMemoryStream(rowBytes * bitmap.height());
+            const int rowBytes = srcRect.width() * 3;
+            result = new SkMemoryStream(rowBytes * srcRect.height());
             uint8_t* dst = (uint8_t*)result->getMemoryBase();
-            for (int y = 0; y < bitmap.height(); y++) {
+            for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
                 uint16_t* src = bitmap.getAddr16(0, y);
-                for (int x = 0; x < width; x++) {
-                    dst[0] = SkGetPackedR16(src[0]);
-                    dst[1] = SkGetPackedG16(src[0]);
-                    dst[2] = SkGetPackedB16(src[0]);
-                    src++;
+                for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
+                    dst[0] = SkGetPackedR16(src[x]);
+                    dst[1] = SkGetPackedG16(src[x]);
+                    dst[2] = SkGetPackedB16(src[x]);
                     dst += 3;
                 }
             }
             break;
         }
         case SkBitmap::kARGB_8888_Config: {
-            const int width = bitmap.width();
-            const int rowBytes = width * 3;
-            result = new SkMemoryStream(rowBytes * bitmap.height());
+            const int rowBytes = srcRect.width() * 3;
+            result = new SkMemoryStream(rowBytes * srcRect.height());
             uint8_t* dst = (uint8_t*)result->getMemoryBase();
-            for (int y = 0; y < bitmap.height(); y++) {
+            for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
                 uint32_t* src = bitmap.getAddr32(0, y);
-                for (int x = 0; x < width; x++) {
-                    dst[0] = SkGetPackedR32(src[0]);
-                    dst[1] = SkGetPackedG32(src[0]);
-                    dst[2] = SkGetPackedB32(src[0]);
-                    src++;
+                for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
+                    dst[0] = SkGetPackedR32(src[x]);
+                    dst[1] = SkGetPackedG32(src[x]);
+                    dst[2] = SkGetPackedB32(src[x]);
                     dst += 3;
                 }
             }
@@ -149,7 +153,8 @@
 
 };  // namespace
 
-SkPDFImage::SkPDFImage(const SkBitmap& bitmap, const SkPaint& paint) {
+SkPDFImage::SkPDFImage(const SkBitmap& bitmap, const SkIRect& srcRect,
+                       const SkPaint& paint) {
     SkBitmap::Config config = bitmap.getConfig();
 
     // TODO(vandebo) Handle alpha and alpha only images correctly.
@@ -159,7 +164,7 @@
              config == SkBitmap::kIndex8_Config ||
              config == SkBitmap::kRLE_Index8_Config);
 
-    SkMemoryStream* image_data = extractImageData(bitmap);
+    SkMemoryStream* image_data = extractImageData(bitmap, srcRect);
     SkAutoUnref image_data_unref(image_data);
     fStream = new SkPDFStream(image_data);
     fStream->unref();  // SkRefPtr and new both took a reference.
@@ -172,11 +177,11 @@
     subTypeValue->unref();  // SkRefPtr and new both took a reference.
     insert("Subtype", subTypeValue.get());
 
-    SkRefPtr<SkPDFInt> widthValue = new SkPDFInt(bitmap.width());
+    SkRefPtr<SkPDFInt> widthValue = new SkPDFInt(srcRect.width());
     widthValue->unref();  // SkRefPtr and new both took a reference.
     insert("Width", widthValue.get());
 
-    SkRefPtr<SkPDFInt> heightValue = new SkPDFInt(bitmap.height());
+    SkRefPtr<SkPDFInt> heightValue = new SkPDFInt(srcRect.height());
     heightValue->unref();  // SkRefPtr and new both took a reference.
     insert("Height", heightValue.get());