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/gm/gmmain.cpp b/gm/gmmain.cpp
index 357a54e..cb4e036 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -261,7 +261,10 @@
if (gRec[i].fBackend == kPDF_Backend && writePath) {
#ifdef SK_SUPPORT_PDF
SkISize size = gm->getISize();
- SkPDFDevice* dev = new SkPDFDevice(size.width(), size.height());
+ SkMatrix identity;
+ identity.reset();
+ SkPDFDevice* dev = new SkPDFDevice(size.width(), size.height(),
+ identity);
SkAutoUnref aur(dev);
SkCanvas c(dev);
diff --git a/include/pdf/SkPDFDevice.h b/include/pdf/SkPDFDevice.h
index 9292227..2b9e5e6 100644
--- a/include/pdf/SkPDFDevice.h
+++ b/include/pdf/SkPDFDevice.h
@@ -33,8 +33,8 @@
class SkPDFStream;
class SkPDFDeviceFactory : public SkDeviceFactory {
- virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width, int height,
- bool isOpaque, bool isForLayer);
+ virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width,
+ int height, bool isOpaque, bool isForLayer);
};
/** \class SkPDFDevice
@@ -43,24 +43,22 @@
*/
class SkPDFDevice : public SkDevice {
public:
- /** Skia generally uses the top left as the origin and PDFs natively use
- the bottom left. We can move the origin to the top left in the PDF
- with a transform, but we have to be careful to apply the transform
- only once.
- */
- enum OriginTransform {
- kFlip_OriginTransform,
- kNoFlip_OriginTransform,
- };
-
/** Create a PDF drawing context with the given width and height.
* 72 points/in means letter paper is 612x792.
* @param width Page width in points.
* @param height Page height in points.
- * @param flipOrigin Flip the origin from lower left to upper left.
+ * @param initialTransform The initial transform to apply to the page.
+ * This may be useful to, for example, move the origin in and
+ * over a bit to account for a margin, scale the canvas,
+ * or apply a rotation. Note1: the SkPDFDevice also applies
+ * a scale+translate transform to move the origin from the
+ * bottom left (PDF default) to the top left. Note2: drawDevice
+ * (used by layer restore) draws the device after this initial
+ * transform is applied, so the PDF device factory does an
+ * inverse scale+translate to accommodate the one that SkPDFDevice
+ * always does.
*/
- SkPDFDevice(int width, int height,
- OriginTransform flipOrigin = kFlip_OriginTransform);
+ SkPDFDevice(int width, int height, const SkMatrix& initialTransform);
virtual ~SkPDFDevice();
virtual SkDeviceFactory* getDeviceFactory() {
@@ -141,7 +139,7 @@
private:
int fWidth;
int fHeight;
- OriginTransform fFlipOrigin;
+ SkMatrix fInitialTransform;
SkRefPtr<SkPDFDict> fResourceDict;
SkTDArray<SkPDFGraphicState*> fGraphicStateResources;
diff --git a/include/pdf/SkPDFUtils.h b/include/pdf/SkPDFUtils.h
index 501d746..62a5120 100644
--- a/include/pdf/SkPDFUtils.h
+++ b/include/pdf/SkPDFUtils.h
@@ -40,6 +40,7 @@
class SkPDFUtils {
public:
static SkPDFArray* MatrixToArray(const SkMatrix& matrix);
+ static void AppendTransform(const SkMatrix& matrix, SkWStream* content);
static void MoveTo(SkScalar x, SkScalar y, SkWStream* content);
static void AppendLine(SkScalar x, SkScalar y, SkWStream* content);
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(" ");