1/* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "DMPDFTask.h" 9#include "DMPDFRasterizeTask.h" 10#include "DMUtil.h" 11#include "DMWriteTask.h" 12#include "SkCommandLineFlags.h" 13#include "SkDocument.h" 14 15// The PDF backend is not threadsafe. If you run dm with --pdf repeatedly, you 16// will quickly find yourself crashed. (while catchsegv out/Release/dm;; end). 17// 18// TODO(mtklein): re-enable by default, maybe moving to its own single thread. 19DEFINE_bool(pdf, false, "PDF backend master switch."); 20 21namespace DM { 22 23PDFTask::PDFTask(const char* config, 24 Reporter* reporter, 25 TaskRunner* taskRunner, 26 skiagm::GMRegistry::Factory factory, 27 RasterizePdfProc rasterizePdfProc) 28 : CpuTask(reporter, taskRunner) 29 , fGM(factory(NULL)) 30 , fName(UnderJoin(fGM->getName(), config)) 31 , fRasterize(rasterizePdfProc) {} 32 33PDFTask::PDFTask(Reporter* reporter, 34 TaskRunner* taskRunner, 35 const SkPicture* picture, 36 SkString filename, 37 RasterizePdfProc rasterizePdfProc) 38 : CpuTask(reporter, taskRunner) 39 , fPicture(SkRef(picture)) 40 , fName(UnderJoin(FileToTaskName(filename).c_str(), "pdf")) 41 , fRasterize(rasterizePdfProc) {} 42 43namespace { 44 45class SinglePagePDF { 46public: 47 SinglePagePDF(SkScalar width, SkScalar height) 48 : fDocument(SkDocument::CreatePDF(&fWriteStream)) 49 , fCanvas(fDocument->beginPage(width, height)) {} 50 51 SkCanvas* canvas() { return fCanvas; } 52 53 SkStreamAsset* end() { 54 fCanvas->flush(); 55 fDocument->endPage(); 56 fDocument->close(); 57 return fWriteStream.detachAsStream(); 58 } 59 60private: 61 SkDynamicMemoryWStream fWriteStream; 62 SkAutoTUnref<SkDocument> fDocument; 63 SkCanvas* fCanvas; 64}; 65 66} // namespace 67 68void PDFTask::draw() { 69 SkAutoTDelete<SkStreamAsset> pdfData; 70 bool rasterize = true; 71 if (fGM.get()) { 72 rasterize = 0 == (fGM->getFlags() & skiagm::GM::kSkipPDFRasterization_Flag); 73 SinglePagePDF pdf(fGM->width(), fGM->height()); 74 CanvasPreflight(pdf.canvas()); 75 //TODO(mtklein): GM doesn't do this. Why not? 76 //pdf.canvas()->concat(fGM->getInitialTransform()); 77 fGM->draw(pdf.canvas()); 78 pdfData.reset(pdf.end()); 79 } else { 80 SinglePagePDF pdf(fPicture->cullRect().width(), fPicture->cullRect().height()); 81 CanvasPreflight(pdf.canvas()); 82 fPicture->playback(pdf.canvas()); 83 pdfData.reset(pdf.end()); 84 } 85 86 SkASSERT(pdfData.get()); 87 if (rasterize) { 88 this->spawnChild(SkNEW_ARGS(PDFRasterizeTask, 89 (*this, pdfData->duplicate(), fRasterize))); 90 } 91 const char* sourceType = fGM.get() ? "GM" : "SKP"; 92 this->spawnChild(SkNEW_ARGS(WriteTask, 93 (*this, sourceType, pdfData->duplicate(), ".pdf"))); 94} 95 96bool PDFTask::shouldSkip() const { 97 if (!FLAGS_pdf) { 98 return true; 99 } 100 if (fGM.get() && 0 != (fGM->getFlags() & skiagm::GM::kSkipPDF_Flag)) { 101 return true; 102 } 103 return false; 104} 105 106} // namespace DM 107