diff options
author | halcanary <halcanary@google.com> | 2015-02-20 06:17:26 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-20 06:17:26 -0800 |
commit | a1f1ee98a1f6d0770f6243270ca2f0e6c92efaba (patch) | |
tree | 427609a03b889602589a698834b96ea0035e6e8a | |
parent | 07d5947b886bef06621e830e9f8bf253f9bad703 (diff) |
PDF : New factory function for SkPDFDevice
SkPDFDevice now has factory function that matches what callers need.
Review URL: https://codereview.chromium.org/941023005
-rw-r--r-- | src/doc/SkDocument_PDF.cpp | 55 | ||||
-rw-r--r-- | src/pdf/SkPDFCanon.h | 9 | ||||
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 97 | ||||
-rw-r--r-- | src/pdf/SkPDFDevice.h | 81 | ||||
-rw-r--r-- | src/pdf/SkPDFShader.cpp | 18 | ||||
-rw-r--r-- | tests/AnnotationTest.cpp | 19 | ||||
-rw-r--r-- | tests/CanvasTest.cpp | 9 | ||||
-rw-r--r-- | tests/PDFPrimitivesTest.cpp | 11 |
8 files changed, 131 insertions, 168 deletions
diff --git a/src/doc/SkDocument_PDF.cpp b/src/doc/SkDocument_PDF.cpp index 6d6bf63526..e73b88867f 100644 --- a/src/doc/SkDocument_PDF.cpp +++ b/src/doc/SkDocument_PDF.cpp @@ -6,6 +6,7 @@ */ #include "SkDocument.h" +#include "SkPDFCanon.h" #include "SkPDFDocument.h" #include "SkPDFDevice.h" @@ -16,8 +17,6 @@ public: SkScalar rasterDpi) : SkDocument(stream, doneProc) , fDoc(SkNEW(SkPDFDocument)) - , fDevice(NULL) - , fCanvas(NULL) , fRasterDpi(rasterDpi) {} virtual ~SkDocument_PDF() { @@ -28,56 +27,50 @@ public: protected: virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height, const SkRect& trimBox) SK_OVERRIDE { - SkASSERT(NULL == fCanvas); - SkASSERT(NULL == fDevice); + SkASSERT(!fCanvas.get()); + SkASSERT(!fDevice.get()); - SkISize mediaBoxSize; - mediaBoxSize.set(SkScalarRoundToInt(width), SkScalarRoundToInt(height)); - - fDevice = SkNEW_ARGS(SkPDFDevice, (mediaBoxSize, mediaBoxSize, SkMatrix::I())); - if (fRasterDpi != 0) { - fDevice->setRasterDpi(fRasterDpi); - } - fCanvas = SkNEW_ARGS(SkCanvas, (fDevice)); + SkISize pageSize = SkISize::Make( + SkScalarRoundToInt(width), SkScalarRoundToInt(height)); + fDevice.reset(SkPDFDevice::Create(pageSize, fRasterDpi, &fCanon)); + fCanvas.reset(SkNEW_ARGS(SkCanvas, (fDevice))); fCanvas->clipRect(trimBox); fCanvas->translate(trimBox.x(), trimBox.y()); - return fCanvas; + return fCanvas.get(); } void onEndPage() SK_OVERRIDE { - SkASSERT(fCanvas); - SkASSERT(fDevice); + SkASSERT(fCanvas.get()); + SkASSERT(fDevice.get()); fCanvas->flush(); - fDoc->appendPage(fDevice); - - fCanvas->unref(); - fDevice->unref(); + fDoc->appendPage(fDevice.get()); - fCanvas = NULL; - fDevice = NULL; + fCanvas.reset(NULL); + fDevice.reset(NULL); } bool onClose(SkWStream* stream) SK_OVERRIDE { - SkASSERT(NULL == fCanvas); - SkASSERT(NULL == fDevice); + SkASSERT(!fCanvas.get()); + SkASSERT(!fDevice.get()); bool success = fDoc->emitPDF(stream); - SkDELETE(fDoc); - fDoc = NULL; + fDoc.free(); + SkDEBUGCODE(fCanon.assertEmpty()); return success; } void onAbort() SK_OVERRIDE { - SkDELETE(fDoc); - fDoc = NULL; + fDoc.free(); + SkDEBUGCODE(fCanon.assertEmpty()); } private: - SkPDFDocument* fDoc; - SkPDFDevice* fDevice; - SkCanvas* fCanvas; - SkScalar fRasterDpi; + SkPDFCanon fCanon; + SkAutoTDelete<SkPDFDocument> fDoc; + SkAutoTUnref<SkPDFDevice> fDevice; + SkAutoTUnref<SkCanvas> fCanvas; + SkScalar fRasterDpi; }; /////////////////////////////////////////////////////////////////////////////// diff --git a/src/pdf/SkPDFCanon.h b/src/pdf/SkPDFCanon.h index 6a677e9a68..7c5cdf70c1 100644 --- a/src/pdf/SkPDFCanon.h +++ b/src/pdf/SkPDFCanon.h @@ -73,6 +73,15 @@ public: void addBitmap(SkPDFBitmap*); void removeBitmap(SkPDFBitmap*); + void assertEmpty() const { + SkASSERT(fFontRecords.isEmpty()); + SkASSERT(fFunctionShaderRecords.isEmpty()); + SkASSERT(fAlphaShaderRecords.isEmpty()); + SkASSERT(fImageShaderRecords.isEmpty()); + SkASSERT(fGraphicStateRecords.isEmpty()); + SkASSERT(fBitmapRecords.isEmpty()); + } + private: struct FontRec { SkPDFFont* fFont; diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index 329d0971dd..7c0aaa280e 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -575,11 +575,8 @@ SkBaseDevice* SkPDFDevice::onCreateCompatibleDevice(const CreateInfo& cinfo) { if (kImageFilter_Usage == cinfo.fUsage) { return SkBitmapDevice::Create(cinfo.fInfo); } - - SkMatrix initialTransform; - initialTransform.reset(); SkISize size = SkISize::Make(cinfo.fInfo.width(), cinfo.fInfo.height()); - return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform)); + return SkPDFDevice::Create(size, fRasterDpi, fCanon); } @@ -695,76 +692,36 @@ private: //////////////////////////////////////////////////////////////////////////////// -static inline SkImageInfo make_content_info(const SkISize& contentSize, - const SkMatrix* initialTransform) { - SkImageInfo info; - if (initialTransform) { - // Compute the size of the drawing area. - SkVector drawingSize; - SkMatrix inverse; - drawingSize.set(SkIntToScalar(contentSize.fWidth), - SkIntToScalar(contentSize.fHeight)); - if (!initialTransform->invert(&inverse)) { - // This shouldn't happen, initial transform should be invertible. - SkASSERT(false); - inverse.reset(); - } - inverse.mapVectors(&drawingSize, 1); - SkISize size = SkSize::Make(drawingSize.fX, drawingSize.fY).toRound(); - info = SkImageInfo::MakeUnknown(abs(size.fWidth), abs(size.fHeight)); - } else { - info = SkImageInfo::MakeUnknown(abs(contentSize.fWidth), - abs(contentSize.fHeight)); - } - return info; -} - -// TODO(vandebo) change pageSize to SkSize. -SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize, - const SkMatrix& initialTransform) +SkPDFDevice::SkPDFDevice(SkISize pageSize, + SkScalar rasterDpi, + SkPDFCanon* canon, + bool flip) : fPageSize(pageSize) - , fContentSize(contentSize) + , fContentSize(pageSize) + , fExistingClipRegion(SkIRect::MakeSize(pageSize)) + , fAnnotations(NULL) + , fResourceDict(NULL) , fLastContentEntry(NULL) , fLastMarginContentEntry(NULL) + , fDrawingArea(kContent_DrawingArea) , fClipStack(NULL) - , fRasterDpi(72.0f) -{ - const SkImageInfo info = make_content_info(contentSize, &initialTransform); - - // Just report that PDF does not supports perspective in the - // initial transform. - NOT_IMPLEMENTED(initialTransform.hasPerspective(), true); - - // Skia generally uses the top left as the origin but PDF natively has the - // origin at the bottom left. This matrix corrects for that. But that only - // needs to be done once, we don't do it when layering. - fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight)); - fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1); - fInitialTransform.preConcat(initialTransform); - fLegacyBitmap.setInfo(info); - - SkIRect existingClip = info.bounds(); - fExistingClipRegion.setRect(existingClip); - this->init(); -} - -// TODO(vandebo) change layerSize to SkSize. -SkPDFDevice::SkPDFDevice(const SkISize& layerSize, - const SkClipStack& existingClipStack, - const SkRegion& existingClipRegion) - : fPageSize(layerSize) - , fContentSize(layerSize) - , fExistingClipStack(existingClipStack) - , fExistingClipRegion(existingClipRegion) - , fLastContentEntry(NULL) - , fLastMarginContentEntry(NULL) - , fClipStack(NULL) - , fRasterDpi(72.0f) -{ - fInitialTransform.reset(); - fLegacyBitmap.setInfo(make_content_info(layerSize, NULL)); - - this->init(); + , fFontGlyphUsage(SkNEW(SkPDFGlyphSetMap)) + , fRasterDpi(rasterDpi) + , fCanon(canon) { + SkASSERT(pageSize.width() > 0); + SkASSERT(pageSize.height() > 0); + fLegacyBitmap.setInfo( + SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height())); + if (flip) { + // Skia generally uses the top left as the origin but PDF + // natively has the origin at the bottom left. This matrix + // corrects for that. But that only needs to be done once, we + // don't do it when layering. + fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight)); + fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1); + } else { + fInitialTransform.setIdentity(); + } } SkPDFDevice::~SkPDFDevice() { diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h index 4c0f752405..fc4f208f48 100644 --- a/src/pdf/SkPDFDevice.h +++ b/src/pdf/SkPDFDevice.h @@ -23,6 +23,7 @@ #include "SkTemplates.h" class SkPDFArray; +class SkPDFCanon; class SkPDFDevice; class SkPDFDict; class SkPDFFont; @@ -47,28 +48,37 @@ struct NamedDestination; */ class SkPDFDevice : public SkBaseDevice { public: - /** Create a PDF drawing context with the given width and height. - * 72 points/in means letter paper is 612x792. - * @param pageSize Page size in points. - * @param contentSize The content size of the page in points. This will be - * combined with the initial transform to determine the drawing area - * (as reported by the width and height methods). Anything outside - * of the drawing area will be clipped. - * @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 does an - * inverse scale+translate to accommodate the one that SkPDFDevice - * always does. + /** Create a PDF drawing context. SkPDFDevice applies a + * scale-and-translate transform to move the origin from the + * bottom left (PDF default) to the top left (Skia default). + * @param pageSize Page size in point units. + * 1 point == 127/360 mm == 1/72 inch + * @param rasterDpi the DPI at which features without native PDF + * support will be rasterized (e.g. draw image with + * perspective, draw text with perspective, ...). A + * larger DPI would create a PDF that reflects the + * original intent with better fidelity, but it can make + * for larger PDF files too, which would use more memory + * while rendering, and it would be slower to be processed + * or sent online or to printer. A good choice is + * SK_ScalarDefaultRasterDPI(72.0f). + * @param SkPDFCanon. Should be non-null, and shared by all + * devices in a document. */ - // Deprecated, please use SkDocument::CreatePdf() instead. - SK_API SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize, - const SkMatrix& initialTransform); - SK_API virtual ~SkPDFDevice(); + static SkPDFDevice* Create(SkISize pageSize, + SkScalar rasterDpi, + SkPDFCanon* canon) { + return SkNEW_ARGS(SkPDFDevice, (pageSize, rasterDpi, canon, true)); + } + + /** Create a PDF drawing context without fipping the y-axis. */ + static SkPDFDevice* CreateUnflipped(SkISize pageSize, + SkScalar rasterDpi, + SkPDFCanon* canon) { + return SkNEW_ARGS(SkPDFDevice, (pageSize, rasterDpi, canon, false)); + } + + virtual ~SkPDFDevice(); /** These are called inside the per-device-layer loop for each draw call. When these are called, we have already applied any saveLayer operations, @@ -173,21 +183,6 @@ public: return *(fFontGlyphUsage.get()); } - - /** - * rasterDpi - the DPI at which features without native PDF support - * will be rasterized (e.g. draw image with perspective, - * draw text with perspective, ...) - * A larger DPI would create a PDF that reflects the original - * intent with better fidelity, but it can make for larger - * PDF files too, which would use more memory while rendering, - * and it would be slower to be processed or sent online or - * to printer. - */ - void setRasterDpi(SkScalar rasterDpi) { - fRasterDpi = rasterDpi; - } - protected: const SkBitmap& onAccessBitmap() SK_OVERRIDE { return fLegacyBitmap; @@ -224,8 +219,6 @@ private: // Accessor and setter functions based on the current DrawingArea. SkAutoTDelete<ContentEntry>* getContentEntries(); - ContentEntry* getLastContentEntry(); - void setLastContentEntry(ContentEntry* contentEntry); // Glyph ids used for each font on this device. SkAutoTDelete<SkPDFGlyphSetMap> fFontGlyphUsage; @@ -234,8 +227,16 @@ private: SkBitmap fLegacyBitmap; - SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack, - const SkRegion& existingClipRegion); + SkPDFCanon* fCanon; // Owned by SkDocument_PDF + //////////////////////////////////////////////////////////////////////////// + + SkPDFDevice(SkISize pageSize, + SkScalar rasterDpi, + SkPDFCanon* canon, + bool flip); + + ContentEntry* getLastContentEntry(); + void setLastContentEntry(ContentEntry* contentEntry); // override from SkBaseDevice SkBaseDevice* onCreateCompatibleDevice(const CreateInfo&) SK_OVERRIDE; diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp index e9283bc275..979ef3faea 100644 --- a/src/pdf/SkPDFShader.cpp +++ b/src/pdf/SkPDFShader.cpp @@ -942,15 +942,11 @@ SkPDFImageShader* SkPDFImageShader::Create( deviceBounds.join(bitmapBounds); } - SkMatrix unflip; - unflip.setTranslate(0, SkScalarRoundToScalar(deviceBounds.height())); - unflip.preScale(SK_Scalar1, -SK_Scalar1); SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()), SkScalarRoundToInt(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); + SkAutoTUnref<SkPDFDevice> patternDevice( + SkPDFDevice::CreateUnflipped(size, 72.0f, NULL)); + SkCanvas canvas(patternDevice.get()); SkRect patternBBox; image->getBounds(&patternBBox); @@ -1108,14 +1104,16 @@ SkPDFImageShader* SkPDFImageShader::Create( } // Put the canvas into the pattern stream (fContent). - SkAutoTDelete<SkStream> content(pattern.content()); + SkAutoTDelete<SkStream> content(patternDevice->content()); SkPDFImageShader* imageShader = SkNEW_ARGS(SkPDFImageShader, (autoState->detach())); imageShader->setData(content.get()); - populate_tiling_pattern_dict(imageShader, patternBBox, - pattern.getResourceDict(), finalMatrix); + populate_tiling_pattern_dict(imageShader, + patternBBox, + patternDevice->getResourceDict(), + finalMatrix); imageShader->fShaderState->fImage.unlockPixels(); diff --git a/tests/AnnotationTest.cpp b/tests/AnnotationTest.cpp index 0ba3af9e9b..fc762b1493 100644 --- a/tests/AnnotationTest.cpp +++ b/tests/AnnotationTest.cpp @@ -8,6 +8,7 @@ #include "SkAnnotation.h" #include "SkCanvas.h" #include "SkData.h" +#include "SkPDFCanon.h" #include "SkPDFDevice.h" #include "SkPDFDocument.h" #include "Test.h" @@ -41,10 +42,9 @@ DEF_TEST(Annotation_NoDraw, reporter) { DEF_TEST(Annotation_PdfLink, reporter) { SkISize size = SkISize::Make(612, 792); - SkMatrix initialTransform; - initialTransform.reset(); - SkPDFDevice device(size, size, initialTransform); - SkCanvas canvas(&device); + SkPDFCanon canon; + SkAutoTUnref<SkPDFDevice> device(SkPDFDevice::Create(size, 72.0f, &canon)); + SkCanvas canvas(device.get()); SkRect r = SkRect::MakeXYWH(SkIntToScalar(72), SkIntToScalar(72), SkIntToScalar(288), SkIntToScalar(72)); @@ -52,7 +52,7 @@ DEF_TEST(Annotation_PdfLink, reporter) { SkAnnotateRectWithURL(&canvas, r, data.get()); SkPDFDocument doc; - doc.appendPage(&device); + doc.appendPage(device.get()); SkDynamicMemoryWStream outStream; doc.emitPDF(&outStream); SkAutoDataUnref out(outStream.copyToData()); @@ -63,17 +63,16 @@ DEF_TEST(Annotation_PdfLink, reporter) { DEF_TEST(Annotation_NamedDestination, reporter) { SkISize size = SkISize::Make(612, 792); - SkMatrix initialTransform; - initialTransform.reset(); - SkPDFDevice device(size, size, initialTransform); - SkCanvas canvas(&device); + SkPDFCanon canon; + SkAutoTUnref<SkPDFDevice> device(SkPDFDevice::Create(size, 72.0f, &canon)); + SkCanvas canvas(device.get()); SkPoint p = SkPoint::Make(SkIntToScalar(72), SkIntToScalar(72)); SkAutoDataUnref data(SkData::NewWithCString("example")); SkAnnotateNamedDestination(&canvas, p, data.get()); SkPDFDocument doc; - doc.appendPage(&device); + doc.appendPage(device.get()); SkDynamicMemoryWStream outStream; doc.emitPDF(&outStream); SkAutoDataUnref out(outStream.copyToData()); diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp index d1f0abd19f..c405fcd52c 100644 --- a/tests/CanvasTest.cpp +++ b/tests/CanvasTest.cpp @@ -49,6 +49,7 @@ #include "SkDevice.h" #include "SkMatrix.h" #include "SkNWayCanvas.h" +#include "SkPDFCanon.h" #include "SkPDFDevice.h" #include "SkPDFDocument.h" #include "SkPaint.h" @@ -558,12 +559,14 @@ static void TestPdfDevice(skiatest::Reporter* reporter, const TestData& d, CanvasTestStep* testStep) { SkISize pageSize = SkISize::Make(d.fWidth, d.fHeight); - SkPDFDevice device(pageSize, pageSize, SkMatrix::I()); - SkCanvas canvas(&device); + SkPDFCanon canon; + SkAutoTUnref<SkPDFDevice> pdfDevice( + SkPDFDevice::Create(pageSize, 72.0f, &canon)); + SkCanvas canvas(pdfDevice.get()); testStep->setAssertMessageFormat(kPdfAssertMessageFormat); testStep->draw(&canvas, d, reporter); SkPDFDocument doc; - doc.appendPage(&device); + doc.appendPage(pdfDevice.get()); SkDynamicMemoryWStream stream; doc.emitPDF(&stream); } diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp index 2d4ac77aa4..97ad25e09a 100644 --- a/tests/PDFPrimitivesTest.cpp +++ b/tests/PDFPrimitivesTest.cpp @@ -11,6 +11,7 @@ #include "SkFlate.h" #include "SkImageEncoder.h" #include "SkMatrix.h" +#include "SkPDFCanon.h" #include "SkPDFCatalog.h" #include "SkPDFDevice.h" #include "SkPDFStream.h" @@ -215,8 +216,8 @@ static void TestSubstitute(skiatest::Reporter* reporter) { // and there is no assert on input data in Debug mode. static void test_issue1083() { SkISize pageSize = SkISize::Make(100, 100); - SkAutoTUnref<SkPDFDevice> dev(new SkPDFDevice(pageSize, pageSize, SkMatrix::I())); - + SkPDFCanon canon; + SkAutoTUnref<SkPDFDevice> dev(SkPDFDevice::Create(pageSize, 72.0f, &canon)); SkCanvas c(dev); SkPaint paint; paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); @@ -354,8 +355,10 @@ void DummyImageFilter::toString(SkString* str) const { // CPU rasterization. DEF_TEST(PDFImageFilter, reporter) { SkISize pageSize = SkISize::Make(100, 100); - SkAutoTUnref<SkPDFDevice> device(new SkPDFDevice(pageSize, pageSize, SkMatrix::I())); - SkCanvas canvas(device.get()); + SkPDFCanon canon; + SkAutoTUnref<SkPDFDevice> pdfDevice( + SkPDFDevice::Create(pageSize, 72.0f, &canon)); + SkCanvas canvas(pdfDevice.get()); SkAutoTUnref<DummyImageFilter> filter(new DummyImageFilter()); // Filter just created; should be unvisited. |