Generalize the flip origin argument to the PDF device constructor.

The argument still has a default value that does what most users will want, but provides more flexibility.
Chrome will use this change to support an initial translation of the origin to simulate a margin and to scale the entire content (needed on Windows).

When landing to Chrome, this will need http://codereview.chromium.org/6820038

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

git-svn-id: http://skia.googlecode.com/svn/trunk@1111 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 3665dd8..4a25511 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -113,11 +113,13 @@
 SkDevice* SkPDFDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
                                         int width, int height, bool isOpaque,
                                         bool isForLayer) {
-    SkPDFDevice::OriginTransform flip = SkPDFDevice::kFlip_OriginTransform;
+    SkMatrix initialTransform;
+    initialTransform.reset();
     if (isForLayer) {
-        flip = SkPDFDevice::kNoFlip_OriginTransform;
+        initialTransform.setTranslate(0, height);
+        initialTransform.preScale(1, -1);
     }
-    return SkNEW_ARGS(SkPDFDevice, (width, height, flip));
+    return SkNEW_ARGS(SkPDFDevice, (width, height, initialTransform));
 }
 
 static inline SkBitmap makeABitmap(int width, int height) {
@@ -126,11 +128,11 @@
     return bitmap;
 }
 
-SkPDFDevice::SkPDFDevice(int width, int height, OriginTransform flipOrigin)
+SkPDFDevice::SkPDFDevice(int width, int height,
+                         const SkMatrix& initialTransform)
     : SkDevice(NULL, makeABitmap(width, height), false),
       fWidth(width),
       fHeight(height),
-      fFlipOrigin(flipOrigin),
       fGraphicStackIndex(0) {
     fGraphicStack[0].fColor = SK_ColorBLACK;
     fGraphicStack[0].fTextSize = SK_ScalarNaN;  // This has no default value.
@@ -142,10 +144,14 @@
     fGraphicStack[0].fClip.setRect(0,0, width, height);
     fGraphicStack[0].fTransform.reset();
 
-    if (flipOrigin == kFlip_OriginTransform) {
-        fContent.writeText("1 0 0 -1 0 ");
-        fContent.writeDecAsText(fHeight);
-        fContent.writeText(" cm\n");
+    // Skia generally uses the top left as the origin but PDF natively has the
+    // origin at the bottom left. This matrix corrects for that.  When layering,
+    // we specify an inverse correction to cancel this out.
+    fInitialTransform.setTranslate(0, height);
+    fInitialTransform.preScale(1, -1);
+    fInitialTransform.preConcat(initialTransform);
+    if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) {
+        SkPDFUtils::AppendTransform(fInitialTransform, &fContent);
     }
 }
 
@@ -601,13 +607,10 @@
         // PDF positions patterns relative to the initial transform, so
         // we need to apply the current transform to the shader parameters.
         SkMatrix transform = fGraphicStack[fGraphicStackIndex].fTransform;
-        if (fFlipOrigin == kFlip_OriginTransform) {
-            transform.postScale(1, -1);
-            transform.postTranslate(0, fHeight);
-        }
+        transform.postConcat(fInitialTransform);
 
         // PDF doesn't support kClamp_TileMode, so we simulate it by making
-        // a pattern the size of the drawing service.
+        // a pattern the size of the drawing surface.
         SkIRect bounds = fGraphicStack[fGraphicStackIndex].fClip.getBounds();
         pdfShader = SkPDFShader::getPDFShader(*shader, transform, bounds);
         SkSafeUnref(pdfShader.get());  // getShader and SkRefPtr both took a ref
@@ -808,13 +811,7 @@
             fGraphicStack[fGraphicStackIndex - 1].fClip)
         pushGS();
 
-    SkScalar transform[6];
-    SkAssertResult(m.pdfTransform(transform));
-    for (size_t i = 0; i < SK_ARRAY_COUNT(transform); i++) {
-        SkPDFScalar::Append(transform[i], &fContent);
-        fContent.writeText(" ");
-    }
-    fContent.writeText("cm\n");
+    SkPDFUtils::AppendTransform(m, &fContent);
     fGraphicStack[fGraphicStackIndex].fTransform = m;
 
     return old;
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index 9a2180d..3e363f7 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -251,15 +251,7 @@
     content->writeText(" d1\n");
 }
 
-SkPDFArray* makeFontBBox(
-        SkIRect glyphBBox, uint16_t emSize,
-        SkPDFDevice::OriginTransform flipOrigin =
-            SkPDFDevice::kNoFlip_OriginTransform) {
-    if (flipOrigin == SkPDFDevice::kFlip_OriginTransform) {
-        int32_t temp = -glyphBBox.fTop;
-        glyphBBox.fTop = -glyphBBox.fBottom;
-        glyphBBox.fBottom = temp;
-    }
+SkPDFArray* makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
     SkPDFArray* bbox = new SkPDFArray;
     bbox->reserve(4);
     bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fLeft,
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
index c833c5d..3f383e5 100644
--- a/src/pdf/SkPDFShader.cpp
+++ b/src/pdf/SkPDFShader.cpp
@@ -495,8 +495,10 @@
     surfaceBBox.set(fState.get()->fBBox);
     transformBBox(finalMatrix, &surfaceBBox);
 
-    SkPDFDevice pattern(surfaceBBox.fRight, surfaceBBox.fBottom,
-                        SkPDFDevice::kNoFlip_OriginTransform);
+    SkMatrix unflip;
+    unflip.setTranslate(0, surfaceBBox.fBottom);
+    unflip.preScale(1, -1);
+    SkPDFDevice pattern(surfaceBBox.fRight, surfaceBBox.fBottom, unflip);
     SkCanvas canvas(&pattern);
     canvas.clipRect(surfaceBBox, SkRegion::kReplace_Op);
 
diff --git a/src/pdf/SkPDFUtils.cpp b/src/pdf/SkPDFUtils.cpp
index 8bd9c8f..57e0cb7 100644
--- a/src/pdf/SkPDFUtils.cpp
+++ b/src/pdf/SkPDFUtils.cpp
@@ -35,6 +35,17 @@
 }
 
 // static
+void SkPDFUtils::AppendTransform(const SkMatrix& matrix, SkWStream* content) {
+    SkScalar values[6];
+    SkAssertResult(matrix.pdfTransform(values));
+    for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
+        SkPDFScalar::Append(values[i], content);
+        content->writeText(" ");
+    }
+    content->writeText("cm\n");
+}
+
+// static
 void SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkWStream* content) {
     SkPDFScalar::Append(x, content);
     content->writeText(" ");