diff options
author | 2017-06-27 14:28:37 -0400 | |
---|---|---|
committer | 2017-06-27 19:56:43 +0000 | |
commit | 51329c944c3021d8eb594fcb79989e6a25545c67 (patch) | |
tree | 1b86e3184a6fac928bc3dc4b08fd1e6a8838c405 /src | |
parent | 0bb0411f59aff6362cedcd90b6ca272c53e19c4c (diff) |
SkPDF: clean up PDFDevice.
Motivation: factor out some code for later re-use; clean up.
- mask_to_greyscale_image()
- addSMaskGraphicState()
- clearMaskOnGraphicState()
- stop using bare pointer to indicate ownership.
- add ScopedContentEntry::stream()
Change-Id: I7abe7ff9eab89e1002692017000cda2ca7642631
Reviewed-on: https://skia-review.googlesource.com/20978
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 149 | ||||
-rw-r--r-- | src/pdf/SkPDFDevice.h | 26 | ||||
-rw-r--r-- | src/pdf/SkPDFDocument.cpp | 3 | ||||
-rw-r--r-- | src/pdf/SkPDFShader.cpp | 3 |
4 files changed, 87 insertions, 94 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index c3ff976132..f559e9081e 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -62,6 +62,33 @@ // Utility functions +// This function destroys the mask and either frees or takes the pixels. +sk_sp<SkImage> mask_to_greyscale_image(SkMask* mask) { + sk_sp<SkImage> img; + SkPixmap pm(SkImageInfo::Make(mask->fBounds.width(), mask->fBounds.height(), + kGray_8_SkColorType, kOpaque_SkAlphaType), + mask->fImage, mask->fRowBytes); + const int imgQuality = SK_PDF_MASK_QUALITY; + if (imgQuality <= 100 && imgQuality >= 0) { + SkDynamicMemoryWStream buffer; + SkJpegEncoder::Options jpegOptions; + jpegOptions.fQuality = imgQuality; + if (SkJpegEncoder::Encode(&buffer, pm, jpegOptions)) { + img = SkImage::MakeFromEncoded(buffer.detachAsData()); + SkASSERT(img); + if (img) { + SkMask::FreeImage(mask->fImage); + } + } + } + if (!img) { + img = SkImage::MakeFromRaster(pm, [](const void* p, void*) { SkMask::FreeImage((void*)p); }, + nullptr); + } + *mask = SkMask(); // destructive; + return img; +} + static void draw_points(SkCanvas::PointMode mode, size_t count, const SkPoint* points, @@ -433,7 +460,7 @@ SkBaseDevice* SkPDFDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint return SkBitmapDevice::Create(cinfo.fInfo, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); } SkISize size = SkISize::Make(cinfo.fInfo.width(), cinfo.fInfo.height()); - return SkPDFDevice::Create(size, fRasterDpi, fDocument); + return SkPDFDevice::Make(size, fRasterDpi, fDocument).release(); } SkPDFCanon* SkPDFDevice::getCanon() const { return fDocument->canon(); } @@ -476,6 +503,7 @@ public: } SkPDFDevice::ContentEntry* entry() { return fContentEntry; } + SkDynamicMemoryWStream* stream() { return &fContentEntry->fContent; } /* Returns true when we explicitly need the shape of the drawing. */ bool needShape() { @@ -675,34 +703,28 @@ void SkPDFDevice::drawPoints(SkCanvas::PointMode mode, if (!content.entry()) { return; } - + SkDynamicMemoryWStream* contentStream = content.stream(); switch (mode) { case SkCanvas::kPolygon_PointMode: - SkPDFUtils::MoveTo(points[0].fX, points[0].fY, - &content.entry()->fContent); + SkPDFUtils::MoveTo(points[0].fX, points[0].fY, contentStream); for (size_t i = 1; i < count; i++) { - SkPDFUtils::AppendLine(points[i].fX, points[i].fY, - &content.entry()->fContent); + SkPDFUtils::AppendLine(points[i].fX, points[i].fY, contentStream); } - SkPDFUtils::StrokePath(&content.entry()->fContent); + SkPDFUtils::StrokePath(contentStream); break; case SkCanvas::kLines_PointMode: for (size_t i = 0; i < count/2; i++) { - SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY, - &content.entry()->fContent); - SkPDFUtils::AppendLine(points[i * 2 + 1].fX, - points[i * 2 + 1].fY, - &content.entry()->fContent); - SkPDFUtils::StrokePath(&content.entry()->fContent); + SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY, contentStream); + SkPDFUtils::AppendLine(points[i * 2 + 1].fX, points[i * 2 + 1].fY, contentStream); + SkPDFUtils::StrokePath(contentStream); } break; case SkCanvas::kPoints_PointMode: SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap); for (size_t i = 0; i < count; i++) { - SkPDFUtils::MoveTo(points[i].fX, points[i].fY, - &content.entry()->fContent); - SkPDFUtils::ClosePath(&content.entry()->fContent); - SkPDFUtils::StrokePath(&content.entry()->fContent); + SkPDFUtils::MoveTo(points[i].fX, points[i].fY, contentStream); + SkPDFUtils::ClosePath(contentStream); + SkPDFUtils::StrokePath(contentStream); } break; default: @@ -775,9 +797,8 @@ void SkPDFDevice::drawRect(const SkRect& rect, if (!content.entry()) { return; } - SkPDFUtils::AppendRectangle(r, &content.entry()->fContent); - SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, - &content.entry()->fContent); + SkPDFUtils::AppendRectangle(r, content.stream()); + SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, content.stream()); } void SkPDFDevice::drawRRect(const SkRRect& rrect, @@ -840,38 +861,15 @@ void SkPDFDevice::internalDrawPathWithFilter(const SkClipStack& clipStack, if (!paint->getMaskFilter()->filterMask(&dstMask, sourceMask, ctm, &margin)) { return; } - SkPixmap pm(SkImageInfo::Make(dstMask.fBounds.width(), dstMask.fBounds.height(), - kGray_8_SkColorType, kOpaque_SkAlphaType), - dstMask.fImage, dstMask.fRowBytes); - sk_sp<SkImage> mask; - const int maskQuality = SK_PDF_MASK_QUALITY; - if (maskQuality <= 100 && maskQuality >= 0) { - SkDynamicMemoryWStream buffer; - SkJpegEncoder::Options jpegOptions; - jpegOptions.fQuality = maskQuality; - if (SkJpegEncoder::Encode(&buffer, pm, jpegOptions)) { - mask = SkImage::MakeFromEncoded(buffer.detachAsData()); - SkASSERT(mask); - if (mask) { - SkMask::FreeImage(dstMask.fImage); - } - } - } - if (!mask) { - mask = SkImage::MakeFromRaster( - pm, [](const void* p, void*) { SkMask::FreeImage((void*)p); }, nullptr); - } + SkIRect dstMaskBounds = dstMask.fBounds; + sk_sp<SkImage> mask = mask_to_greyscale_image(&dstMask); // PDF doesn't seem to allow masking vector graphics with an Image XObject. // Must mask with a Form XObject. - sk_sp<SkPDFDevice> maskDevice(SkPDFDevice::CreateUnflipped(fPageSize, fRasterDpi, fDocument)); + sk_sp<SkPDFDevice> maskDevice = this->makeCongruentDevice(); { SkPDFCanvas canvas(maskDevice); - canvas.drawImage(mask, dstMask.fBounds.x(), dstMask.fBounds.y()); + canvas.drawImage(mask, dstMaskBounds.x(), dstMaskBounds.y()); } - sk_sp<SkPDFDict> sMaskGS = SkPDFGraphicState::GetSMaskGraphicState( - maskDevice->makeFormXObjectFromDevice(), false, - SkPDFGraphicState::kLuminosity_SMaskMode, fDocument->canon()); - maskDevice = nullptr; if (!ctm.isIdentity() && paint->getShader()) { transform_shader(paint.writable(), ctm); // Since we are using identity matrix. } @@ -879,18 +877,25 @@ void SkPDFDevice::internalDrawPathWithFilter(const SkClipStack& clipStack, if (!content.entry()) { return; } - SkPDFUtils::ApplyGraphicState(this->addGraphicStateResource(sMaskGS.get()), - &content.entry()->fContent); + this->addSMaskGraphicState(std::move(maskDevice), content.stream()); + SkPDFUtils::AppendRectangle(SkRect::Make(dstMaskBounds), content.stream()); + SkPDFUtils::PaintPath(SkPaint::kFill_Style, path.getFillType(), content.stream()); + this->clearMaskOnGraphicState(content.stream()); +} - SkRect dstBounds = SkRect::Make(dstMask.fBounds); - SkPDFUtils::AppendRectangle(dstBounds, &content.entry()->fContent); - SkPDFUtils::PaintPath(SkPaint::kFill_Style, path.getFillType(), &content.entry()->fContent); +void SkPDFDevice::addSMaskGraphicState(sk_sp<SkPDFDevice> maskDevice, + SkDynamicMemoryWStream* contentStream) { + sk_sp<SkPDFDict> sMaskGS = SkPDFGraphicState::GetSMaskGraphicState( + maskDevice->makeFormXObjectFromDevice(), false, + SkPDFGraphicState::kLuminosity_SMaskMode, this->getCanon()); + SkPDFUtils::ApplyGraphicState(this->addGraphicStateResource(sMaskGS.get()), contentStream); +} +void SkPDFDevice::clearMaskOnGraphicState(SkDynamicMemoryWStream* contentStream) { // The no-softmask graphic state is used to "turn off" the mask for later draw calls. - auto noSMaskGS = SkPDFUtils::GetCachedT(&fDocument->canon()->fNoSmaskGraphicState, + auto noSMaskGS = SkPDFUtils::GetCachedT(&this->getCanon()->fNoSmaskGraphicState, &SkPDFGraphicState::MakeNoSmaskGraphicState); - SkPDFUtils::ApplyGraphicState(this->addGraphicStateResource(noSMaskGS.get()), - &content.entry()->fContent); + SkPDFUtils::ApplyGraphicState(this->addGraphicStateResource(noSMaskGS.get()), contentStream); } void SkPDFDevice::internalDrawPath(const SkClipStack& clipStack, @@ -967,12 +972,9 @@ void SkPDFDevice::internalDrawPath(const SkClipStack& clipStack, paint.getStyle() == SkPaint::kFill_Style || (paint.getStrokeCap() != SkPaint::kRound_Cap && paint.getStrokeCap() != SkPaint::kSquare_Cap); - SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), - consumeDegeratePathSegments, - &content.entry()->fContent, + SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), consumeDegeratePathSegments, content.stream(), tolerance); - SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), - &content.entry()->fContent); + SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), content.stream()); } @@ -1537,7 +1539,7 @@ void SkPDFDevice::internalDrawText( if (!content.entry()) { return; } - SkDynamicMemoryWStream* out = &content.entry()->fContent; + SkDynamicMemoryWStream* out = content.stream(); const SkTDArray<SkUnichar>& glyphToUnicode = metrics->fGlyphToUnicode; out->writeText("BT\n"); @@ -1732,8 +1734,7 @@ void SkPDFDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& } sk_sp<SkPDFObject> xObject = pdfDevice->makeFormXObjectFromDevice(); - SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()), - &content.entry()->fContent); + SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()), content.stream()); } sk_sp<SkSurface> SkPDFDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) { @@ -1920,14 +1921,12 @@ void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex, if (!content.entry()) { return; } - SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), - &content.entry()->fContent); - SkPDFUtils::DrawFormXObject(xObjectIndex, &content.entry()->fContent); + SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), content.stream()); + SkPDFUtils::DrawFormXObject(xObjectIndex, content.stream()); sMaskGS = SkPDFUtils::GetCachedT(&fDocument->canon()->fNoSmaskGraphicState, &SkPDFGraphicState::MakeNoSmaskGraphicState); - SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), - &content.entry()->fContent); + SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), content.stream()); } SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack& clipStack, @@ -2033,8 +2032,7 @@ void SkPDFDevice::finishContentEntry(SkBlendMode blendMode, blendMode == SkBlendMode::kSrcATop) { ScopedContentEntry content(this, fExistingClipStack, SkMatrix::I(), stockPaint); // TODO: addXObjectResource take sk_sp - SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst.get()), - &content.entry()->fContent); + SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst.get()), content.stream()); return; } else { blendMode = SkBlendMode::kClear; @@ -2078,9 +2076,8 @@ void SkPDFDevice::finishContentEntry(SkBlendMode blendMode, blendMode == SkBlendMode::kDstATop) { ScopedContentEntry content(this, fExistingClipStack, SkMatrix::I(), stockPaint); if (content.entry()) { - SkPDFUtils::DrawFormXObject( - this->addXObjectResource(srcFormXObject.get()), - &content.entry()->fContent); + SkPDFUtils::DrawFormXObject(this->addXObjectResource(srcFormXObject.get()), + content.stream()); } if (blendMode == SkBlendMode::kSrc) { return; @@ -2089,8 +2086,7 @@ void SkPDFDevice::finishContentEntry(SkBlendMode blendMode, ScopedContentEntry content(this, fExistingClipStack, SkMatrix::I(), stockPaint); if (content.entry()) { - SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst.get()), - &content.entry()->fContent); + SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst.get()), content.stream()); } } @@ -2409,8 +2405,7 @@ void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix, fDocument->canon()->fPDFBitmapMap.set(key, pdfimage); } // TODO(halcanary): addXObjectResource() should take a sk_sp<SkPDFObject> - SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()), - &content.entry()->fContent); + SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()), content.stream()); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h index e409ed9bb2..ad44bcd12d 100644 --- a/src/pdf/SkPDFDevice.h +++ b/src/pdf/SkPDFDevice.h @@ -59,17 +59,19 @@ public: * for early serializing of large immutable objects, such * as images (via SkPDFDocument::serialize()). */ - static SkPDFDevice* Create(SkISize pageSize, - SkScalar rasterDpi, - SkPDFDocument* doc) { - return new SkPDFDevice(pageSize, rasterDpi, doc, true); + static sk_sp<SkPDFDevice> Make(SkISize pageSize, SkScalar rasterDpi, SkPDFDocument* doc) { + return sk_sp<SkPDFDevice>(new SkPDFDevice(pageSize, rasterDpi, doc, true)); } /** Create a PDF drawing context without fipping the y-axis. */ - static SkPDFDevice* CreateUnflipped(SkISize pageSize, - SkScalar rasterDpi, - SkPDFDocument* doc) { - return new SkPDFDevice(pageSize, rasterDpi, doc, false); + static sk_sp<SkPDFDevice> MakeUnflipped(SkISize pageSize, + SkScalar rasterDpi, + SkPDFDocument* doc) { + return sk_sp<SkPDFDevice>(new SkPDFDevice(pageSize, rasterDpi, doc, false)); + } + + sk_sp<SkPDFDevice> makeCongruentDevice() { + return sk_sp<SkPDFDevice>(new SkPDFDevice(fPageSize, fRasterDpi, fDocument, false)); } ~SkPDFDevice() override; @@ -283,12 +285,10 @@ private: const SkPaint& paint, bool pathIsMutable, const SkMatrix* prePathMatrix = nullptr); - typedef SkClipStackDevice INHERITED; + void addSMaskGraphicState(sk_sp<SkPDFDevice> maskDevice, SkDynamicMemoryWStream*); + void clearMaskOnGraphicState(SkDynamicMemoryWStream*); - // TODO(edisonn): Only SkDocument_PDF and SkPDFImageShader should be able to create - // an SkPDFDevice - //friend class SkDocument_PDF; - //friend class SkPDFImageShader; + typedef SkClipStackDevice INHERITED; }; #endif diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp index 931ce9917d..774d023db6 100644 --- a/src/pdf/SkPDFDocument.cpp +++ b/src/pdf/SkPDFDocument.cpp @@ -215,8 +215,7 @@ SkCanvas* SkPDFDocument::onBeginPage(SkScalar width, SkScalar height, } SkISize pageSize = SkISize::Make( SkScalarRoundToInt(width), SkScalarRoundToInt(height)); - fPageDevice.reset( - SkPDFDevice::Create(pageSize, fRasterDpi, this)); + fPageDevice = SkPDFDevice::Make(pageSize, fRasterDpi, this); fCanvas.reset(new SkPDFCanvas(fPageDevice)); if (SkRect::MakeWH(width, height) != trimBox) { fCanvas->clipRect(trimBox); diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp index 49af685d7a..9cf40d42e6 100644 --- a/src/pdf/SkPDFShader.cpp +++ b/src/pdf/SkPDFShader.cpp @@ -991,8 +991,7 @@ static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc, SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()), SkScalarRoundToInt(deviceBounds.height())); - sk_sp<SkPDFDevice> patternDevice( - SkPDFDevice::CreateUnflipped(size, dpi, doc)); + sk_sp<SkPDFDevice> patternDevice = SkPDFDevice::MakeUnflipped(size, dpi, doc); SkCanvas canvas(patternDevice.get()); SkRect patternBBox; |