Use SkPicture::ExtractBitmap callback in pdf too, there is no need for a specialized function pointer for pdf only only to pass a rectangle, when we can use subseted bitmaps.

R=scroggo@google.com, reed@google.com, vandebo@chromium.org, bsalomon@google.com

Author: edisonn@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@11591 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index e84d61a..defd691 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -193,7 +193,7 @@
         | SkGPipeWriter::kSharedAddressSpace_Flag }
 };
 
-static bool encode_to_dct_stream(SkWStream* stream, const SkBitmap& bitmap, const SkIRect& rect);
+static SkData* encode_to_dct_data(size_t* pixelRefOffset, const SkBitmap& bitmap);
 
 const static ErrorCombination kDefaultIgnorableErrorTypes = ErrorCombination()
     .plus(kMissingExpectations_ErrorType)
@@ -633,7 +633,7 @@
                               SkScalarRoundToInt(content.height()));
             dev = new SkPDFDevice(pageSize, contentSize, initialTransform);
         }
-        dev->setDCTEncoder(encode_to_dct_stream);
+        dev->setDCTEncoder(encode_to_dct_data);
         SkAutoUnref aur(dev);
 
         SkCanvas c(dev);
@@ -1422,7 +1422,6 @@
 DEFINE_int32(pdfJpegQuality, -1, "Encodes images in JPEG at quality level N, "
              "which can be in range 0-100). N = -1 will disable JPEG compression. "
              "Default is N = 100, maximum quality.");
-
 // TODO(edisonn): pass a matrix instead of forcePerspectiveMatrix
 // Either the 9 numbers defining the matrix
 // or probably more readable would be to replace it with a set of a few predicates
@@ -1431,32 +1430,33 @@
 // then we can write something reabable like --rotate centerx centery 90
 DEFINE_bool(forcePerspectiveMatrix, false, "Force a perspective matrix.");
 
-static bool encode_to_dct_stream(SkWStream* stream, const SkBitmap& bitmap, const SkIRect& rect) {
+static SkData* encode_to_dct_data(size_t* pixelRefOffset, const SkBitmap& bitmap) {
     // Filter output of warnings that JPEG is not available for the image.
-    if (bitmap.width() >= 65500 || bitmap.height() >= 65500) return false;
-    if (FLAGS_pdfJpegQuality == -1) return false;
+    if (bitmap.width() >= 65500 || bitmap.height() >= 65500) return NULL;
+    if (FLAGS_pdfJpegQuality == -1) return NULL;
 
-    SkIRect bitmapBounds;
-    SkBitmap subset;
-    const SkBitmap* bitmapToUse = &bitmap;
-    bitmap.getBounds(&bitmapBounds);
-    if (rect != bitmapBounds) {
-        SkAssertResult(bitmap.extractSubset(&subset, rect));
-        bitmapToUse = ⊂
-    }
-
+    SkBitmap bm = bitmap;
 #if defined(SK_BUILD_FOR_MAC)
     // Workaround bug #1043 where bitmaps with referenced pixels cause
     // CGImageDestinationFinalize to crash
     SkBitmap copy;
-    bitmapToUse->deepCopyTo(&copy, bitmapToUse->config());
-    bitmapToUse = ©
+    bitmap.deepCopyTo(&copy, bitmap.config());
+    bm = copy;
 #endif
 
-    return SkImageEncoder::EncodeStream(stream,
-                                        *bitmapToUse,
-                                        SkImageEncoder::kJPEG_Type,
-                                        FLAGS_pdfJpegQuality);
+    SkPixelRef* pr = bm.pixelRef();
+    if (pr != NULL) {
+        SkData* data = pr->refEncodedData();
+        if (data != NULL) {
+            *pixelRefOffset = bm.pixelRefOffset();
+            return data;
+        }
+    }
+
+    *pixelRefOffset = 0;
+    return SkImageEncoder::EncodeData(bm,
+                                      SkImageEncoder::kJPEG_Type,
+                                      FLAGS_pdfJpegQuality);
 }
 
 static int findConfig(const char config[]) {
diff --git a/include/pdf/SkPDFDevice.h b/include/pdf/SkPDFDevice.h
index 8ac227d..02acce3 100644
--- a/include/pdf/SkPDFDevice.h
+++ b/include/pdf/SkPDFDevice.h
@@ -14,6 +14,7 @@
 #include "SkCanvas.h"
 #include "SkPaint.h"
 #include "SkPath.h"
+#include "SkPicture.h"
 #include "SkRect.h"
 #include "SkRefCnt.h"
 #include "SkStream.h"
@@ -38,8 +39,6 @@
 struct GraphicStateEntry;
 struct NamedDestination;
 
-typedef bool (*EncodeToDCTStream)(SkWStream* stream, const SkBitmap& bitmap, const SkIRect& rect);
-
 /** \class SkPDFDevice
 
     The drawing context for the PDF backend.
@@ -140,7 +139,7 @@
      *         encoding and decoding might not be worth the space savings,
      *         if any at all.
      */
-    void setDCTEncoder(EncodeToDCTStream encoder) {
+    void setDCTEncoder(SkPicture::EncodeBitmap encoder) {
         fEncoder = encoder;
     }
 
@@ -232,7 +231,7 @@
     // Glyph ids used for each font on this device.
     SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage;
 
-    EncodeToDCTStream fEncoder;
+    SkPicture::EncodeBitmap fEncoder;
 
     SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack,
                 const SkRegion& existingClipRegion);
diff --git a/src/pdf/SkPDFImage.cpp b/src/pdf/SkPDFImage.cpp
index fbd37eb..19ad79e 100644
--- a/src/pdf/SkPDFImage.cpp
+++ b/src/pdf/SkPDFImage.cpp
@@ -339,7 +339,7 @@
 // static
 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
                                     const SkIRect& srcRect,
-                                    EncodeToDCTStream encoder) {
+                                    SkPicture::EncodeBitmap encoder) {
     if (bitmap.getConfig() == SkBitmap::kNo_Config) {
         return NULL;
     }
@@ -390,7 +390,7 @@
                        const SkBitmap& bitmap,
                        bool isAlpha,
                        const SkIRect& srcRect,
-                       EncodeToDCTStream encoder)
+                       SkPicture::EncodeBitmap encoder)
     : fIsAlpha(isAlpha),
       fSrcRect(srcRect),
       fEncoder(encoder) {
@@ -482,19 +482,28 @@
         // Initializing image data for the first time.
         SkDynamicMemoryWStream dctCompressedWStream;
         if (!skip_compression(catalog) && fEncoder &&
-                get_uncompressed_size(fBitmap, fSrcRect) > 1 &&
-                fEncoder(&dctCompressedWStream, fBitmap, fSrcRect) &&
-                dctCompressedWStream.getOffset() <
-                            get_uncompressed_size(fBitmap, fSrcRect)) {
-            SkAutoTUnref<SkData> data(dctCompressedWStream.copyToData());
-            SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data)));
-            setData(stream.get());
+                get_uncompressed_size(fBitmap, fSrcRect) > 1) {
+            SkBitmap subset;
+            // Extract subset
+            if (!fBitmap.extractSubset(&subset, fSrcRect)) {
+                // TODO(edisonn) It fails only for kA1_Config, if that is a
+                // major concern we will fix it later, so far it is NYI.
+                return false;
+            }
+            size_t pixelRefOffset = 0;
+            SkAutoTUnref<SkData> data(fEncoder(&pixelRefOffset, subset));
+            if (data.get() && data->size() < get_uncompressed_size(fBitmap,
+                                                                   fSrcRect)) {
+                SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream,
+                                                         (data)));
+                setData(stream.get());
 
-            insertName("Filter", "DCTDecode");
-            insertInt("ColorTransform", kNoColorTransform);
-            insertInt("Length", getData()->getLength());
-            setState(kCompressed_State);
-            return true;
+                insertName("Filter", "DCTDecode");
+                insertInt("ColorTransform", kNoColorTransform);
+                insertInt("Length", getData()->getLength());
+                setState(kCompressed_State);
+                return true;
+            }
         }
         // Fallback method
         if (!fStreamValid) {
diff --git a/src/pdf/SkPDFImage.h b/src/pdf/SkPDFImage.h
index 52d323d..10f8be6 100644
--- a/src/pdf/SkPDFImage.h
+++ b/src/pdf/SkPDFImage.h
@@ -10,6 +10,7 @@
 #ifndef SkPDFImage_DEFINED
 #define SkPDFImage_DEFINED
 
+#include "SkPicture.h"
 #include "SkPDFDevice.h"
 #include "SkPDFStream.h"
 #include "SkPDFTypes.h"
@@ -38,7 +39,7 @@
      */
     static SkPDFImage* CreateImage(const SkBitmap& bitmap,
                                    const SkIRect& srcRect,
-                                   EncodeToDCTStream encoder);
+                                   SkPicture::EncodeBitmap encoder);
 
     virtual ~SkPDFImage();
 
@@ -60,7 +61,7 @@
     SkBitmap fBitmap;
     bool fIsAlpha;
     SkIRect fSrcRect;
-    EncodeToDCTStream fEncoder;
+    SkPicture::EncodeBitmap fEncoder;
     bool fStreamValid;
 
     SkTDArray<SkPDFObject*> fResources;
@@ -80,7 +81,7 @@
      *                    May be NULL.
      */
     SkPDFImage(SkStream* stream, const SkBitmap& bitmap, bool isAlpha,
-               const SkIRect& srcRect, EncodeToDCTStream encoder);
+               const SkIRect& srcRect, SkPicture::EncodeBitmap encoder);
 
     /** Copy constructor, used to generate substitutes.
      *  @param image      The SkPDFImage to copy.
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index b4ba052..0d623a1 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -39,9 +39,11 @@
     SkTDArray<SkPDFObject*> fResources;
 };
 
-static bool encode_to_dct_stream(SkWStream* stream, const SkBitmap& bitmap, const SkIRect& rect) {
-    stream->writeText("DCT compessed stream.");
-    return true;
+#define DUMMY_TEXT "DCT compessed stream."
+
+static SkData* encode_to_dct_data(size_t* pixelRefOffset, const SkBitmap& bitmap) {
+    *pixelRefOffset = 0;
+    return SkData::NewWithProc(DUMMY_TEXT, sizeof(DUMMY_TEXT) - 1, NULL, NULL);
 }
 
 static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
@@ -253,7 +255,7 @@
     SkAutoTUnref<SkPDFDevice> dev(new SkPDFDevice(pageSize, pageSize, SkMatrix::I()));
 
     if (useDCTEncoder) {
-        dev->setDCTEncoder(encode_to_dct_stream);
+        dev->setDCTEncoder(encode_to_dct_data);
     }
 
     SkCanvas c(dev);
diff --git a/tools/PdfRenderer.h b/tools/PdfRenderer.h
index d2d1a5c..be338e9 100644
--- a/tools/PdfRenderer.h
+++ b/tools/PdfRenderer.h
@@ -33,7 +33,7 @@
     virtual void render() = 0;
     virtual void end();
 
-    PdfRenderer(EncodeToDCTStream encoder)
+    PdfRenderer(SkPicture::EncodeBitmap encoder)
         : fPicture(NULL)
         , fPDFDevice(NULL)
         , fEncoder(encoder)
@@ -48,7 +48,7 @@
     SkAutoTUnref<SkCanvas> fCanvas;
     SkPicture* fPicture;
     SkPDFDevice* fPDFDevice;
-    EncodeToDCTStream fEncoder;
+    SkPicture::EncodeBitmap fEncoder;
 
 private:
     typedef SkRefCnt INHERITED;
@@ -56,7 +56,7 @@
 
 class SimplePdfRenderer : public PdfRenderer {
 public:
-    SimplePdfRenderer(EncodeToDCTStream encoder)
+    SimplePdfRenderer(SkPicture::EncodeBitmap encoder)
         : PdfRenderer(encoder) {}
     virtual void render() SK_OVERRIDE;
 
diff --git a/tools/render_pdfs_main.cpp b/tools/render_pdfs_main.cpp
index f443502..a710064 100644
--- a/tools/render_pdfs_main.cpp
+++ b/tools/render_pdfs_main.cpp
@@ -12,6 +12,7 @@
 #include "SkImageEncoder.h"
 #include "SkOSFile.h"
 #include "SkPicture.h"
+#include "SkPixelRef.h"
 #include "SkStream.h"
 #include "SkTArray.h"
 #include "PdfRenderer.h"
@@ -81,30 +82,33 @@
 }
 
 int gJpegQuality = 100;
-static bool encode_to_dct_stream(SkWStream* stream, const SkBitmap& bitmap, const SkIRect& rect) {
-    if (gJpegQuality == -1) return false;
+static SkData* encode_to_dct_data(size_t* pixelRefOffset, const SkBitmap& bitmap) {
+    if (gJpegQuality == -1) {
+        return NULL;
+    }
 
-        SkIRect bitmapBounds;
-        SkBitmap subset;
-        const SkBitmap* bitmapToUse = &bitmap;
-        bitmap.getBounds(&bitmapBounds);
-        if (rect != bitmapBounds) {
-            SkAssertResult(bitmap.extractSubset(&subset, rect));
-            bitmapToUse = &subset;
-        }
-
+    SkBitmap bm = bitmap;
 #if defined(SK_BUILD_FOR_MAC)
-        // Workaround bug #1043 where bitmaps with referenced pixels cause
-        // CGImageDestinationFinalize to crash
-        SkBitmap copy;
-        bitmapToUse->deepCopyTo(&copy, bitmapToUse->config());
-        bitmapToUse = &copy;
+    // Workaround bug #1043 where bitmaps with referenced pixels cause
+    // CGImageDestinationFinalize to crash
+    SkBitmap copy;
+    bitmap.deepCopyTo(&copy, bitmap.config());
+    bm = copy;
 #endif
 
-    return SkImageEncoder::EncodeStream(stream,
-                                        *bitmapToUse,
-                                        SkImageEncoder::kJPEG_Type,
-                                        gJpegQuality);
+    SkPixelRef* pr = bm.pixelRef();
+    if (pr != NULL) {
+        SkData* data = pr->refEncodedData();
+        if (data != NULL) {
+            *pixelRefOffset = bm.pixelRefOffset();
+            return data;
+        }
+    }
+
+    *pixelRefOffset = 0;
+    return SkImageEncoder::EncodeData(bm,
+                                      SkImageEncoder::kJPEG_Type,
+                                      gJpegQuality);
 }
 
 /** Builds the output filename. path = dir/name, and it replaces expected
@@ -264,7 +268,7 @@
     SkTArray<SkString> inputs;
 
     SkAutoTUnref<sk_tools::PdfRenderer>
-        renderer(SkNEW_ARGS(sk_tools::SimplePdfRenderer, (encode_to_dct_stream)));
+        renderer(SkNEW_ARGS(sk_tools::SimplePdfRenderer, (encode_to_dct_data)));
     SkASSERT(renderer.get());
 
     SkString outputDir;