aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-10-14 13:42:12 +0000
committerGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-10-14 13:42:12 +0000
commit5e00989a283111cef05bed8102e45c16651e43e4 (patch)
treef392a48807724566537fd8d128f00ce175f1417c
parent1108fc3058e64a9363f7ea4ef41e2b04ca51f539 (diff)
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
-rw-r--r--gm/gm_error.h3
-rw-r--r--gm/gmmain.cpp140
-rw-r--r--gyp/pdf.gyp1
-rw-r--r--gyp/pdf.gypi2
-rw-r--r--include/core/SkDraw.h8
-rw-r--r--include/pdf/SkPDFDevice.h8
-rw-r--r--src/doc/SkDocument_PDF.cpp17
-rw-r--r--src/pdf/SkPDFDevice.cpp1
-rw-r--r--src/pdf/SkPDFDeviceFlattener.cpp155
-rw-r--r--src/pdf/SkPDFDeviceFlattener.h53
-rw-r--r--src/pdf/SkPDFShader.cpp3
-rw-r--r--tools/PdfRenderer.cpp35
-rw-r--r--tools/PdfRenderer.h18
-rw-r--r--tools/render_pdfs_main.cpp32
14 files changed, 354 insertions, 122 deletions
diff --git a/gm/gm_error.h b/gm/gm_error.h
index e442f5d894..e2274c4ffa 100644
--- a/gm/gm_error.h
+++ b/gm/gm_error.h
@@ -28,6 +28,7 @@ namespace skiagm {
kIntentionallySkipped_ErrorType,
kRenderModeMismatch_ErrorType,
+ kGeneratePdfFailed_ErrorType,
kExpectationsMismatch_ErrorType,
kMissingExpectations_ErrorType,
kWritingReferenceImage_ErrorType,
@@ -45,6 +46,8 @@ namespace skiagm {
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 3ee90fe084..00fcb64b14 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 @@ typedef int GLContextType;
#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 @@ public:
}
}
- 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);
- } 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);
+ if (FLAGS_useDocumentInsteadOfDevice) {
+ SkISize pageISize = gm->getISize();
+ SkAutoTUnref<SkDocument> pdfDoc(SkDocument::CreatePDF(&pdf, NULL, encode_to_dct_data));
- SkCanvas c(dev);
- invokeGM(gm, &c, true, false);
+ if (!pdfDoc.get()) {
+ return false;
+ }
- SkPDFDocument doc;
- doc.appendPage(dev);
- doc.emitPDF(&pdf);
-#endif
+ SkCanvas* canvas = NULL;
+ canvas = pdfDoc->beginPage(SkIntToScalar(pageISize.width()),
+ SkIntToScalar(pageISize.height()));
+ canvas->concat(initialTransform);
+
+ invokeGM(gm, canvas, true, false);
+
+ return pdfDoc->close();
+ } else {
+ 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);
+ }
+#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 @@ public:
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 (!generate_pdf(gm, document)) {
+ errors.add(kGeneratePdfFailed_ErrorType);
+ } else {
+ 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 (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 (!(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 {
- errors.add(kIntentionallySkipped_ErrorType);
}
} else if (gRec.fBackend == kXPS_Backend) {
generate_xps(gm, document);
@@ -1446,6 +1469,7 @@ DEFINE_int32(pdfJpegQuality, -1, "Encodes images in JPEG at quality level N, "
// 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 0ac8d45a51..2c75b26623 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 d9a1bc4249..fec201f223 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 1c2c66efb3..772e11e00d 100644
--- a/include/core/SkDraw.h
+++ b/include/core/SkDraw.h
@@ -97,16 +97,16 @@ public:
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 30ec2dc630..d668be5df3 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 @@ public:
* 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 @@ private:
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 b9b55f8dce..695929f32f 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 @@ public:
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 @@ protected:
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 538422c510..43117a2b2f 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -2034,6 +2034,7 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
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 0000000000..9c0bf41db2
--- /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 0000000000..f1047db3fc
--- /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 80ea2f2ce7..70fb616a24 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 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
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 704cbeae51..890abde320 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 @@ void PdfRenderer::init(SkPicture* pict) {
}
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* canvas = fPdfDoc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
+ canvas->ref();
-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));
+ 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 be338e9ea3..d70c458c74 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 @@ class SimplePdfRenderer : public PdfRenderer {
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 a710064528..e07664c304 100644
--- a/tools/render_pdfs_main.cpp
+++ b/tools/render_pdfs_main.cpp
@@ -131,28 +131,24 @@ static bool make_output_filepath(SkString* path, const SkString& dir,
* @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 @@ static bool render_pdf(const SkString& inputPath, const SkString& outputDir,
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;
}