diff options
author | 2013-10-14 13:42:12 +0000 | |
---|---|---|
committer | 2013-10-14 13:42:12 +0000 | |
commit | 5e00989a283111cef05bed8102e45c16651e43e4 (patch) | |
tree | f392a48807724566537fd8d128f00ce175f1417c | |
parent | 1108fc3058e64a9363f7ea4ef41e2b04ca51f539 (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.h | 3 | ||||
-rw-r--r-- | gm/gmmain.cpp | 140 | ||||
-rw-r--r-- | gyp/pdf.gyp | 1 | ||||
-rw-r--r-- | gyp/pdf.gypi | 2 | ||||
-rw-r--r-- | include/core/SkDraw.h | 8 | ||||
-rw-r--r-- | include/pdf/SkPDFDevice.h | 8 | ||||
-rw-r--r-- | src/doc/SkDocument_PDF.cpp | 17 | ||||
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 1 | ||||
-rw-r--r-- | src/pdf/SkPDFDeviceFlattener.cpp | 155 | ||||
-rw-r--r-- | src/pdf/SkPDFDeviceFlattener.h | 53 | ||||
-rw-r--r-- | src/pdf/SkPDFShader.cpp | 3 | ||||
-rw-r--r-- | tools/PdfRenderer.cpp | 35 | ||||
-rw-r--r-- | tools/PdfRenderer.h | 18 | ||||
-rw-r--r-- | tools/render_pdfs_main.cpp | 32 |
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; } |