Add SkPDFDeviceFlatenner which extends SkPDFDevice to add support to flatten the path and the text when we have perspective.
prepare to deprecate SkPDFDevice constructor, and route gm and render_pdfs to use SkDocument::Create pdf interface instead. - controlled by a flag
add comments where we are supposed to flatten other features (paint, shaders, ... )
R=reed@google.com, bungeman@google.com, scroggo@google.com, vandebo@chromium.org, bsalomon@google.com
Author: edisonn@google.com
Review URL: https://codereview.chromium.org/24811002
git-svn-id: http://skia.googlecode.com/svn/trunk@11751 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/gm_error.h b/gm/gm_error.h
index e442f5d..e2274c4 100644
--- a/gm/gm_error.h
+++ b/gm/gm_error.h
@@ -28,6 +28,7 @@
kIntentionallySkipped_ErrorType,
kRenderModeMismatch_ErrorType,
+ kGeneratePdfFailed_ErrorType,
kExpectationsMismatch_ErrorType,
kMissingExpectations_ErrorType,
kWritingReferenceImage_ErrorType,
@@ -45,6 +46,8 @@
return "IntentionallySkipped";
case kRenderModeMismatch_ErrorType:
return "RenderModeMismatch";
+ case kGeneratePdfFailed_ErrorType:
+ return "GeneratePdfFailed";
case kExpectationsMismatch_ErrorType:
return "ExpectationsMismatch";
case kMissingExpectations_ErrorType:
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 3ee90fe..00fcb64 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -23,6 +23,7 @@
#include "SkData.h"
#include "SkDeferredCanvas.h"
#include "SkDevice.h"
+#include "SkDocument.h"
#include "SkDrawFilter.h"
#include "SkForceLinking.h"
#include "SkGPipe.h"
@@ -33,6 +34,7 @@
#include "SkPDFRasterizer.h"
#include "SkPicture.h"
#include "SkRefCnt.h"
+#include "SkScalar.h"
#include "SkStream.h"
#include "SkTArray.h"
#include "SkTDict.h"
@@ -75,6 +77,7 @@
#define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message")
extern bool gSkSuppressFontCachePurgeSpew;
+DECLARE_bool(useDocumentInsteadOfDevice);
#ifdef SK_SUPPORT_PDF
#include "SkPDFDevice.h"
@@ -627,34 +630,51 @@
}
}
- static void generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) {
+ static bool generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) {
#ifdef SK_SUPPORT_PDF
SkMatrix initialTransform = gm->getInitialTransform();
- SkISize pageSize = gm->getISize();
- SkPDFDevice* dev = NULL;
- if (initialTransform.isIdentity()) {
- dev = new SkPDFDevice(pageSize, pageSize, initialTransform);
+ if (FLAGS_useDocumentInsteadOfDevice) {
+ SkISize pageISize = gm->getISize();
+ SkAutoTUnref<SkDocument> pdfDoc(SkDocument::CreatePDF(&pdf, NULL, encode_to_dct_data));
+
+ if (!pdfDoc.get()) {
+ return false;
+ }
+
+ SkCanvas* canvas = NULL;
+ canvas = pdfDoc->beginPage(SkIntToScalar(pageISize.width()),
+ SkIntToScalar(pageISize.height()));
+ canvas->concat(initialTransform);
+
+ invokeGM(gm, canvas, true, false);
+
+ return pdfDoc->close();
} else {
- SkRect content = SkRect::MakeWH(SkIntToScalar(pageSize.width()),
- SkIntToScalar(pageSize.height()));
- initialTransform.mapRect(&content);
- content.intersect(0, 0, SkIntToScalar(pageSize.width()),
- SkIntToScalar(pageSize.height()));
- SkISize contentSize =
- SkISize::Make(SkScalarRoundToInt(content.width()),
- SkScalarRoundToInt(content.height()));
- dev = new SkPDFDevice(pageSize, contentSize, initialTransform);
+ SkISize pageSize = gm->getISize();
+ SkPDFDevice* dev = NULL;
+ if (initialTransform.isIdentity()) {
+ dev = new SkPDFDevice(pageSize, pageSize, initialTransform);
+ } else {
+ SkRect content = SkRect::MakeWH(SkIntToScalar(pageSize.width()),
+ SkIntToScalar(pageSize.height()));
+ initialTransform.mapRect(&content);
+ content.intersect(0, 0, SkIntToScalar(pageSize.width()),
+ SkIntToScalar(pageSize.height()));
+ SkISize contentSize =
+ SkISize::Make(SkScalarRoundToInt(content.width()),
+ SkScalarRoundToInt(content.height()));
+ dev = new SkPDFDevice(pageSize, contentSize, initialTransform);
+ }
+ dev->setDCTEncoder(encode_to_dct_data);
+ SkAutoUnref aur(dev);
+ SkCanvas c(dev);
+ invokeGM(gm, &c, true, false);
+ SkPDFDocument doc;
+ doc.appendPage(dev);
+ doc.emitPDF(&pdf);
}
- dev->setDCTEncoder(encode_to_dct_data);
- SkAutoUnref aur(dev);
-
- SkCanvas c(dev);
- invokeGM(gm, &c, true, false);
-
- SkPDFDocument doc;
- doc.appendPage(dev);
- doc.emitPDF(&pdf);
-#endif
+#endif // SK_SUPPORT_PDF
+ return true; // Do not report failure if pdf is not supported.
}
static void generate_xps(GM* gm, SkDynamicMemoryWStream& xps) {
@@ -1048,43 +1068,46 @@
errors.add(write_bitmap(path, bitmapAndDigest.fBitmap));
}
} else if (gRec.fBackend == kPDF_Backend) {
- generate_pdf(gm, document);
-
- SkAutoTUnref<SkStreamAsset> documentStream(document.detachAsStream());
- if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
- path = make_filename(writePath, gm->shortName(), gRec.fName, "", "pdf");
- errors.add(write_document(path, documentStream));
- }
-
- if (!(gm->getFlags() & GM::kSkipPDFRasterization_Flag)) {
- for (int i = 0; i < pdfRasterizers.count(); i++) {
- SkBitmap pdfBitmap;
- SkASSERT(documentStream->rewind());
- bool success = (*pdfRasterizers[i]->fRasterizerFunction)(
- documentStream.get(), &pdfBitmap);
- if (!success) {
- gm_fprintf(stderr, "FAILED to render PDF for %s using renderer %s\n",
- gm->shortName(),
- pdfRasterizers[i]->fName);
- continue;
- }
-
- SkString configName(gRec.fName);
- configName.append("-");
- configName.append(pdfRasterizers[i]->fName);
-
- BitmapAndDigest bitmapAndDigest(pdfBitmap);
- errors.add(compare_test_results_to_stored_expectations(
- gm, gRec, configName.c_str(), &bitmapAndDigest));
-
- if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
- path = make_bitmap_filename(writePath, gm->shortName(), configName.c_str(),
- "", bitmapAndDigest.fDigest);
- errors.add(write_bitmap(path, bitmapAndDigest.fBitmap));
- }
- }
+ if (!generate_pdf(gm, document)) {
+ errors.add(kGeneratePdfFailed_ErrorType);
} else {
- errors.add(kIntentionallySkipped_ErrorType);
+ SkAutoTUnref<SkStreamAsset> documentStream(document.detachAsStream());
+ if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
+ path = make_filename(writePath, gm->shortName(), gRec.fName, "", "pdf");
+ errors.add(write_document(path, documentStream));
+ }
+
+ if (!(gm->getFlags() & GM::kSkipPDFRasterization_Flag)) {
+ for (int i = 0; i < pdfRasterizers.count(); i++) {
+ SkBitmap pdfBitmap;
+ SkASSERT(documentStream->rewind());
+ bool success = (*pdfRasterizers[i]->fRasterizerFunction)(
+ documentStream.get(), &pdfBitmap);
+ if (!success) {
+ gm_fprintf(stderr, "FAILED to render PDF for %s using renderer %s\n",
+ gm->shortName(),
+ pdfRasterizers[i]->fName);
+ continue;
+ }
+
+ SkString configName(gRec.fName);
+ configName.append("-");
+ configName.append(pdfRasterizers[i]->fName);
+
+ BitmapAndDigest bitmapAndDigest(pdfBitmap);
+ errors.add(compare_test_results_to_stored_expectations(
+ gm, gRec, configName.c_str(), &bitmapAndDigest));
+
+ if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
+ path = make_bitmap_filename(writePath, gm->shortName(),
+ configName.c_str(),
+ "", bitmapAndDigest.fDigest);
+ errors.add(write_bitmap(path, bitmapAndDigest.fBitmap));
+ }
+ }
+ } else {
+ errors.add(kIntentionallySkipped_ErrorType);
+ }
}
} else if (gRec.fBackend == kXPS_Backend) {
generate_xps(gm, document);
@@ -1446,6 +1469,7 @@
// Probably define spacial names like centerx, centery, top, bottom, left, right
// then we can write something reabable like --rotate centerx centery 90
DEFINE_bool(forcePerspectiveMatrix, false, "Force a perspective matrix.");
+DEFINE_bool(useDocumentInsteadOfDevice, false, "Use SkDocument::CreateFoo instead of SkFooDevice.");
static SkData* encode_to_dct_data(size_t* pixelRefOffset, const SkBitmap& bitmap) {
// Filter output of warnings that JPEG is not available for the image.
diff --git a/gyp/pdf.gyp b/gyp/pdf.gyp
index 0ac8d45..2c75b26 100644
--- a/gyp/pdf.gyp
+++ b/gyp/pdf.gyp
@@ -15,6 +15,7 @@
'include_dirs': [
'../include/pdf',
'../src/core', # needed to get SkGlyphCache.h and SkTextFormatParams.h
+ '../src/pdf',
'../src/utils', # needed to get SkBitSet.h
],
'sources': [
diff --git a/gyp/pdf.gypi b/gyp/pdf.gypi
index d9a1bc4..fec201f 100644
--- a/gyp/pdf.gypi
+++ b/gyp/pdf.gypi
@@ -13,6 +13,8 @@
'<(skia_src_path)/pdf/SkPDFCatalog.cpp',
'<(skia_src_path)/pdf/SkPDFCatalog.h',
'<(skia_src_path)/pdf/SkPDFDevice.cpp',
+ '<(skia_src_path)/pdf/SkPDFDeviceFlattener.cpp',
+ '<(skia_src_path)/pdf/SkPDFDeviceFlattener.h',
'<(skia_src_path)/pdf/SkPDFDocument.cpp',
'<(skia_src_path)/pdf/SkPDFFont.cpp',
'<(skia_src_path)/pdf/SkPDFFont.h',
diff --git a/include/core/SkDraw.h b/include/core/SkDraw.h
index 1c2c66e..772e11e 100644
--- a/include/core/SkDraw.h
+++ b/include/core/SkDraw.h
@@ -97,16 +97,16 @@
static RectType ComputeRectType(const SkPaint&, const SkMatrix&,
SkPoint* strokeSize);
-private:
void drawText_asPaths(const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkPaint&) const;
- void drawDevMask(const SkMask& mask, const SkPaint&) const;
- void drawBitmapAsMask(const SkBitmap&, const SkPaint&) const;
-
void drawPosText_asPaths(const char text[], size_t byteLength,
const SkScalar pos[], SkScalar constY,
int scalarsPerPosition, const SkPaint&) const;
+private:
+ void drawDevMask(const SkMask& mask, const SkPaint&) const;
+ void drawBitmapAsMask(const SkBitmap&, const SkPaint&) const;
+
/**
* Return the current clip bounds, in local coordinates, with slop to account
* for antialiasing or hairlines (i.e. device-bounds outset by 1, and then
diff --git a/include/pdf/SkPDFDevice.h b/include/pdf/SkPDFDevice.h
index 30ec2dc..d668be5 100644
--- a/include/pdf/SkPDFDevice.h
+++ b/include/pdf/SkPDFDevice.h
@@ -11,6 +11,7 @@
#define SkPDFDevice_DEFINED
#include "SkBitmapDevice.h"
+#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkPath.h"
@@ -63,7 +64,7 @@
* inverse scale+translate to accommodate the one that SkPDFDevice
* always does.
*/
- // TODO(vandebo): The sizes should be SkSize and not SkISize.
+ // Deprecated, please use SkDocument::CreatePdf() instead.
SK_API SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
const SkMatrix& initialTransform);
SK_API virtual ~SkPDFDevice();
@@ -311,6 +312,11 @@
const SkMatrix& matrix);
typedef SkBitmapDevice INHERITED;
+
+ // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create
+ // an SkPDFDevice
+ //friend class SkDocument_PDF;
+ //friend class SkPDFImageShader;
};
#endif
diff --git a/src/doc/SkDocument_PDF.cpp b/src/doc/SkDocument_PDF.cpp
index b9b55f8..695929f 100644
--- a/src/doc/SkDocument_PDF.cpp
+++ b/src/doc/SkDocument_PDF.cpp
@@ -6,8 +6,8 @@
*/
#include "SkDocument.h"
-#include "SkPDFDevice.h"
#include "SkPDFDocument.h"
+#include "SkPDFDeviceFlattener.h"
class SkDocument_PDF : public SkDocument {
public:
@@ -27,19 +27,14 @@
protected:
virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height,
- const SkRect& content) SK_OVERRIDE {
+ const SkRect& trimBox) SK_OVERRIDE {
SkASSERT(NULL == fCanvas);
SkASSERT(NULL == fDevice);
- SkISize pageS, contentS;
- SkMatrix matrix;
+ SkSize mediaBoxSize;
+ mediaBoxSize.set(width, height);
- pageS.set(SkScalarRoundToInt(width), SkScalarRoundToInt(height));
- contentS.set(SkScalarRoundToInt(content.width()),
- SkScalarRoundToInt(content.height()));
- matrix.setTranslate(content.fLeft, content.fTop);
-
- fDevice = SkNEW_ARGS(SkPDFDevice, (pageS, contentS, matrix));
+ fDevice = SkNEW_ARGS(SkPDFDeviceFlattener, (mediaBoxSize, &trimBox));
if (fEncoder) {
fDevice->setDCTEncoder(fEncoder);
}
@@ -78,7 +73,7 @@
private:
SkPDFDocument* fDoc;
- SkPDFDevice* fDevice;
+ SkPDFDeviceFlattener* fDevice;
SkCanvas* fCanvas;
SkPicture::EncodeBitmap fEncoder;
};
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 538422c..43117a2 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -2034,6 +2034,7 @@
const SkBitmap& bitmap,
const SkIRect* srcRect,
const SkPaint& paint) {
+ // TODO(edisonn): Perspective matrix support implemented here
SkMatrix scaled;
// Adjust for origin flip.
scaled.setScale(SK_Scalar1, -SK_Scalar1);
diff --git a/src/pdf/SkPDFDeviceFlattener.cpp b/src/pdf/SkPDFDeviceFlattener.cpp
new file mode 100644
index 0000000..9c0bf41
--- /dev/null
+++ b/src/pdf/SkPDFDeviceFlattener.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPDFDeviceFlattener.h"
+
+#include "SkDraw.h"
+
+static SkISize SkSizeToISize(const SkSize& size) {
+ return SkISize::Make(SkScalarRoundToInt(size.width()), SkScalarRoundToInt(size.height()));
+}
+
+SkPDFDeviceFlattener::SkPDFDeviceFlattener(const SkSize& pageSize, const SkRect* trimBox)
+ : SkPDFDevice(SkSizeToISize(pageSize),
+ SkSizeToISize(pageSize),
+ SkMatrix::I()) {
+ // TODO(edisonn): store the trimbox on emit.
+}
+
+SkPDFDeviceFlattener::~SkPDFDeviceFlattener() {
+}
+
+static void flattenPaint(const SkDraw& d, SkPaint* paint) {
+ if (paint->getShader()) {
+ SkMatrix local = paint->getShader()->getLocalMatrix();
+ local.preConcat(*d.fMatrix);
+ paint->getShader()->setLocalMatrix(local);
+ }
+}
+
+void SkPDFDeviceFlattener::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
+ size_t count, const SkPoint points[],
+ const SkPaint& paint) {
+ if (!mustFlatten(d)) {
+ INHERITED::drawPoints(d, mode, count, points, paint);
+ return;
+ }
+
+ SkPaint paintFlatten(paint);
+ flattenPaint(d, &paintFlatten);
+
+ SkPoint* flattenedPoints = SkNEW_ARRAY(SkPoint, count);
+ d.fMatrix->mapPoints(flattenedPoints, points, count);
+ SkDraw draw(d);
+ SkMatrix identity = SkMatrix::I();
+ draw.fMatrix = &identity;
+ INHERITED::drawPoints(draw, mode, count, flattenedPoints, paintFlatten);
+ SkDELETE_ARRAY(flattenedPoints);
+}
+
+void SkPDFDeviceFlattener::drawRect(const SkDraw& d, const SkRect& r, const SkPaint& paint) {
+ if (!mustFlatten(d)) {
+ INHERITED::drawRect(d, r, paint);
+ return;
+ }
+
+ SkPath path;
+ path.addRect(r);
+ path.transform(*d.fMatrix);
+ SkDraw draw(d);
+ SkMatrix matrix = SkMatrix::I();
+ draw.fMatrix = &matrix;
+
+ SkPaint paintFlatten(paint);
+ flattenPaint(d, &paintFlatten);
+
+ INHERITED::drawPath(draw, path, paintFlatten, NULL, true);
+}
+
+void SkPDFDeviceFlattener::drawPath(const SkDraw& d, const SkPath& origPath,
+ const SkPaint& paint, const SkMatrix* prePathMatrix,
+ bool pathIsMutable) {
+ if (!mustFlatten(d) && !(prePathMatrix && prePathMatrix->hasPerspective())) {
+ INHERITED::drawPath(d, origPath, paint, prePathMatrix, pathIsMutable);
+ return;
+ }
+
+ SkPath* pathPtr = (SkPath*)&origPath;
+ SkPath tmpPath;
+
+ if (!pathIsMutable) {
+ tmpPath = origPath;
+ pathPtr = &tmpPath;
+ }
+
+ if (prePathMatrix) {
+ pathPtr->transform(*prePathMatrix);
+ }
+
+ SkPaint paintFlatten(paint);
+ flattenPaint(d, &paintFlatten);
+
+ bool fill = paintFlatten.getFillPath(*pathPtr, &tmpPath);
+ SkDEBUGCODE(pathPtr = (SkPath*)0x12345678); // Don't use pathPtr after this point.
+
+ paintFlatten.setPathEffect(NULL);
+ if (fill) {
+ paintFlatten.setStyle(SkPaint::kFill_Style);
+ } else {
+ paintFlatten.setStyle(SkPaint::kStroke_Style);
+ paintFlatten.setStrokeWidth(0);
+ }
+
+ tmpPath.transform(*d.fMatrix);
+
+ SkDraw draw(d);
+ SkMatrix matrix = SkMatrix::I();
+ draw.fMatrix = &matrix;
+
+ INHERITED::drawPath(draw, tmpPath, paintFlatten, NULL, true);
+}
+
+void SkPDFDeviceFlattener::drawText(const SkDraw& d, const void* text, size_t len,
+ SkScalar x, SkScalar y, const SkPaint& paint) {
+ if (mustPathText(d, paint)) {
+ d.drawText_asPaths((const char*)text, len, x, y, paint);
+ return;
+ }
+
+ INHERITED::drawText(d, text, len, x, y, paint);
+}
+
+void SkPDFDeviceFlattener::drawPosText(const SkDraw& d, const void* text, size_t len,
+ const SkScalar pos[], SkScalar constY,
+ int scalarsPerPos, const SkPaint& paint) {
+ if (mustPathText(d, paint)) {
+ d.drawPosText_asPaths((const char*)text, len, pos, constY, scalarsPerPos, paint);
+ return;
+ }
+ INHERITED::drawPosText(d, text, len, pos, constY,scalarsPerPos, paint);
+}
+
+void SkPDFDeviceFlattener::drawTextOnPath(const SkDraw& d, const void* text, size_t len,
+ const SkPath& path, const SkMatrix* matrix,
+ const SkPaint& paint) {
+ if (mustPathText(d, paint) || (matrix && matrix->hasPerspective())) {
+ d.drawTextOnPath((const char*)text, len, path, matrix, paint);
+ return;
+ }
+ INHERITED::drawTextOnPath(d, text, len, path, matrix, paint);
+}
+
+bool SkPDFDeviceFlattener::mustFlatten(const SkDraw& d) const {
+ // TODO(edisonn): testability, add flag to force return true.
+ return d.fMatrix->hasPerspective();
+}
+
+bool SkPDFDeviceFlattener::mustPathText(const SkDraw& d, const SkPaint&) {
+ // TODO(edisonn): testability, add flag to force return true.
+ // TODO(edisonn): TBD: How to flatten MaskFilter.
+ return d.fMatrix->hasPerspective();
+}
diff --git a/src/pdf/SkPDFDeviceFlattener.h b/src/pdf/SkPDFDeviceFlattener.h
new file mode 100644
index 0000000..f1047db
--- /dev/null
+++ b/src/pdf/SkPDFDeviceFlattener.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkPDFDeviceFlattener_DEFINED
+#define SkPDFDeviceFlattener_DEFINED
+
+#include "SkPDFDevice.h"
+
+
+/** \class SkPDFDeviceFlattener
+
+ The PDF Device Flattener is used to flatten features without native support in PDF.
+ For now, the only one implemented is Perspective.
+
+ TODO(edisonn): Rename the class once we know all the things it will do.
+*/
+class SkPDFDeviceFlattener : public SkPDFDevice {
+private:
+ typedef SkPDFDevice INHERITED;
+
+ SK_API SkPDFDeviceFlattener(const SkSize& pageSize, const SkRect* trimBox = NULL);
+
+public:
+ SK_API virtual ~SkPDFDeviceFlattener();
+
+ virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
+ size_t count, const SkPoint[],
+ const SkPaint& paint) SK_OVERRIDE;
+ virtual void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint);
+ virtual void drawPath(const SkDraw&, const SkPath& origpath,
+ const SkPaint& paint, const SkMatrix* prePathMatrix,
+ bool pathIsMutable) SK_OVERRIDE;
+ virtual void drawText(const SkDraw&, const void* text, size_t len,
+ SkScalar x, SkScalar y, const SkPaint&) SK_OVERRIDE;
+ virtual void drawPosText(const SkDraw&, const void* text, size_t len,
+ const SkScalar pos[], SkScalar constY,
+ int scalarsPerPos, const SkPaint&) SK_OVERRIDE;
+ virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
+ const SkPath& path, const SkMatrix* matrix,
+ const SkPaint& paint) SK_OVERRIDE;
+private:
+
+ bool mustFlatten(const SkDraw& d) const;
+ bool mustPathText(const SkDraw& d, const SkPaint& paint);
+
+ friend class SkDocument_PDF;
+};
+
+#endif // SkPDFDeviceFlattener_DEFINED
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
index 80ea2f2..70fb616 100644
--- a/src/pdf/SkPDFShader.cpp
+++ b/src/pdf/SkPDFShader.cpp
@@ -9,7 +9,6 @@
#include "SkPDFShader.h"
-#include "SkCanvas.h"
#include "SkData.h"
#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
@@ -870,6 +869,8 @@
unflip.preScale(SK_Scalar1, -SK_Scalar1);
SkISize size = SkISize::Make(SkScalarRound(deviceBounds.width()),
SkScalarRound(deviceBounds.height()));
+ // TODO(edisonn): should we pass here the DCT encoder of the destination device?
+ // TODO(edisonn): NYI Perspective, use SkPDFDeviceFlattener.
SkPDFDevice pattern(size, size, unflip);
SkCanvas canvas(&pattern);
diff --git a/tools/PdfRenderer.cpp b/tools/PdfRenderer.cpp
index 704cbea..890abde 100644
--- a/tools/PdfRenderer.cpp
+++ b/tools/PdfRenderer.cpp
@@ -13,7 +13,7 @@
namespace sk_tools {
-void PdfRenderer::init(SkPicture* pict) {
+void PdfRenderer::init(SkPicture* pict, SkWStream* stream) {
SkASSERT(NULL == fPicture);
SkASSERT(NULL == fCanvas.get());
if (fPicture != NULL || NULL != fCanvas.get()) {
@@ -26,44 +26,35 @@
}
fPicture = pict;
- fCanvas.reset(this->setupCanvas());
+ fCanvas.reset(this->setupCanvas(stream, pict->width(), pict->height()));
}
-SkCanvas* PdfRenderer::setupCanvas() {
- return this->setupCanvas(fPicture->width(), fPicture->height());
-}
+SkCanvas* PdfRenderer::setupCanvas(SkWStream* stream, int width, int height) {
+ fPdfDoc.reset(SkDocument::CreatePDF(stream, NULL, fEncoder));
-SkCanvas* PdfRenderer::setupCanvas(int width, int height) {
- SkISize pageSize = SkISize::Make(width, height);
- fPDFDevice = SkNEW_ARGS(SkPDFDevice, (pageSize, pageSize, SkMatrix::I()));
- fPDFDevice->setDCTEncoder(fEncoder);
- return SkNEW_ARGS(SkCanvas, (fPDFDevice));
+ SkCanvas* canvas = fPdfDoc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
+ canvas->ref();
+
+ return canvas;
}
void PdfRenderer::end() {
fPicture = NULL;
fCanvas.reset(NULL);
- if (fPDFDevice) {
- SkDELETE(fPDFDevice);
- fPDFDevice = NULL;
- }
+ fPdfDoc.reset(NULL);
}
-void PdfRenderer::write(SkWStream* stream) const {
- SkPDFDocument doc;
- doc.appendPage(fPDFDevice);
- doc.emitPDF(stream);
-}
-
-void SimplePdfRenderer::render() {
+bool SimplePdfRenderer::render() {
SkASSERT(fCanvas.get() != NULL);
SkASSERT(fPicture != NULL);
if (NULL == fCanvas.get() || NULL == fPicture) {
- return;
+ return false;
}
fCanvas->drawPicture(*fPicture);
fCanvas->flush();
+
+ return fPdfDoc->close();
}
}
diff --git a/tools/PdfRenderer.h b/tools/PdfRenderer.h
index be338e9..d70c458 100644
--- a/tools/PdfRenderer.h
+++ b/tools/PdfRenderer.h
@@ -13,8 +13,8 @@
// An SkPicture can be built manually, or read from an SKP file.
//
+#include "SkDocument.h"
#include "SkMath.h"
-#include "SkPDFDevice.h"
#include "SkPicture.h"
#include "SkTypes.h"
#include "SkTDArray.h"
@@ -23,32 +23,30 @@
class SkBitmap;
class SkCanvas;
+class SkWStream;
namespace sk_tools {
class PdfRenderer : public SkRefCnt {
public:
- virtual void init(SkPicture* pict);
+ virtual void init(SkPicture* pict, SkWStream* stream);
virtual void setup() {}
- virtual void render() = 0;
+ virtual bool render() = 0;
virtual void end();
PdfRenderer(SkPicture::EncodeBitmap encoder)
: fPicture(NULL)
- , fPDFDevice(NULL)
, fEncoder(encoder)
+ , fPdfDoc(NULL)
{}
- void write(SkWStream* stream) const;
-
protected:
- SkCanvas* setupCanvas();
- SkCanvas* setupCanvas(int width, int height);
+ SkCanvas* setupCanvas(SkWStream* stream, int width, int height);
SkAutoTUnref<SkCanvas> fCanvas;
SkPicture* fPicture;
- SkPDFDevice* fPDFDevice;
SkPicture::EncodeBitmap fEncoder;
+ SkAutoTUnref<SkDocument> fPdfDoc;
private:
typedef SkRefCnt INHERITED;
@@ -58,7 +56,7 @@
public:
SimplePdfRenderer(SkPicture::EncodeBitmap encoder)
: PdfRenderer(encoder) {}
- virtual void render() SK_OVERRIDE;
+ virtual bool render() SK_OVERRIDE;
private:
typedef PdfRenderer INHERITED;
diff --git a/tools/render_pdfs_main.cpp b/tools/render_pdfs_main.cpp
index a710064..e07664c 100644
--- a/tools/render_pdfs_main.cpp
+++ b/tools/render_pdfs_main.cpp
@@ -131,28 +131,24 @@
* @param inputFilename The skp file that was read.
* @param renderer The object responsible to write the pdf file.
*/
-static bool write_output(const SkString& outputDir,
- const SkString& inputFilename,
- const sk_tools::PdfRenderer& renderer) {
+static SkWStream* open_stream(const SkString& outputDir,
+ const SkString& inputFilename) {
if (outputDir.isEmpty()) {
- SkDynamicMemoryWStream stream;
- renderer.write(&stream);
- return true;
+ return SkNEW(SkDynamicMemoryWStream);
}
SkString outputPath;
if (!make_output_filepath(&outputPath, outputDir, inputFilename)) {
- return false;
+ return NULL;
}
- SkFILEWStream stream(outputPath.c_str());
- if (!stream.isValid()) {
+ SkFILEWStream* stream = SkNEW_ARGS(SkFILEWStream, (outputPath.c_str()));
+ if (!stream->isValid()) {
SkDebugf("Could not write to file %s\n", outputPath.c_str());
- return false;
+ return NULL;
}
- renderer.write(&stream);
- return true;
+ return stream;
}
/** Reads an skp file, renders it to pdf and writes the output to a pdf file
@@ -182,13 +178,19 @@
SkDebugf("exporting... [%i %i] %s\n", picture->width(), picture->height(),
inputPath.c_str());
- renderer.init(picture);
+ SkWStream* stream(open_stream(outputDir, inputFilename));
- renderer.render();
+ if (!stream) {
+ return false;
+ }
- bool success = write_output(outputDir, inputFilename, renderer);
+ renderer.init(picture, stream);
+
+ bool success = renderer.render();
+ SkDELETE(stream);
renderer.end();
+
return success;
}